actor: Annotate signals to enable some optimization
[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-actor.h"
354 #include "deprecated/clutter-behaviour.h"
355 #include "deprecated/clutter-container.h"
356
357 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
358 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
359
360 /* Internal enum used to control mapped state update.  This is a hint
361  * which indicates when to do something other than just enforce
362  * invariants.
363  */
364 typedef enum {
365   MAP_STATE_CHECK,           /* just enforce invariants. */
366   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
367                               * used when about to unparent.
368                               */
369   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
370                               * used to set mapped on toplevels.
371                               */
372   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
373                               * used just before unmapping parent.
374                               */
375 } MapStateChange;
376
377 /* 3 entries should be a good compromise, few layout managers
378  * will ask for 3 different preferred size in each allocation cycle */
379 #define N_CACHED_SIZE_REQUESTS 3
380
381 struct _ClutterActorPrivate
382 {
383   /* request mode */
384   ClutterRequestMode request_mode;
385
386   /* our cached size requests for different width / height */
387   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
388   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
389
390   /* An age of 0 means the entry is not set */
391   guint cached_height_age;
392   guint cached_width_age;
393
394   /* the bounding box of the actor, relative to the parent's
395    * allocation
396    */
397   ClutterActorBox allocation;
398   ClutterAllocationFlags allocation_flags;
399
400   /* depth */
401   gfloat z;
402
403   /* clip, in actor coordinates */
404   cairo_rectangle_t clip;
405
406   /* the cached transformation matrix; see apply_transform() */
407   CoglMatrix transform;
408
409   guint8 opacity;
410   gint opacity_override;
411
412   ClutterOffscreenRedirect offscreen_redirect;
413
414   /* This is an internal effect used to implement the
415      offscreen-redirect property */
416   ClutterEffect *flatten_effect;
417
418   /* scene graph */
419   ClutterActor *parent;
420   ClutterActor *prev_sibling;
421   ClutterActor *next_sibling;
422   ClutterActor *first_child;
423   ClutterActor *last_child;
424
425   gint n_children;
426
427   /* tracks whenever the children of an actor are changed; the
428    * age is incremented by 1 whenever an actor is added or
429    * removed. the age is not incremented when the first or the
430    * last child pointers are changed, or when grandchildren of
431    * an actor are changed.
432    */
433   gint age;
434
435   gchar *name; /* a non-unique name, used for debugging */
436   guint32 id; /* unique id, used for backward compatibility */
437
438   gint32 pick_id; /* per-stage unique id, used for picking */
439
440   /* a back-pointer to the Pango context that we can use
441    * to create pre-configured PangoLayout
442    */
443   PangoContext *pango_context;
444
445   /* the text direction configured for this child - either by
446    * application code, or by the actor's parent
447    */
448   ClutterTextDirection text_direction;
449
450   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
451   gint internal_child;
452
453   /* meta classes */
454   ClutterMetaGroup *actions;
455   ClutterMetaGroup *constraints;
456   ClutterMetaGroup *effects;
457
458   /* delegate object used to allocate the children of this actor */
459   ClutterLayoutManager *layout_manager;
460
461   /* used when painting, to update the paint volume */
462   ClutterEffect *current_effect;
463
464   /* This is used to store an effect which needs to be redrawn. A
465      redraw can be queued to start from a particular effect. This is
466      used by parametrised effects that can cache an image of the
467      actor. If a parameter of the effect changes then it only needs to
468      redraw the cached image, not the actual actor. The pointer is
469      only valid if is_dirty == TRUE. If the pointer is NULL then the
470      whole actor is dirty. */
471   ClutterEffect *effect_to_redraw;
472
473   /* This is used when painting effects to implement the
474      clutter_actor_continue_paint() function. It points to the node in
475      the list of effects that is next in the chain */
476   const GList *next_effect_to_paint;
477
478   ClutterPaintVolume paint_volume;
479
480   /* NB: This volume isn't relative to this actor, it is in eye
481    * coordinates so that it can remain valid after the actor changes.
482    */
483   ClutterPaintVolume last_paint_volume;
484
485   ClutterStageQueueRedrawEntry *queue_redraw_entry;
486
487   ClutterColor bg_color;
488
489   /* bitfields */
490
491   /* fixed position and sizes */
492   guint position_set                : 1;
493   guint min_width_set               : 1;
494   guint min_height_set              : 1;
495   guint natural_width_set           : 1;
496   guint natural_height_set          : 1;
497   /* cached request is invalid (implies allocation is too) */
498   guint needs_width_request         : 1;
499   /* cached request is invalid (implies allocation is too) */
500   guint needs_height_request        : 1;
501   /* cached allocation is invalid (request has changed, probably) */
502   guint needs_allocation            : 1;
503   guint show_on_set_parent          : 1;
504   guint has_clip                    : 1;
505   guint clip_to_allocation          : 1;
506   guint enable_model_view_transform : 1;
507   guint enable_paint_unmapped       : 1;
508   guint has_pointer                 : 1;
509   guint propagated_one_redraw       : 1;
510   guint paint_volume_valid          : 1;
511   guint last_paint_volume_valid     : 1;
512   guint in_clone_paint              : 1;
513   guint transform_valid             : 1;
514   /* This is TRUE if anything has queued a redraw since we were last
515      painted. In this case effect_to_redraw will point to an effect
516      the redraw was queued from or it will be NULL if the redraw was
517      queued without an effect. */
518   guint is_dirty                    : 1;
519   guint bg_color_set                : 1;
520 };
521
522 enum
523 {
524   PROP_0,
525
526   PROP_NAME,
527
528   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
529    * when set they force a size request, when gotten they
530    * get the allocation if the allocation is valid, and the
531    * request otherwise
532    */
533   PROP_X,
534   PROP_Y,
535   PROP_WIDTH,
536   PROP_HEIGHT,
537
538   /* Then the rest of these size-related properties are the "actual"
539    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
540    */
541   PROP_FIXED_X,
542   PROP_FIXED_Y,
543
544   PROP_FIXED_POSITION_SET,
545
546   PROP_MIN_WIDTH,
547   PROP_MIN_WIDTH_SET,
548
549   PROP_MIN_HEIGHT,
550   PROP_MIN_HEIGHT_SET,
551
552   PROP_NATURAL_WIDTH,
553   PROP_NATURAL_WIDTH_SET,
554
555   PROP_NATURAL_HEIGHT,
556   PROP_NATURAL_HEIGHT_SET,
557
558   PROP_REQUEST_MODE,
559
560   /* Allocation properties are read-only */
561   PROP_ALLOCATION,
562
563   PROP_DEPTH,
564
565   PROP_CLIP,
566   PROP_HAS_CLIP,
567   PROP_CLIP_TO_ALLOCATION,
568
569   PROP_OPACITY,
570
571   PROP_OFFSCREEN_REDIRECT,
572
573   PROP_VISIBLE,
574   PROP_MAPPED,
575   PROP_REALIZED,
576   PROP_REACTIVE,
577
578   PROP_SCALE_X,
579   PROP_SCALE_Y,
580   PROP_SCALE_CENTER_X,
581   PROP_SCALE_CENTER_Y,
582   PROP_SCALE_GRAVITY,
583
584   PROP_ROTATION_ANGLE_X,
585   PROP_ROTATION_ANGLE_Y,
586   PROP_ROTATION_ANGLE_Z,
587   PROP_ROTATION_CENTER_X,
588   PROP_ROTATION_CENTER_Y,
589   PROP_ROTATION_CENTER_Z,
590   /* This property only makes sense for the z rotation because the
591      others would depend on the actor having a size along the
592      z-axis */
593   PROP_ROTATION_CENTER_Z_GRAVITY,
594
595   PROP_ANCHOR_X,
596   PROP_ANCHOR_Y,
597   PROP_ANCHOR_GRAVITY,
598
599   PROP_SHOW_ON_SET_PARENT,
600
601   PROP_TEXT_DIRECTION,
602   PROP_HAS_POINTER,
603
604   PROP_ACTIONS,
605   PROP_CONSTRAINTS,
606   PROP_EFFECT,
607
608   PROP_LAYOUT_MANAGER,
609
610   PROP_X_ALIGN,
611   PROP_Y_ALIGN,
612   PROP_MARGIN_TOP,
613   PROP_MARGIN_BOTTOM,
614   PROP_MARGIN_LEFT,
615   PROP_MARGIN_RIGHT,
616
617   PROP_BACKGROUND_COLOR,
618   PROP_BACKGROUND_COLOR_SET,
619
620   PROP_FIRST_CHILD,
621   PROP_LAST_CHILD,
622
623   PROP_LAST
624 };
625
626 static GParamSpec *obj_props[PROP_LAST];
627
628 enum
629 {
630   SHOW,
631   HIDE,
632   DESTROY,
633   PARENT_SET,
634   KEY_FOCUS_IN,
635   KEY_FOCUS_OUT,
636   PAINT,
637   PICK,
638   REALIZE,
639   UNREALIZE,
640   QUEUE_REDRAW,
641   QUEUE_RELAYOUT,
642   EVENT,
643   CAPTURED_EVENT,
644   BUTTON_PRESS_EVENT,
645   BUTTON_RELEASE_EVENT,
646   SCROLL_EVENT,
647   KEY_PRESS_EVENT,
648   KEY_RELEASE_EVENT,
649   MOTION_EVENT,
650   ENTER_EVENT,
651   LEAVE_EVENT,
652   ALLOCATION_CHANGED,
653
654   LAST_SIGNAL
655 };
656
657 static guint actor_signals[LAST_SIGNAL] = { 0, };
658
659 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
660 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
661 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
662 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
663
664 /* These setters are all static for now, maybe they should be in the
665  * public API, but they are perhaps obscure enough to leave only as
666  * properties
667  */
668 static void clutter_actor_set_min_width          (ClutterActor *self,
669                                                   gfloat        min_width);
670 static void clutter_actor_set_min_height         (ClutterActor *self,
671                                                   gfloat        min_height);
672 static void clutter_actor_set_natural_width      (ClutterActor *self,
673                                                   gfloat        natural_width);
674 static void clutter_actor_set_natural_height     (ClutterActor *self,
675                                                   gfloat        natural_height);
676 static void clutter_actor_set_min_width_set      (ClutterActor *self,
677                                                   gboolean      use_min_width);
678 static void clutter_actor_set_min_height_set     (ClutterActor *self,
679                                                   gboolean      use_min_height);
680 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
681                                                   gboolean  use_natural_width);
682 static void clutter_actor_set_natural_height_set (ClutterActor *self,
683                                                   gboolean  use_natural_height);
684 static void clutter_actor_update_map_state       (ClutterActor  *self,
685                                                   MapStateChange change);
686 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
687
688 /* Helper routines for managing anchor coords */
689 static void clutter_anchor_coord_get_units (ClutterActor      *self,
690                                             const AnchorCoord *coord,
691                                             gfloat            *x,
692                                             gfloat            *y,
693                                             gfloat            *z);
694 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
695                                             gfloat             x,
696                                             gfloat             y,
697                                             gfloat             z);
698
699 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
700 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
701                                                         ClutterGravity     gravity);
702
703 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
704
705 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
706
707 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
708                                                                ClutterActor *ancestor,
709                                                                CoglMatrix *matrix);
710
711 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
712
713 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
714
715 static void on_layout_manager_changed (ClutterLayoutManager *manager,
716                                        ClutterActor         *self);
717
718 /* Helper macro which translates by the anchor coord, applies the
719    given transformation and then translates back */
720 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
721   gfloat _tx, _ty, _tz;                                                \
722   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
723   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
724   { _transform; }                                                      \
725   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
726
727 static GQuark quark_shader_data = 0;
728 static GQuark quark_actor_layout_info = 0;
729 static GQuark quark_actor_transform_info = 0;
730
731 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
732                          clutter_actor,
733                          G_TYPE_INITIALLY_UNOWNED,
734                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
735                                                 clutter_container_iface_init)
736                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
737                                                 clutter_scriptable_iface_init)
738                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
739                                                 clutter_animatable_iface_init)
740                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
741                                                 atk_implementor_iface_init));
742
743 /*< private >
744  * clutter_actor_get_debug_name:
745  * @actor: a #ClutterActor
746  *
747  * Retrieves a printable name of @actor for debugging messages
748  *
749  * Return value: a string with a printable name
750  */
751 const gchar *
752 _clutter_actor_get_debug_name (ClutterActor *actor)
753 {
754   return actor->priv->name != NULL ? actor->priv->name
755                                    : G_OBJECT_TYPE_NAME (actor);
756 }
757
758 #ifdef CLUTTER_ENABLE_DEBUG
759 /* XXX - this is for debugging only, remove once working (or leave
760  * in only in some debug mode). Should leave it for a little while
761  * until we're confident in the new map/realize/visible handling.
762  */
763 static inline void
764 clutter_actor_verify_map_state (ClutterActor *self)
765 {
766   ClutterActorPrivate *priv = self->priv;
767
768   if (CLUTTER_ACTOR_IS_REALIZED (self))
769     {
770       /* all bets are off during reparent when we're potentially realized,
771        * but should not be according to invariants
772        */
773       if (!CLUTTER_ACTOR_IN_REPARENT (self))
774         {
775           if (priv->parent == NULL)
776             {
777               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
778                 {
779                 }
780               else
781                 g_warning ("Realized non-toplevel actor '%s' should "
782                            "have a parent",
783                            _clutter_actor_get_debug_name (self));
784             }
785           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
786             {
787               g_warning ("Realized actor %s has an unrealized parent %s",
788                          _clutter_actor_get_debug_name (self),
789                          _clutter_actor_get_debug_name (priv->parent));
790             }
791         }
792     }
793
794   if (CLUTTER_ACTOR_IS_MAPPED (self))
795     {
796       if (!CLUTTER_ACTOR_IS_REALIZED (self))
797         g_warning ("Actor '%s' is mapped but not realized",
798                    _clutter_actor_get_debug_name (self));
799
800       /* remaining bets are off during reparent when we're potentially
801        * mapped, but should not be according to invariants
802        */
803       if (!CLUTTER_ACTOR_IN_REPARENT (self))
804         {
805           if (priv->parent == NULL)
806             {
807               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
808                 {
809                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
810                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
811                     {
812                       g_warning ("Toplevel actor '%s' is mapped "
813                                  "but not visible",
814                                  _clutter_actor_get_debug_name (self));
815                     }
816                 }
817               else
818                 {
819                   g_warning ("Mapped actor '%s' should have a parent",
820                              _clutter_actor_get_debug_name (self));
821                 }
822             }
823           else
824             {
825               ClutterActor *iter = self;
826
827               /* check for the enable_paint_unmapped flag on the actor
828                * and parents; if the flag is enabled at any point of this
829                * branch of the scene graph then all the later checks
830                * become pointless
831                */
832               while (iter != NULL)
833                 {
834                   if (iter->priv->enable_paint_unmapped)
835                     return;
836
837                   iter = iter->priv->parent;
838                 }
839
840               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
841                 {
842                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
843                              "is not visible",
844                              _clutter_actor_get_debug_name (self),
845                              _clutter_actor_get_debug_name (priv->parent));
846                 }
847
848               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
849                 {
850                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
851                              "is not realized",
852                              _clutter_actor_get_debug_name (self),
853                              _clutter_actor_get_debug_name (priv->parent));
854                 }
855
856               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
857                 {
858                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
859                     g_warning ("Actor '%s' is mapped but its non-toplevel "
860                                "parent '%s' is not mapped",
861                                _clutter_actor_get_debug_name (self),
862                                _clutter_actor_get_debug_name (priv->parent));
863                 }
864             }
865         }
866     }
867 }
868
869 #endif /* CLUTTER_ENABLE_DEBUG */
870
871 static void
872 clutter_actor_set_mapped (ClutterActor *self,
873                           gboolean      mapped)
874 {
875   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
876     return;
877
878   if (mapped)
879     {
880       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
881       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
882     }
883   else
884     {
885       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
886       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
887     }
888 }
889
890 /* this function updates the mapped and realized states according to
891  * invariants, in the appropriate order.
892  */
893 static void
894 clutter_actor_update_map_state (ClutterActor  *self,
895                                 MapStateChange change)
896 {
897   gboolean was_mapped;
898
899   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
900
901   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
902     {
903       /* the mapped flag on top-level actors must be set by the
904        * per-backend implementation because it might be asynchronous.
905        *
906        * That is, the MAPPED flag on toplevels currently tracks the X
907        * server mapped-ness of the window, while the expected behavior
908        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
909        * This creates some weird complexity by breaking the invariant
910        * that if we're visible and all ancestors shown then we are
911        * also mapped - instead, we are mapped if all ancestors
912        * _possibly excepting_ the stage are mapped. The stage
913        * will map/unmap for example when it is minimized or
914        * moved to another workspace.
915        *
916        * So, the only invariant on the stage is that if visible it
917        * should be realized, and that it has to be visible to be
918        * mapped.
919        */
920       if (CLUTTER_ACTOR_IS_VISIBLE (self))
921         clutter_actor_realize (self);
922
923       switch (change)
924         {
925         case MAP_STATE_CHECK:
926           break;
927
928         case MAP_STATE_MAKE_MAPPED:
929           g_assert (!was_mapped);
930           clutter_actor_set_mapped (self, TRUE);
931           break;
932
933         case MAP_STATE_MAKE_UNMAPPED:
934           g_assert (was_mapped);
935           clutter_actor_set_mapped (self, FALSE);
936           break;
937
938         case MAP_STATE_MAKE_UNREALIZED:
939           /* we only use MAKE_UNREALIZED in unparent,
940            * and unparenting a stage isn't possible.
941            * If someone wants to just unrealize a stage
942            * then clutter_actor_unrealize() doesn't
943            * go through this codepath.
944            */
945           g_warning ("Trying to force unrealize stage is not allowed");
946           break;
947         }
948
949       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
950           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
951           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
952         {
953           g_warning ("Clutter toplevel of type '%s' is not visible, but "
954                      "it is somehow still mapped",
955                      _clutter_actor_get_debug_name (self));
956         }
957     }
958   else
959     {
960       ClutterActorPrivate *priv = self->priv;
961       ClutterActor *parent = priv->parent;
962       gboolean should_be_mapped;
963       gboolean may_be_realized;
964       gboolean must_be_realized;
965
966       should_be_mapped = FALSE;
967       may_be_realized = TRUE;
968       must_be_realized = FALSE;
969
970       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
971         {
972           may_be_realized = FALSE;
973         }
974       else
975         {
976           /* Maintain invariant that if parent is mapped, and we are
977            * visible, then we are mapped ...  unless parent is a
978            * stage, in which case we map regardless of parent's map
979            * state but do require stage to be visible and realized.
980            *
981            * If parent is realized, that does not force us to be
982            * realized; but if parent is unrealized, that does force
983            * us to be unrealized.
984            *
985            * The reason we don't force children to realize with
986            * parents is _clutter_actor_rerealize(); if we require that
987            * a realized parent means children are realized, then to
988            * unrealize an actor we would have to unrealize its
989            * parents, which would end up meaning unrealizing and
990            * hiding the entire stage. So we allow unrealizing a
991            * child (as long as that child is not mapped) while that
992            * child still has a realized parent.
993            *
994            * Also, if we unrealize from leaf nodes to root, and
995            * realize from root to leaf, the invariants are never
996            * violated if we allow children to be unrealized
997            * while parents are realized.
998            *
999            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1000            * to force us to unmap, even though parent is still
1001            * mapped. This is because we're unmapping from leaf nodes
1002            * up to root nodes.
1003            */
1004           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1005               change != MAP_STATE_MAKE_UNMAPPED)
1006             {
1007               gboolean parent_is_visible_realized_toplevel;
1008
1009               parent_is_visible_realized_toplevel =
1010                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1011                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1012                  CLUTTER_ACTOR_IS_REALIZED (parent));
1013
1014               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1015                   parent_is_visible_realized_toplevel)
1016                 {
1017                   must_be_realized = TRUE;
1018                   should_be_mapped = TRUE;
1019                 }
1020             }
1021
1022           /* if the actor has been set to be painted even if unmapped
1023            * then we should map it and check for realization as well;
1024            * this is an override for the branch of the scene graph
1025            * which begins with this node
1026            */
1027           if (priv->enable_paint_unmapped)
1028             {
1029               if (priv->parent == NULL)
1030                 g_warning ("Attempting to map an unparented actor '%s'",
1031                            _clutter_actor_get_debug_name (self));
1032
1033               should_be_mapped = TRUE;
1034               must_be_realized = TRUE;
1035             }
1036
1037           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1038             may_be_realized = FALSE;
1039         }
1040
1041       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1042         {
1043           if (parent == NULL)
1044             g_warning ("Attempting to map a child that does not "
1045                        "meet the necessary invariants: the actor '%s' "
1046                        "has no parent",
1047                        _clutter_actor_get_debug_name (self));
1048           else
1049             g_warning ("Attempting to map a child that does not "
1050                        "meet the necessary invariants: the actor '%s' "
1051                        "is parented to an unmapped actor '%s'",
1052                        _clutter_actor_get_debug_name (self),
1053                        _clutter_actor_get_debug_name (priv->parent));
1054         }
1055
1056       /* If in reparent, we temporarily suspend unmap and unrealize.
1057        *
1058        * We want to go in the order "realize, map" and "unmap, unrealize"
1059        */
1060
1061       /* Unmap */
1062       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1063         clutter_actor_set_mapped (self, FALSE);
1064
1065       /* Realize */
1066       if (must_be_realized)
1067         clutter_actor_realize (self);
1068
1069       /* if we must be realized then we may be, presumably */
1070       g_assert (!(must_be_realized && !may_be_realized));
1071
1072       /* Unrealize */
1073       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1074         clutter_actor_unrealize_not_hiding (self);
1075
1076       /* Map */
1077       if (should_be_mapped)
1078         {
1079           if (!must_be_realized)
1080             g_warning ("Somehow we think actor '%s' should be mapped but "
1081                        "not realized, which isn't allowed",
1082                        _clutter_actor_get_debug_name (self));
1083
1084           /* realization is allowed to fail (though I don't know what
1085            * an app is supposed to do about that - shouldn't it just
1086            * be a g_error? anyway, we have to avoid mapping if this
1087            * happens)
1088            */
1089           if (CLUTTER_ACTOR_IS_REALIZED (self))
1090             clutter_actor_set_mapped (self, TRUE);
1091         }
1092     }
1093
1094 #ifdef CLUTTER_ENABLE_DEBUG
1095   /* check all invariants were kept */
1096   clutter_actor_verify_map_state (self);
1097 #endif
1098 }
1099
1100 static void
1101 clutter_actor_real_map (ClutterActor *self)
1102 {
1103   ClutterActorPrivate *priv = self->priv;
1104   ClutterActor *stage, *iter;
1105
1106   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1107
1108   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1109                 _clutter_actor_get_debug_name (self));
1110
1111   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1112
1113   stage = _clutter_actor_get_stage_internal (self);
1114   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1115
1116   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1117                 priv->pick_id,
1118                 _clutter_actor_get_debug_name (self));
1119
1120   /* notify on parent mapped before potentially mapping
1121    * children, so apps see a top-down notification.
1122    */
1123   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1124
1125   for (iter = self->priv->first_child;
1126        iter != NULL;
1127        iter = iter->priv->next_sibling)
1128     {
1129       clutter_actor_map (iter);
1130     }
1131 }
1132
1133 /**
1134  * clutter_actor_map:
1135  * @self: A #ClutterActor
1136  *
1137  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1138  * and realizes its children if they are visible. Does nothing if the
1139  * actor is not visible.
1140  *
1141  * Calling this function is strongly disencouraged: the default
1142  * implementation of #ClutterActorClass.map() will map all the children
1143  * of an actor when mapping its parent.
1144  *
1145  * When overriding map, it is mandatory to chain up to the parent
1146  * implementation.
1147  *
1148  * Since: 1.0
1149  */
1150 void
1151 clutter_actor_map (ClutterActor *self)
1152 {
1153   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1154
1155   if (CLUTTER_ACTOR_IS_MAPPED (self))
1156     return;
1157
1158   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1159     return;
1160
1161   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1162 }
1163
1164 static void
1165 clutter_actor_real_unmap (ClutterActor *self)
1166 {
1167   ClutterActorPrivate *priv = self->priv;
1168   ClutterActor *iter;
1169
1170   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1171
1172   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1173                 _clutter_actor_get_debug_name (self));
1174
1175   for (iter = self->priv->first_child;
1176        iter != NULL;
1177        iter = iter->priv->next_sibling)
1178     {
1179       clutter_actor_unmap (iter);
1180     }
1181
1182   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1183
1184   /* clear the contents of the last paint volume, so that hiding + moving +
1185    * showing will not result in the wrong area being repainted
1186    */
1187   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1188   priv->last_paint_volume_valid = TRUE;
1189
1190   /* notify on parent mapped after potentially unmapping
1191    * children, so apps see a bottom-up notification.
1192    */
1193   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1194
1195   /* relinquish keyboard focus if we were unmapped while owning it */
1196   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1197     {
1198       ClutterStage *stage;
1199
1200       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1201
1202       if (stage != NULL)
1203         _clutter_stage_release_pick_id (stage, priv->pick_id);
1204
1205       priv->pick_id = -1;
1206
1207       if (stage != NULL &&
1208           clutter_stage_get_key_focus (stage) == self)
1209         {
1210           clutter_stage_set_key_focus (stage, NULL);
1211         }
1212     }
1213 }
1214
1215 /**
1216  * clutter_actor_unmap:
1217  * @self: A #ClutterActor
1218  *
1219  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1220  * unmaps its children if they were mapped.
1221  *
1222  * Calling this function is not encouraged: the default #ClutterActor
1223  * implementation of #ClutterActorClass.unmap() will also unmap any
1224  * eventual children by default when their parent is unmapped.
1225  *
1226  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1227  * chain up to the parent implementation.
1228  *
1229  * <note>It is important to note that the implementation of the
1230  * #ClutterActorClass.unmap() virtual function may be called after
1231  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1232  * implementation, but it is guaranteed to be called before the
1233  * #GObjectClass.finalize() implementation.</note>
1234  *
1235  * Since: 1.0
1236  */
1237 void
1238 clutter_actor_unmap (ClutterActor *self)
1239 {
1240   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1241
1242   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1243     return;
1244
1245   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1246 }
1247
1248 static void
1249 clutter_actor_real_show (ClutterActor *self)
1250 {
1251   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1252     {
1253       ClutterActorPrivate *priv = self->priv;
1254
1255       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1256
1257       /* we notify on the "visible" flag in the clutter_actor_show()
1258        * wrapper so the entire show signal emission completes first
1259        * (?)
1260        */
1261       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1262
1263       /* we queue a relayout unless the actor is inside a
1264        * container that explicitly told us not to
1265        */
1266       if (priv->parent != NULL &&
1267           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1268         {
1269           /* While an actor is hidden the parent may not have
1270            * allocated/requested so we need to start from scratch
1271            * and avoid the short-circuiting in
1272            * clutter_actor_queue_relayout().
1273            */
1274           priv->needs_width_request  = FALSE;
1275           priv->needs_height_request = FALSE;
1276           priv->needs_allocation     = FALSE;
1277           clutter_actor_queue_relayout (self);
1278         }
1279     }
1280 }
1281
1282 static inline void
1283 set_show_on_set_parent (ClutterActor *self,
1284                         gboolean      set_show)
1285 {
1286   ClutterActorPrivate *priv = self->priv;
1287
1288   set_show = !!set_show;
1289
1290   if (priv->show_on_set_parent == set_show)
1291     return;
1292
1293   if (priv->parent == NULL)
1294     {
1295       priv->show_on_set_parent = set_show;
1296       g_object_notify_by_pspec (G_OBJECT (self),
1297                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1298     }
1299 }
1300
1301 /**
1302  * clutter_actor_show:
1303  * @self: A #ClutterActor
1304  *
1305  * Flags an actor to be displayed. An actor that isn't shown will not
1306  * be rendered on the stage.
1307  *
1308  * Actors are visible by default.
1309  *
1310  * If this function is called on an actor without a parent, the
1311  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1312  * effect.
1313  */
1314 void
1315 clutter_actor_show (ClutterActor *self)
1316 {
1317   ClutterActorPrivate *priv;
1318
1319   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1320
1321   /* simple optimization */
1322   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1323     {
1324       /* we still need to set the :show-on-set-parent property, in
1325        * case show() is called on an unparented actor
1326        */
1327       set_show_on_set_parent (self, TRUE);
1328       return;
1329     }
1330
1331 #ifdef CLUTTER_ENABLE_DEBUG
1332   clutter_actor_verify_map_state (self);
1333 #endif
1334
1335   priv = self->priv;
1336
1337   g_object_freeze_notify (G_OBJECT (self));
1338
1339   set_show_on_set_parent (self, TRUE);
1340
1341   g_signal_emit (self, actor_signals[SHOW], 0);
1342   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1343
1344   if (priv->parent != NULL)
1345     clutter_actor_queue_redraw (priv->parent);
1346
1347   g_object_thaw_notify (G_OBJECT (self));
1348 }
1349
1350 /**
1351  * clutter_actor_show_all:
1352  * @self: a #ClutterActor
1353  *
1354  * Calls clutter_actor_show() on all children of an actor (if any).
1355  *
1356  * Since: 0.2
1357  *
1358  * Deprecated: 1.10: Actors are visible by default
1359  */
1360 void
1361 clutter_actor_show_all (ClutterActor *self)
1362 {
1363   ClutterActorClass *klass;
1364
1365   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1366
1367   klass = CLUTTER_ACTOR_GET_CLASS (self);
1368   if (klass->show_all)
1369     klass->show_all (self);
1370 }
1371
1372 static void
1373 clutter_actor_real_hide (ClutterActor *self)
1374 {
1375   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1376     {
1377       ClutterActorPrivate *priv = self->priv;
1378
1379       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1380
1381       /* we notify on the "visible" flag in the clutter_actor_hide()
1382        * wrapper so the entire hide signal emission completes first
1383        * (?)
1384        */
1385       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1386
1387       /* we queue a relayout unless the actor is inside a
1388        * container that explicitly told us not to
1389        */
1390       if (priv->parent != NULL &&
1391           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1392         clutter_actor_queue_relayout (priv->parent);
1393     }
1394 }
1395
1396 /**
1397  * clutter_actor_hide:
1398  * @self: A #ClutterActor
1399  *
1400  * Flags an actor to be hidden. A hidden actor will not be
1401  * rendered on the stage.
1402  *
1403  * Actors are visible by default.
1404  *
1405  * If this function is called on an actor without a parent, the
1406  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1407  * as a side-effect.
1408  */
1409 void
1410 clutter_actor_hide (ClutterActor *self)
1411 {
1412   ClutterActorPrivate *priv;
1413
1414   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1415
1416   /* simple optimization */
1417   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1418     {
1419       /* we still need to set the :show-on-set-parent property, in
1420        * case hide() is called on an unparented actor
1421        */
1422       set_show_on_set_parent (self, FALSE);
1423       return;
1424     }
1425
1426 #ifdef CLUTTER_ENABLE_DEBUG
1427   clutter_actor_verify_map_state (self);
1428 #endif
1429
1430   priv = self->priv;
1431
1432   g_object_freeze_notify (G_OBJECT (self));
1433
1434   set_show_on_set_parent (self, FALSE);
1435
1436   g_signal_emit (self, actor_signals[HIDE], 0);
1437   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1438
1439   if (priv->parent != NULL)
1440     clutter_actor_queue_redraw (priv->parent);
1441
1442   g_object_thaw_notify (G_OBJECT (self));
1443 }
1444
1445 /**
1446  * clutter_actor_hide_all:
1447  * @self: a #ClutterActor
1448  *
1449  * Calls clutter_actor_hide() on all child actors (if any).
1450  *
1451  * Since: 0.2
1452  *
1453  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1454  *   prevent its children from being painted as well.
1455  */
1456 void
1457 clutter_actor_hide_all (ClutterActor *self)
1458 {
1459   ClutterActorClass *klass;
1460
1461   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1462
1463   klass = CLUTTER_ACTOR_GET_CLASS (self);
1464   if (klass->hide_all)
1465     klass->hide_all (self);
1466 }
1467
1468 /**
1469  * clutter_actor_realize:
1470  * @self: A #ClutterActor
1471  *
1472  * Realization informs the actor that it is attached to a stage. It
1473  * can use this to allocate resources if it wanted to delay allocation
1474  * until it would be rendered. However it is perfectly acceptable for
1475  * an actor to create resources before being realized because Clutter
1476  * only ever has a single rendering context so that actor is free to
1477  * be moved from one stage to another.
1478  *
1479  * This function does nothing if the actor is already realized.
1480  *
1481  * Because a realized actor must have realized parent actors, calling
1482  * clutter_actor_realize() will also realize all parents of the actor.
1483  *
1484  * This function does not realize child actors, except in the special
1485  * case that realizing the stage, when the stage is visible, will
1486  * suddenly map (and thus realize) the children of the stage.
1487  **/
1488 void
1489 clutter_actor_realize (ClutterActor *self)
1490 {
1491   ClutterActorPrivate *priv;
1492
1493   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1494
1495   priv = self->priv;
1496
1497 #ifdef CLUTTER_ENABLE_DEBUG
1498   clutter_actor_verify_map_state (self);
1499 #endif
1500
1501   if (CLUTTER_ACTOR_IS_REALIZED (self))
1502     return;
1503
1504   /* To be realized, our parent actors must be realized first.
1505    * This will only succeed if we're inside a toplevel.
1506    */
1507   if (priv->parent != NULL)
1508     clutter_actor_realize (priv->parent);
1509
1510   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1511     {
1512       /* toplevels can be realized at any time */
1513     }
1514   else
1515     {
1516       /* "Fail" the realization if parent is missing or unrealized;
1517        * this should really be a g_warning() not some kind of runtime
1518        * failure; how can an app possibly recover? Instead it's a bug
1519        * in the app and the app should get an explanatory warning so
1520        * someone can fix it. But for now it's too hard to fix this
1521        * because e.g. ClutterTexture needs reworking.
1522        */
1523       if (priv->parent == NULL ||
1524           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1525         return;
1526     }
1527
1528   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1529
1530   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1531   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1532
1533   g_signal_emit (self, actor_signals[REALIZE], 0);
1534
1535   /* Stage actor is allowed to unset the realized flag again in its
1536    * default signal handler, though that is a pathological situation.
1537    */
1538
1539   /* If realization "failed" we'll have to update child state. */
1540   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1541 }
1542
1543 static void
1544 clutter_actor_real_unrealize (ClutterActor *self)
1545 {
1546   /* we must be unmapped (implying our children are also unmapped) */
1547   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1548 }
1549
1550 /**
1551  * clutter_actor_unrealize:
1552  * @self: A #ClutterActor
1553  *
1554  * Unrealization informs the actor that it may be being destroyed or
1555  * moved to another stage. The actor may want to destroy any
1556  * underlying graphics resources at this point. However it is
1557  * perfectly acceptable for it to retain the resources until the actor
1558  * is destroyed because Clutter only ever uses a single rendering
1559  * context and all of the graphics resources are valid on any stage.
1560  *
1561  * Because mapped actors must be realized, actors may not be
1562  * unrealized if they are mapped. This function hides the actor to be
1563  * sure it isn't mapped, an application-visible side effect that you
1564  * may not be expecting.
1565  *
1566  * This function should not be called by application code.
1567  */
1568 void
1569 clutter_actor_unrealize (ClutterActor *self)
1570 {
1571   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1572   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1573
1574 /* This function should not really be in the public API, because
1575  * there isn't a good reason to call it. ClutterActor will already
1576  * unrealize things for you when it's important to do so.
1577  *
1578  * If you were using clutter_actor_unrealize() in a dispose
1579  * implementation, then don't, just chain up to ClutterActor's
1580  * dispose.
1581  *
1582  * If you were using clutter_actor_unrealize() to implement
1583  * unrealizing children of your container, then don't, ClutterActor
1584  * will already take care of that.
1585  *
1586  * If you were using clutter_actor_unrealize() to re-realize to
1587  * create your resources in a different way, then use
1588  * _clutter_actor_rerealize() (inside Clutter) or just call your
1589  * code that recreates your resources directly (outside Clutter).
1590  */
1591
1592 #ifdef CLUTTER_ENABLE_DEBUG
1593   clutter_actor_verify_map_state (self);
1594 #endif
1595
1596   clutter_actor_hide (self);
1597
1598   clutter_actor_unrealize_not_hiding (self);
1599 }
1600
1601 static ClutterActorTraverseVisitFlags
1602 unrealize_actor_before_children_cb (ClutterActor *self,
1603                                     int depth,
1604                                     void *user_data)
1605 {
1606   /* If an actor is already unrealized we know its children have also
1607    * already been unrealized... */
1608   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1609     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1610
1611   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1612
1613   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1614 }
1615
1616 static ClutterActorTraverseVisitFlags
1617 unrealize_actor_after_children_cb (ClutterActor *self,
1618                                    int depth,
1619                                    void *user_data)
1620 {
1621   /* We want to unset the realized flag only _after_
1622    * child actors are unrealized, to maintain invariants.
1623    */
1624   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1625   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1626   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1627 }
1628
1629 /*
1630  * clutter_actor_unrealize_not_hiding:
1631  * @self: A #ClutterActor
1632  *
1633  * Unrealization informs the actor that it may be being destroyed or
1634  * moved to another stage. The actor may want to destroy any
1635  * underlying graphics resources at this point. However it is
1636  * perfectly acceptable for it to retain the resources until the actor
1637  * is destroyed because Clutter only ever uses a single rendering
1638  * context and all of the graphics resources are valid on any stage.
1639  *
1640  * Because mapped actors must be realized, actors may not be
1641  * unrealized if they are mapped. You must hide the actor or one of
1642  * its parents before attempting to unrealize.
1643  *
1644  * This function is separate from clutter_actor_unrealize() because it
1645  * does not automatically hide the actor.
1646  * Actors need not be hidden to be unrealized, they just need to
1647  * be unmapped. In fact we don't want to mess up the application's
1648  * setting of the "visible" flag, so hiding is very undesirable.
1649  *
1650  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1651  * backward compatibility.
1652  */
1653 static void
1654 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1655 {
1656   _clutter_actor_traverse (self,
1657                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1658                            unrealize_actor_before_children_cb,
1659                            unrealize_actor_after_children_cb,
1660                            NULL);
1661 }
1662
1663 /*
1664  * _clutter_actor_rerealize:
1665  * @self: A #ClutterActor
1666  * @callback: Function to call while unrealized
1667  * @data: data for callback
1668  *
1669  * If an actor is already unrealized, this just calls the callback.
1670  *
1671  * If it is realized, it unrealizes temporarily, calls the callback,
1672  * and then re-realizes the actor.
1673  *
1674  * As a side effect, leaves all children of the actor unrealized if
1675  * the actor was realized but not showing.  This is because when we
1676  * unrealize the actor temporarily we must unrealize its children
1677  * (e.g. children of a stage can't be realized if stage window is
1678  * gone). And we aren't clever enough to save the realization state of
1679  * all children. In most cases this should not matter, because
1680  * the children will automatically realize when they next become mapped.
1681  */
1682 void
1683 _clutter_actor_rerealize (ClutterActor    *self,
1684                           ClutterCallback  callback,
1685                           void            *data)
1686 {
1687   gboolean was_mapped;
1688   gboolean was_showing;
1689   gboolean was_realized;
1690
1691   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1692
1693 #ifdef CLUTTER_ENABLE_DEBUG
1694   clutter_actor_verify_map_state (self);
1695 #endif
1696
1697   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1698   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1699   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1700
1701   /* Must be unmapped to unrealize. Note we only have to hide this
1702    * actor if it was mapped (if all parents were showing).  If actor
1703    * is merely visible (but not mapped), then that's fine, we can
1704    * leave it visible.
1705    */
1706   if (was_mapped)
1707     clutter_actor_hide (self);
1708
1709   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1710
1711   /* unrealize self and all children */
1712   clutter_actor_unrealize_not_hiding (self);
1713
1714   if (callback != NULL)
1715     {
1716       (* callback) (self, data);
1717     }
1718
1719   if (was_showing)
1720     clutter_actor_show (self); /* will realize only if mapping implies it */
1721   else if (was_realized)
1722     clutter_actor_realize (self); /* realize self and all parents */
1723 }
1724
1725 static void
1726 clutter_actor_real_pick (ClutterActor       *self,
1727                          const ClutterColor *color)
1728 {
1729   /* the default implementation is just to paint a rectangle
1730    * with the same size of the actor using the passed color
1731    */
1732   if (clutter_actor_should_pick_paint (self))
1733     {
1734       ClutterActorBox box = { 0, };
1735       float width, height;
1736
1737       clutter_actor_get_allocation_box (self, &box);
1738
1739       width = box.x2 - box.x1;
1740       height = box.y2 - box.y1;
1741
1742       cogl_set_source_color4ub (color->red,
1743                                 color->green,
1744                                 color->blue,
1745                                 color->alpha);
1746
1747       cogl_rectangle (0, 0, width, height);
1748     }
1749
1750   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1751    * with existing container classes that override the pick() virtual
1752    * and chain up to the default implementation - otherwise we'll end up
1753    * painting our children twice.
1754    *
1755    * this has to go away for 2.0; hopefully along the pick() itself.
1756    */
1757   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1758     {
1759       ClutterActor *iter;
1760
1761       for (iter = self->priv->first_child;
1762            iter != NULL;
1763            iter = iter->priv->next_sibling)
1764         clutter_actor_paint (iter);
1765     }
1766 }
1767
1768 /**
1769  * clutter_actor_should_pick_paint:
1770  * @self: A #ClutterActor
1771  *
1772  * Should be called inside the implementation of the
1773  * #ClutterActor::pick virtual function in order to check whether
1774  * the actor should paint itself in pick mode or not.
1775  *
1776  * This function should never be called directly by applications.
1777  *
1778  * Return value: %TRUE if the actor should paint its silhouette,
1779  *   %FALSE otherwise
1780  */
1781 gboolean
1782 clutter_actor_should_pick_paint (ClutterActor *self)
1783 {
1784   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1785
1786   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1787       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1788        CLUTTER_ACTOR_IS_REACTIVE (self)))
1789     return TRUE;
1790
1791   return FALSE;
1792 }
1793
1794 static void
1795 clutter_actor_real_get_preferred_width (ClutterActor *self,
1796                                         gfloat        for_height,
1797                                         gfloat       *min_width_p,
1798                                         gfloat       *natural_width_p)
1799 {
1800   ClutterActorPrivate *priv = self->priv;
1801
1802   if (priv->n_children != 0 &&
1803       priv->layout_manager != NULL)
1804     {
1805       ClutterContainer *container = CLUTTER_CONTAINER (self);
1806
1807       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1808                     "for the preferred width",
1809                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1810                     priv->layout_manager);
1811
1812       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1813                                                   container,
1814                                                   for_height,
1815                                                   min_width_p,
1816                                                   natural_width_p);
1817
1818       return;
1819     }
1820
1821   /* Default implementation is always 0x0, usually an actor
1822    * using this default is relying on someone to set the
1823    * request manually
1824    */
1825   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1826
1827   if (min_width_p)
1828     *min_width_p = 0;
1829
1830   if (natural_width_p)
1831     *natural_width_p = 0;
1832 }
1833
1834 static void
1835 clutter_actor_real_get_preferred_height (ClutterActor *self,
1836                                          gfloat        for_width,
1837                                          gfloat       *min_height_p,
1838                                          gfloat       *natural_height_p)
1839 {
1840   ClutterActorPrivate *priv = self->priv;
1841
1842   if (priv->n_children != 0 &&
1843       priv->layout_manager != NULL)
1844     {
1845       ClutterContainer *container = CLUTTER_CONTAINER (self);
1846
1847       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1848                     "for the preferred height",
1849                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1850                     priv->layout_manager);
1851
1852       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1853                                                    container,
1854                                                    for_width,
1855                                                    min_height_p,
1856                                                    natural_height_p);
1857
1858       return;
1859     }
1860   /* Default implementation is always 0x0, usually an actor
1861    * using this default is relying on someone to set the
1862    * request manually
1863    */
1864   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1865
1866   if (min_height_p)
1867     *min_height_p = 0;
1868
1869   if (natural_height_p)
1870     *natural_height_p = 0;
1871 }
1872
1873 static void
1874 clutter_actor_store_old_geometry (ClutterActor    *self,
1875                                   ClutterActorBox *box)
1876 {
1877   *box = self->priv->allocation;
1878 }
1879
1880 static inline void
1881 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1882                                           const ClutterActorBox *old)
1883 {
1884   ClutterActorPrivate *priv = self->priv;
1885   GObject *obj = G_OBJECT (self);
1886
1887   g_object_freeze_notify (obj);
1888
1889   /* to avoid excessive requisition or allocation cycles we
1890    * use the cached values.
1891    *
1892    * - if we don't have an allocation we assume that we need
1893    *   to notify anyway
1894    * - if we don't have a width or a height request we notify
1895    *   width and height
1896    * - if we have a valid allocation then we check the old
1897    *   bounding box with the current allocation and we notify
1898    *   the changes
1899    */
1900   if (priv->needs_allocation)
1901     {
1902       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1903       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1904       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1905       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1906     }
1907   else if (priv->needs_width_request || priv->needs_height_request)
1908     {
1909       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1910       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1911     }
1912   else
1913     {
1914       gfloat xu, yu;
1915       gfloat widthu, heightu;
1916
1917       xu = priv->allocation.x1;
1918       yu = priv->allocation.y1;
1919       widthu = priv->allocation.x2 - priv->allocation.x1;
1920       heightu = priv->allocation.y2 - priv->allocation.y1;
1921
1922       if (xu != old->x1)
1923         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1924
1925       if (yu != old->y1)
1926         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1927
1928       if (widthu != (old->x2 - old->x1))
1929         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1930
1931       if (heightu != (old->y2 - old->y1))
1932         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1933     }
1934
1935   g_object_thaw_notify (obj);
1936 }
1937
1938 /*< private >
1939  * clutter_actor_set_allocation_internal:
1940  * @self: a #ClutterActor
1941  * @box: a #ClutterActorBox
1942  * @flags: allocation flags
1943  *
1944  * Stores the allocation of @self.
1945  *
1946  * This function only performs basic storage and property notification.
1947  *
1948  * This function should be called by clutter_actor_set_allocation()
1949  * and by the default implementation of #ClutterActorClass.allocate().
1950  *
1951  * Return value: %TRUE if the allocation of the #ClutterActor has been
1952  *   changed, and %FALSE otherwise
1953  */
1954 static inline gboolean
1955 clutter_actor_set_allocation_internal (ClutterActor           *self,
1956                                        const ClutterActorBox  *box,
1957                                        ClutterAllocationFlags  flags)
1958 {
1959   ClutterActorPrivate *priv = self->priv;
1960   GObject *obj;
1961   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
1962   gboolean flags_changed;
1963   gboolean retval;
1964   ClutterActorBox old_alloc = { 0, };
1965
1966   obj = G_OBJECT (self);
1967
1968   g_object_freeze_notify (obj);
1969
1970   clutter_actor_store_old_geometry (self, &old_alloc);
1971
1972   x1_changed = priv->allocation.x1 != box->x1;
1973   y1_changed = priv->allocation.y1 != box->y1;
1974   x2_changed = priv->allocation.x2 != box->x2;
1975   y2_changed = priv->allocation.y2 != box->y2;
1976
1977   flags_changed = priv->allocation_flags != flags;
1978
1979   priv->allocation = *box;
1980   priv->allocation_flags = flags;
1981
1982   /* allocation is authoritative */
1983   priv->needs_width_request = FALSE;
1984   priv->needs_height_request = FALSE;
1985   priv->needs_allocation = FALSE;
1986
1987   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1988     {
1989       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
1990                     _clutter_actor_get_debug_name (self));
1991
1992       priv->transform_valid = FALSE;
1993
1994       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
1995
1996       retval = TRUE;
1997     }
1998   else
1999     retval = FALSE;
2000
2001   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2002
2003   g_object_thaw_notify (obj);
2004
2005   return retval;
2006 }
2007
2008 static void clutter_actor_real_allocate (ClutterActor           *self,
2009                                          const ClutterActorBox  *box,
2010                                          ClutterAllocationFlags  flags);
2011
2012 static inline void
2013 clutter_actor_maybe_layout_children (ClutterActor           *self,
2014                                      const ClutterActorBox  *allocation,
2015                                      ClutterAllocationFlags  flags)
2016 {
2017   ClutterActorPrivate *priv = self->priv;
2018
2019   /* this is going to be a bit hard to follow, so let's put an explanation
2020    * here.
2021    *
2022    * we want ClutterActor to have a default layout manager if the actor was
2023    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2024    *
2025    * we also want any subclass of ClutterActor that does not override the
2026    * ::allocate() virtual function to delegate to a layout manager.
2027    *
2028    * finally, we want to allow people subclassing ClutterActor and overriding
2029    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2030    *
2031    * on the other hand, we want existing actor subclasses overriding the
2032    * ::allocate() virtual function and chaining up to the parent's
2033    * implementation to continue working without allocating their children
2034    * twice, or without entering an allocation loop.
2035    *
2036    * for the first two points, we check if the class of the actor is
2037    * overridding the ::allocate() virtual function; if it isn't, then we
2038    * follow through with checking whether we have children and a layout
2039    * manager, and eventually calling clutter_layout_manager_allocate().
2040    *
2041    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2042    * allocation flags that we got passed, and if it is present, we continue
2043    * with the check above.
2044    *
2045    * if neither of these two checks yields a positive result, we just
2046    * assume that the ::allocate() virtual function that resulted in this
2047    * function being called will also allocate the children of the actor.
2048    */
2049
2050   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2051     goto check_layout;
2052
2053   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2054     goto check_layout;
2055
2056   return;
2057
2058 check_layout:
2059   if (priv->n_children != 0 &&
2060       priv->layout_manager != NULL)
2061     {
2062       ClutterContainer *container = CLUTTER_CONTAINER (self);
2063       ClutterAllocationFlags children_flags;
2064       ClutterActorBox children_box;
2065
2066       /* normalize the box passed to the layout manager */
2067       children_box.x1 = children_box.y1 = 0.f;
2068       children_box.x2 = (allocation->x2 - allocation->x1);
2069       children_box.y2 = (allocation->y2 - allocation->y1);
2070
2071       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2072        * the actor's children, since it refers only to the current
2073        * actor's allocation.
2074        */
2075       children_flags = flags;
2076       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2077
2078       CLUTTER_NOTE (LAYOUT,
2079                     "Allocating %d children of %s "
2080                     "at { %.2f, %.2f - %.2f x %.2f } "
2081                     "using %s",
2082                     priv->n_children,
2083                     _clutter_actor_get_debug_name (self),
2084                     allocation->x1,
2085                     allocation->y1,
2086                     (allocation->x2 - allocation->x1),
2087                     (allocation->y2 - allocation->y1),
2088                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2089
2090       clutter_layout_manager_allocate (priv->layout_manager,
2091                                        container,
2092                                        &children_box,
2093                                        children_flags);
2094     }
2095 }
2096
2097 static void
2098 clutter_actor_real_allocate (ClutterActor           *self,
2099                              const ClutterActorBox  *box,
2100                              ClutterAllocationFlags  flags)
2101 {
2102   ClutterActorPrivate *priv = self->priv;
2103   gboolean changed;
2104
2105   g_object_freeze_notify (G_OBJECT (self));
2106
2107   changed = clutter_actor_set_allocation_internal (self, box, flags);
2108
2109   /* we allocate our children before we notify changes in our geometry,
2110    * so that people connecting to properties will be able to get valid
2111    * data out of the sub-tree of the scene graph that has this actor at
2112    * the root.
2113    */
2114   clutter_actor_maybe_layout_children (self, box, flags);
2115
2116   if (changed)
2117     {
2118       ClutterActorBox signal_box = priv->allocation;
2119       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2120
2121       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2122                      &signal_box,
2123                      signal_flags);
2124     }
2125
2126   g_object_thaw_notify (G_OBJECT (self));
2127 }
2128
2129 static void
2130 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2131                                     ClutterActor *origin)
2132 {
2133   /* no point in queuing a redraw on a destroyed actor */
2134   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2135     return;
2136
2137   /* NB: We can't bail out early here if the actor is hidden in case
2138    * the actor bas been cloned. In this case the clone will need to
2139    * receive the signal so it can queue its own redraw.
2140    */
2141
2142   /* calls klass->queue_redraw in default handler */
2143   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2144 }
2145
2146 static void
2147 clutter_actor_real_queue_redraw (ClutterActor *self,
2148                                  ClutterActor *origin)
2149 {
2150   ClutterActor *parent;
2151
2152   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2153                 _clutter_actor_get_debug_name (self),
2154                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2155                                : "same actor");
2156
2157   /* no point in queuing a redraw on a destroyed actor */
2158   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2159     return;
2160
2161   /* If the queue redraw is coming from a child then the actor has
2162      become dirty and any queued effect is no longer valid */
2163   if (self != origin)
2164     {
2165       self->priv->is_dirty = TRUE;
2166       self->priv->effect_to_redraw = NULL;
2167     }
2168
2169   /* If the actor isn't visible, we still had to emit the signal
2170    * to allow for a ClutterClone, but the appearance of the parent
2171    * won't change so we don't have to propagate up the hierarchy.
2172    */
2173   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2174     return;
2175
2176   /* Although we could determine here that a full stage redraw
2177    * has already been queued and immediately bail out, we actually
2178    * guarantee that we will propagate a queue-redraw signal to our
2179    * parent at least once so that it's possible to implement a
2180    * container that tracks which of its children have queued a
2181    * redraw.
2182    */
2183   if (self->priv->propagated_one_redraw)
2184     {
2185       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2186       if (stage != NULL &&
2187           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2188         return;
2189     }
2190
2191   self->priv->propagated_one_redraw = TRUE;
2192
2193   /* notify parents, if they are all visible eventually we'll
2194    * queue redraw on the stage, which queues the redraw idle.
2195    */
2196   parent = clutter_actor_get_parent (self);
2197   if (parent != NULL)
2198     {
2199       /* this will go up recursively */
2200       _clutter_actor_signal_queue_redraw (parent, origin);
2201     }
2202 }
2203
2204 static void
2205 clutter_actor_real_queue_relayout (ClutterActor *self)
2206 {
2207   ClutterActorPrivate *priv = self->priv;
2208
2209   /* no point in queueing a redraw on a destroyed actor */
2210   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2211     return;
2212
2213   priv->needs_width_request  = TRUE;
2214   priv->needs_height_request = TRUE;
2215   priv->needs_allocation     = TRUE;
2216
2217   /* reset the cached size requests */
2218   memset (priv->width_requests, 0,
2219           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2220   memset (priv->height_requests, 0,
2221           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2222
2223   /* We need to go all the way up the hierarchy */
2224   if (priv->parent != NULL)
2225     _clutter_actor_queue_only_relayout (priv->parent);
2226 }
2227
2228 /**
2229  * clutter_actor_apply_relative_transform_to_point:
2230  * @self: A #ClutterActor
2231  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2232  *   default #ClutterStage
2233  * @point: A point as #ClutterVertex
2234  * @vertex: (out caller-allocates): The translated #ClutterVertex
2235  *
2236  * Transforms @point in coordinates relative to the actor into
2237  * ancestor-relative coordinates using the relevant transform
2238  * stack (i.e. scale, rotation, etc).
2239  *
2240  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2241  * this case, the coordinates returned will be the coordinates on
2242  * the stage before the projection is applied. This is different from
2243  * the behaviour of clutter_actor_apply_transform_to_point().
2244  *
2245  * Since: 0.6
2246  */
2247 void
2248 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2249                                                  ClutterActor        *ancestor,
2250                                                  const ClutterVertex *point,
2251                                                  ClutterVertex       *vertex)
2252 {
2253   gfloat w;
2254   CoglMatrix matrix;
2255
2256   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2257   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2258   g_return_if_fail (point != NULL);
2259   g_return_if_fail (vertex != NULL);
2260
2261   *vertex = *point;
2262   w = 1.0;
2263
2264   if (ancestor == NULL)
2265     ancestor = _clutter_actor_get_stage_internal (self);
2266
2267   if (ancestor == NULL)
2268     {
2269       *vertex = *point;
2270       return;
2271     }
2272
2273   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2274   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2275 }
2276
2277 static gboolean
2278 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2279                                          const ClutterVertex *vertices_in,
2280                                          ClutterVertex *vertices_out,
2281                                          int n_vertices)
2282 {
2283   ClutterActor *stage;
2284   CoglMatrix modelview;
2285   CoglMatrix projection;
2286   float viewport[4];
2287
2288   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2289
2290   stage = _clutter_actor_get_stage_internal (self);
2291
2292   /* We really can't do anything meaningful in this case so don't try
2293    * to do any transform */
2294   if (stage == NULL)
2295     return FALSE;
2296
2297   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2298    * that gets us to stage coordinates, we want to go all the way to eye
2299    * coordinates */
2300   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2301
2302   /* Fetch the projection and viewport */
2303   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2304   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2305                                &viewport[0],
2306                                &viewport[1],
2307                                &viewport[2],
2308                                &viewport[3]);
2309
2310   _clutter_util_fully_transform_vertices (&modelview,
2311                                           &projection,
2312                                           viewport,
2313                                           vertices_in,
2314                                           vertices_out,
2315                                           n_vertices);
2316
2317   return TRUE;
2318 }
2319
2320 /**
2321  * clutter_actor_apply_transform_to_point:
2322  * @self: A #ClutterActor
2323  * @point: A point as #ClutterVertex
2324  * @vertex: (out caller-allocates): The translated #ClutterVertex
2325  *
2326  * Transforms @point in coordinates relative to the actor
2327  * into screen-relative coordinates with the current actor
2328  * transformation (i.e. scale, rotation, etc)
2329  *
2330  * Since: 0.4
2331  **/
2332 void
2333 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2334                                         const ClutterVertex *point,
2335                                         ClutterVertex       *vertex)
2336 {
2337   g_return_if_fail (point != NULL);
2338   g_return_if_fail (vertex != NULL);
2339   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2340 }
2341
2342 /*
2343  * _clutter_actor_get_relative_transformation_matrix:
2344  * @self: The actor whose coordinate space you want to transform from.
2345  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2346  *            or %NULL if you want to transform all the way to eye coordinates.
2347  * @matrix: A #CoglMatrix to store the transformation
2348  *
2349  * This gets a transformation @matrix that will transform coordinates from the
2350  * coordinate space of @self into the coordinate space of @ancestor.
2351  *
2352  * For example if you need a matrix that can transform the local actor
2353  * coordinates of @self into stage coordinates you would pass the actor's stage
2354  * pointer as the @ancestor.
2355  *
2356  * If you pass %NULL then the transformation will take you all the way through
2357  * to eye coordinates. This can be useful if you want to extract the entire
2358  * modelview transform that Clutter applies before applying the projection
2359  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2360  * using cogl_set_modelview_matrix() for example then you would want a matrix
2361  * that transforms into eye coordinates.
2362  *
2363  * <note><para>This function explicitly initializes the given @matrix. If you just
2364  * want clutter to multiply a relative transformation with an existing matrix
2365  * you can use clutter_actor_apply_relative_transformation_matrix()
2366  * instead.</para></note>
2367  *
2368  */
2369 /* XXX: We should consider caching the stage relative modelview along with
2370  * the actor itself */
2371 static void
2372 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2373                                                    ClutterActor *ancestor,
2374                                                    CoglMatrix *matrix)
2375 {
2376   cogl_matrix_init_identity (matrix);
2377
2378   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2379 }
2380
2381 /* Project the given @box into stage window coordinates, writing the
2382  * transformed vertices to @verts[]. */
2383 static gboolean
2384 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2385                                           const ClutterActorBox *box,
2386                                           ClutterVertex          verts[])
2387 {
2388   ClutterVertex box_vertices[4];
2389
2390   box_vertices[0].x = box->x1;
2391   box_vertices[0].y = box->y1;
2392   box_vertices[0].z = 0;
2393   box_vertices[1].x = box->x2;
2394   box_vertices[1].y = box->y1;
2395   box_vertices[1].z = 0;
2396   box_vertices[2].x = box->x1;
2397   box_vertices[2].y = box->y2;
2398   box_vertices[2].z = 0;
2399   box_vertices[3].x = box->x2;
2400   box_vertices[3].y = box->y2;
2401   box_vertices[3].z = 0;
2402
2403   return
2404     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2405 }
2406
2407 /**
2408  * clutter_actor_get_allocation_vertices:
2409  * @self: A #ClutterActor
2410  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2411  *   against, or %NULL to use the #ClutterStage
2412  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2413  *   location for an array of 4 #ClutterVertex in which to store the result
2414  *
2415  * Calculates the transformed coordinates of the four corners of the
2416  * actor in the plane of @ancestor. The returned vertices relate to
2417  * the #ClutterActorBox coordinates as follows:
2418  * <itemizedlist>
2419  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2420  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2421  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2422  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2423  * </itemizedlist>
2424  *
2425  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2426  * this case, the coordinates returned will be the coordinates on
2427  * the stage before the projection is applied. This is different from
2428  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2429  *
2430  * Since: 0.6
2431  */
2432 void
2433 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2434                                        ClutterActor  *ancestor,
2435                                        ClutterVertex  verts[])
2436 {
2437   ClutterActorPrivate *priv;
2438   ClutterActorBox box;
2439   ClutterVertex vertices[4];
2440   CoglMatrix modelview;
2441
2442   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2443   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2444
2445   if (ancestor == NULL)
2446     ancestor = _clutter_actor_get_stage_internal (self);
2447
2448   /* Fallback to a NOP transform if the actor isn't parented under a
2449    * stage. */
2450   if (ancestor == NULL)
2451     ancestor = self;
2452
2453   priv = self->priv;
2454
2455   /* if the actor needs to be allocated we force a relayout, so that
2456    * we will have valid values to use in the transformations */
2457   if (priv->needs_allocation)
2458     {
2459       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2460       if (stage)
2461         _clutter_stage_maybe_relayout (stage);
2462       else
2463         {
2464           box.x1 = box.y1 = 0;
2465           /* The result isn't really meaningful in this case but at
2466            * least try to do something *vaguely* reasonable... */
2467           clutter_actor_get_size (self, &box.x2, &box.y2);
2468         }
2469     }
2470
2471   clutter_actor_get_allocation_box (self, &box);
2472
2473   vertices[0].x = box.x1;
2474   vertices[0].y = box.y1;
2475   vertices[0].z = 0;
2476   vertices[1].x = box.x2;
2477   vertices[1].y = box.y1;
2478   vertices[1].z = 0;
2479   vertices[2].x = box.x1;
2480   vertices[2].y = box.y2;
2481   vertices[2].z = 0;
2482   vertices[3].x = box.x2;
2483   vertices[3].y = box.y2;
2484   vertices[3].z = 0;
2485
2486   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2487                                                      &modelview);
2488
2489   cogl_matrix_transform_points (&modelview,
2490                                 3,
2491                                 sizeof (ClutterVertex),
2492                                 vertices,
2493                                 sizeof (ClutterVertex),
2494                                 vertices,
2495                                 4);
2496 }
2497
2498 /**
2499  * clutter_actor_get_abs_allocation_vertices:
2500  * @self: A #ClutterActor
2501  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2502  *   of 4 #ClutterVertex where to store the result.
2503  *
2504  * Calculates the transformed screen coordinates of the four corners of
2505  * the actor; the returned vertices relate to the #ClutterActorBox
2506  * coordinates  as follows:
2507  * <itemizedlist>
2508  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2509  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2510  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2511  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2512  * </itemizedlist>
2513  *
2514  * Since: 0.4
2515  */
2516 void
2517 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2518                                            ClutterVertex  verts[])
2519 {
2520   ClutterActorPrivate *priv;
2521   ClutterActorBox actor_space_allocation;
2522
2523   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2524
2525   priv = self->priv;
2526
2527   /* if the actor needs to be allocated we force a relayout, so that
2528    * the actor allocation box will be valid for
2529    * _clutter_actor_transform_and_project_box()
2530    */
2531   if (priv->needs_allocation)
2532     {
2533       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2534       /* There's nothing meaningful we can do now */
2535       if (!stage)
2536         return;
2537
2538       _clutter_stage_maybe_relayout (stage);
2539     }
2540
2541   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2542    * own coordinate space... */
2543   actor_space_allocation.x1 = 0;
2544   actor_space_allocation.y1 = 0;
2545   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2546   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2547   _clutter_actor_transform_and_project_box (self,
2548                                             &actor_space_allocation,
2549                                             verts);
2550 }
2551
2552 static void
2553 clutter_actor_real_apply_transform (ClutterActor *self,
2554                                     CoglMatrix   *matrix)
2555 {
2556   ClutterActorPrivate *priv = self->priv;
2557
2558   if (!priv->transform_valid)
2559     {
2560       CoglMatrix *transform = &priv->transform;
2561       const ClutterTransformInfo *info;
2562
2563       info = _clutter_actor_get_transform_info_or_defaults (self);
2564
2565       cogl_matrix_init_identity (transform);
2566
2567       cogl_matrix_translate (transform,
2568                              priv->allocation.x1,
2569                              priv->allocation.y1,
2570                              0.0);
2571
2572       if (priv->z)
2573         cogl_matrix_translate (transform, 0, 0, priv->z);
2574
2575       /*
2576        * because the rotation involves translations, we must scale
2577        * before applying the rotations (if we apply the scale after
2578        * the rotations, the translations included in the rotation are
2579        * not scaled and so the entire object will move on the screen
2580        * as a result of rotating it).
2581        */
2582       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2583         {
2584           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2585                                         &info->scale_center,
2586                                         cogl_matrix_scale (transform,
2587                                                            info->scale_x,
2588                                                            info->scale_y,
2589                                                            1.0));
2590         }
2591
2592       if (info->rz_angle)
2593         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2594                                       &info->rz_center,
2595                                       cogl_matrix_rotate (transform,
2596                                                           info->rz_angle,
2597                                                           0, 0, 1.0));
2598
2599       if (info->ry_angle)
2600         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2601                                       &info->ry_center,
2602                                       cogl_matrix_rotate (transform,
2603                                                           info->ry_angle,
2604                                                           0, 1.0, 0));
2605
2606       if (info->rx_angle)
2607         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2608                                       &info->rx_center,
2609                                       cogl_matrix_rotate (transform,
2610                                                           info->rx_angle,
2611                                                           1.0, 0, 0));
2612
2613       if (!clutter_anchor_coord_is_zero (&info->anchor))
2614         {
2615           gfloat x, y, z;
2616
2617           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2618           cogl_matrix_translate (transform, -x, -y, -z);
2619         }
2620
2621       priv->transform_valid = TRUE;
2622     }
2623
2624   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2625 }
2626
2627 /* Applies the transforms associated with this actor to the given
2628  * matrix. */
2629 void
2630 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2631                                           CoglMatrix *matrix)
2632 {
2633   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2634 }
2635
2636 /*
2637  * clutter_actor_apply_relative_transformation_matrix:
2638  * @self: The actor whose coordinate space you want to transform from.
2639  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2640  *            or %NULL if you want to transform all the way to eye coordinates.
2641  * @matrix: A #CoglMatrix to apply the transformation too.
2642  *
2643  * This multiplies a transform with @matrix that will transform coordinates
2644  * from the coordinate space of @self into the coordinate space of @ancestor.
2645  *
2646  * For example if you need a matrix that can transform the local actor
2647  * coordinates of @self into stage coordinates you would pass the actor's stage
2648  * pointer as the @ancestor.
2649  *
2650  * If you pass %NULL then the transformation will take you all the way through
2651  * to eye coordinates. This can be useful if you want to extract the entire
2652  * modelview transform that Clutter applies before applying the projection
2653  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2654  * using cogl_set_modelview_matrix() for example then you would want a matrix
2655  * that transforms into eye coordinates.
2656  *
2657  * <note>This function doesn't initialize the given @matrix, it simply
2658  * multiplies the requested transformation matrix with the existing contents of
2659  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2660  * before calling this function, or you can use
2661  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2662  */
2663 void
2664 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2665                                                      ClutterActor *ancestor,
2666                                                      CoglMatrix *matrix)
2667 {
2668   ClutterActor *parent;
2669
2670   /* Note we terminate before ever calling stage->apply_transform()
2671    * since that would conceptually be relative to the underlying
2672    * window OpenGL coordinates so we'd need a special @ancestor
2673    * value to represent the fake parent of the stage. */
2674   if (self == ancestor)
2675     return;
2676
2677   parent = clutter_actor_get_parent (self);
2678
2679   if (parent != NULL)
2680     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2681                                                          matrix);
2682
2683   _clutter_actor_apply_modelview_transform (self, matrix);
2684 }
2685
2686 static void
2687 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2688                                        ClutterPaintVolume *pv,
2689                                        const char *label,
2690                                        const CoglColor *color)
2691 {
2692   static CoglPipeline *outline = NULL;
2693   CoglPrimitive *prim;
2694   ClutterVertex line_ends[12 * 2];
2695   int n_vertices;
2696   CoglContext *ctx =
2697     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2698   /* XXX: at some point we'll query this from the stage but we can't
2699    * do that until the osx backend uses Cogl natively. */
2700   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2701
2702   if (outline == NULL)
2703     outline = cogl_pipeline_new (ctx);
2704
2705   _clutter_paint_volume_complete (pv);
2706
2707   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2708
2709   /* Front face */
2710   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2711   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2712   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2713   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2714
2715   if (!pv->is_2d)
2716     {
2717       /* Back face */
2718       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2719       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2720       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2721       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2722
2723       /* Lines connecting front face to back face */
2724       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2725       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2726       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2727       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2728     }
2729
2730   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2731                                 n_vertices,
2732                                 (CoglVertexP3 *)line_ends);
2733
2734   cogl_pipeline_set_color (outline, color);
2735   cogl_framebuffer_draw_primitive (fb, outline, prim);
2736   cogl_object_unref (prim);
2737
2738   if (label)
2739     {
2740       PangoLayout *layout;
2741       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2742       pango_layout_set_text (layout, label, -1);
2743       cogl_pango_render_layout (layout,
2744                                 pv->vertices[0].x,
2745                                 pv->vertices[0].y,
2746                                 color,
2747                                 0);
2748       g_object_unref (layout);
2749     }
2750 }
2751
2752 static void
2753 _clutter_actor_draw_paint_volume (ClutterActor *self)
2754 {
2755   ClutterPaintVolume *pv;
2756   CoglColor color;
2757
2758   pv = _clutter_actor_get_paint_volume_mutable (self);
2759   if (!pv)
2760     {
2761       gfloat width, height;
2762       ClutterPaintVolume fake_pv;
2763
2764       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2765       _clutter_paint_volume_init_static (&fake_pv, stage);
2766
2767       clutter_actor_get_size (self, &width, &height);
2768       clutter_paint_volume_set_width (&fake_pv, width);
2769       clutter_paint_volume_set_height (&fake_pv, height);
2770
2771       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2772       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2773                                              _clutter_actor_get_debug_name (self),
2774                                              &color);
2775
2776       clutter_paint_volume_free (&fake_pv);
2777     }
2778   else
2779     {
2780       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2781       _clutter_actor_draw_paint_volume_full (self, pv,
2782                                              _clutter_actor_get_debug_name (self),
2783                                              &color);
2784     }
2785 }
2786
2787 static void
2788 _clutter_actor_paint_cull_result (ClutterActor *self,
2789                                   gboolean success,
2790                                   ClutterCullResult result)
2791 {
2792   ClutterPaintVolume *pv;
2793   CoglColor color;
2794
2795   if (success)
2796     {
2797       if (result == CLUTTER_CULL_RESULT_IN)
2798         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2799       else if (result == CLUTTER_CULL_RESULT_OUT)
2800         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2801       else
2802         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2803     }
2804   else
2805     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2806
2807   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2808     _clutter_actor_draw_paint_volume_full (self, pv,
2809                                            _clutter_actor_get_debug_name (self),
2810                                            &color);
2811   else
2812     {
2813       PangoLayout *layout;
2814       char *label =
2815         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2816       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2817       cogl_set_source_color (&color);
2818
2819       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2820       pango_layout_set_text (layout, label, -1);
2821       cogl_pango_render_layout (layout,
2822                                 0,
2823                                 0,
2824                                 &color,
2825                                 0);
2826       g_free (label);
2827       g_object_unref (layout);
2828     }
2829 }
2830
2831 static int clone_paint_level = 0;
2832
2833 void
2834 _clutter_actor_push_clone_paint (void)
2835 {
2836   clone_paint_level++;
2837 }
2838
2839 void
2840 _clutter_actor_pop_clone_paint (void)
2841 {
2842   clone_paint_level--;
2843 }
2844
2845 static gboolean
2846 in_clone_paint (void)
2847 {
2848   return clone_paint_level > 0;
2849 }
2850
2851 /* Returns TRUE if the actor can be ignored */
2852 /* FIXME: we should return a ClutterCullResult, and
2853  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2854  * means there's no point in trying to cull descendants of the current
2855  * node. */
2856 static gboolean
2857 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2858 {
2859   ClutterActorPrivate *priv = self->priv;
2860   ClutterActor *stage;
2861   const ClutterPlane *stage_clip;
2862
2863   if (!priv->last_paint_volume_valid)
2864     {
2865       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2866                     "->last_paint_volume_valid == FALSE",
2867                     _clutter_actor_get_debug_name (self));
2868       return FALSE;
2869     }
2870
2871   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2872     return FALSE;
2873
2874   stage = _clutter_actor_get_stage_internal (self);
2875   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2876   if (G_UNLIKELY (!stage_clip))
2877     {
2878       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2879                     "No stage clip set",
2880                     _clutter_actor_get_debug_name (self));
2881       return FALSE;
2882     }
2883
2884   if (cogl_get_draw_framebuffer () !=
2885       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2886     {
2887       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2888                     "Current framebuffer doesn't correspond to stage",
2889                     _clutter_actor_get_debug_name (self));
2890       return FALSE;
2891     }
2892
2893   *result_out =
2894     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2895   return TRUE;
2896 }
2897
2898 static void
2899 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2900 {
2901   ClutterActorPrivate *priv = self->priv;
2902   const ClutterPaintVolume *pv;
2903
2904   if (priv->last_paint_volume_valid)
2905     {
2906       clutter_paint_volume_free (&priv->last_paint_volume);
2907       priv->last_paint_volume_valid = FALSE;
2908     }
2909
2910   pv = clutter_actor_get_paint_volume (self);
2911   if (!pv)
2912     {
2913       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2914                     "Actor failed to report a paint volume",
2915                     _clutter_actor_get_debug_name (self));
2916       return;
2917     }
2918
2919   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2920
2921   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2922                                             NULL); /* eye coordinates */
2923
2924   priv->last_paint_volume_valid = TRUE;
2925 }
2926
2927 static inline gboolean
2928 actor_has_shader_data (ClutterActor *self)
2929 {
2930   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2931 }
2932
2933 guint32
2934 _clutter_actor_get_pick_id (ClutterActor *self)
2935 {
2936   if (self->priv->pick_id < 0)
2937     return 0;
2938
2939   return self->priv->pick_id;
2940 }
2941
2942 /* This is the same as clutter_actor_add_effect except that it doesn't
2943    queue a redraw and it doesn't notify on the effect property */
2944 static void
2945 _clutter_actor_add_effect_internal (ClutterActor  *self,
2946                                     ClutterEffect *effect)
2947 {
2948   ClutterActorPrivate *priv = self->priv;
2949
2950   if (priv->effects == NULL)
2951     {
2952       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
2953       priv->effects->actor = self;
2954     }
2955
2956   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2957 }
2958
2959 /* This is the same as clutter_actor_remove_effect except that it doesn't
2960    queue a redraw and it doesn't notify on the effect property */
2961 static void
2962 _clutter_actor_remove_effect_internal (ClutterActor  *self,
2963                                        ClutterEffect *effect)
2964 {
2965   ClutterActorPrivate *priv = self->priv;
2966
2967   if (priv->effects == NULL)
2968     return;
2969
2970   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2971 }
2972
2973 static gboolean
2974 needs_flatten_effect (ClutterActor *self)
2975 {
2976   ClutterActorPrivate *priv = self->priv;
2977
2978   if (G_UNLIKELY (clutter_paint_debug_flags &
2979                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
2980     return FALSE;
2981
2982   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
2983     return TRUE;
2984   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
2985     {
2986       if (clutter_actor_get_paint_opacity (self) < 255 &&
2987           clutter_actor_has_overlaps (self))
2988         return TRUE;
2989     }
2990
2991   return FALSE;
2992 }
2993
2994 static void
2995 add_or_remove_flatten_effect (ClutterActor *self)
2996 {
2997   ClutterActorPrivate *priv = self->priv;
2998
2999   /* Add or remove the flatten effect depending on the
3000      offscreen-redirect property. */
3001   if (needs_flatten_effect (self))
3002     {
3003       if (priv->flatten_effect == NULL)
3004         {
3005           ClutterActorMeta *actor_meta;
3006           gint priority;
3007
3008           priv->flatten_effect = _clutter_flatten_effect_new ();
3009           /* Keep a reference to the effect so that we can queue
3010              redraws from it */
3011           g_object_ref_sink (priv->flatten_effect);
3012
3013           /* Set the priority of the effect to high so that it will
3014              always be applied to the actor first. It uses an internal
3015              priority so that it won't be visible to applications */
3016           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3017           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3018           _clutter_actor_meta_set_priority (actor_meta, priority);
3019
3020           /* This will add the effect without queueing a redraw */
3021           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3022         }
3023     }
3024   else
3025     {
3026       if (priv->flatten_effect != NULL)
3027         {
3028           /* Destroy the effect so that it will lose its fbo cache of
3029              the actor */
3030           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3031           g_object_unref (priv->flatten_effect);
3032           priv->flatten_effect = NULL;
3033         }
3034     }
3035 }
3036
3037 static void
3038 clutter_actor_real_paint (ClutterActor *actor)
3039 {
3040   ClutterActorPrivate *priv = actor->priv;
3041   ClutterActor *iter;
3042
3043   /* paint the background color, if set */
3044   if (priv->bg_color_set)
3045     {
3046       float width, height;
3047       guint8 real_alpha;
3048
3049       clutter_actor_box_get_size (&priv->allocation, &width, &height);
3050
3051       real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3052                  * priv->bg_color.alpha
3053                  / 255;
3054
3055       cogl_set_source_color4ub (priv->bg_color.red,
3056                                 priv->bg_color.green,
3057                                 priv->bg_color.blue,
3058                                 real_alpha);
3059
3060       cogl_rectangle (0, 0, width, height);
3061     }
3062
3063   for (iter = priv->first_child;
3064        iter != NULL;
3065        iter = iter->priv->next_sibling)
3066     {
3067       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3068                     _clutter_actor_get_debug_name (iter),
3069                     _clutter_actor_get_debug_name (actor),
3070                     iter->priv->allocation.x1,
3071                     iter->priv->allocation.y1,
3072                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3073                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3074
3075       clutter_actor_paint (iter);
3076     }
3077 }
3078
3079 /**
3080  * clutter_actor_paint:
3081  * @self: A #ClutterActor
3082  *
3083  * Renders the actor to display.
3084  *
3085  * This function should not be called directly by applications.
3086  * Call clutter_actor_queue_redraw() to queue paints, instead.
3087  *
3088  * This function is context-aware, and will either cause a
3089  * regular paint or a pick paint.
3090  *
3091  * This function will emit the #ClutterActor::paint signal or
3092  * the #ClutterActor::pick signal, depending on the context.
3093  *
3094  * This function does not paint the actor if the actor is set to 0,
3095  * unless it is performing a pick paint.
3096  */
3097 void
3098 clutter_actor_paint (ClutterActor *self)
3099 {
3100   ClutterActorPrivate *priv;
3101   ClutterPickMode pick_mode;
3102   gboolean clip_set = FALSE;
3103   gboolean shader_applied = FALSE;
3104
3105   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3106                           "Actor real-paint counter",
3107                           "Increments each time any actor is painted",
3108                           0 /* no application private data */);
3109   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3110                           "Actor pick-paint counter",
3111                           "Increments each time any actor is painted "
3112                           "for picking",
3113                           0 /* no application private data */);
3114
3115   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3116
3117   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3118     return;
3119
3120   priv = self->priv;
3121
3122   pick_mode = _clutter_context_get_pick_mode ();
3123
3124   if (pick_mode == CLUTTER_PICK_NONE)
3125     priv->propagated_one_redraw = FALSE;
3126
3127   /* It's an important optimization that we consider painting of
3128    * actors with 0 opacity to be a NOP... */
3129   if (pick_mode == CLUTTER_PICK_NONE &&
3130       /* ignore top-levels, since they might be transparent */
3131       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3132       /* Use the override opacity if its been set */
3133       ((priv->opacity_override >= 0) ?
3134        priv->opacity_override : priv->opacity) == 0)
3135     return;
3136
3137   /* if we aren't paintable (not in a toplevel with all
3138    * parents paintable) then do nothing.
3139    */
3140   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3141     return;
3142
3143   /* mark that we are in the paint process */
3144   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3145
3146   cogl_push_matrix();
3147
3148   if (priv->enable_model_view_transform)
3149     {
3150       CoglMatrix matrix;
3151
3152       /* XXX: It could be better to cache the modelview with the actor
3153        * instead of progressively building up the transformations on
3154        * the matrix stack every time we paint. */
3155       cogl_get_modelview_matrix (&matrix);
3156       _clutter_actor_apply_modelview_transform (self, &matrix);
3157
3158 #ifdef CLUTTER_ENABLE_DEBUG
3159       /* Catch when out-of-band transforms have been made by actors not as part
3160        * of an apply_transform vfunc... */
3161       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3162         {
3163           CoglMatrix expected_matrix;
3164
3165           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3166                                                              &expected_matrix);
3167
3168           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3169             {
3170               GString *buf = g_string_sized_new (1024);
3171               ClutterActor *parent;
3172
3173               parent = self;
3174               while (parent != NULL)
3175                 {
3176                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3177
3178                   if (parent->priv->parent != NULL)
3179                     g_string_append (buf, "->");
3180
3181                   parent = parent->priv->parent;
3182                 }
3183
3184               g_warning ("Unexpected transform found when painting actor "
3185                          "\"%s\". This will be caused by one of the actor's "
3186                          "ancestors (%s) using the Cogl API directly to transform "
3187                          "children instead of using ::apply_transform().",
3188                          _clutter_actor_get_debug_name (self),
3189                          buf->str);
3190
3191               g_string_free (buf, TRUE);
3192             }
3193         }
3194 #endif /* CLUTTER_ENABLE_DEBUG */
3195
3196       cogl_set_modelview_matrix (&matrix);
3197     }
3198
3199   if (priv->has_clip)
3200     {
3201       cogl_clip_push_rectangle (priv->clip.x,
3202                                 priv->clip.y,
3203                                 priv->clip.x + priv->clip.width,
3204                                 priv->clip.y + priv->clip.height);
3205       clip_set = TRUE;
3206     }
3207   else if (priv->clip_to_allocation)
3208     {
3209       gfloat width, height;
3210
3211       width  = priv->allocation.x2 - priv->allocation.x1;
3212       height = priv->allocation.y2 - priv->allocation.y1;
3213
3214       cogl_clip_push_rectangle (0, 0, width, height);
3215       clip_set = TRUE;
3216     }
3217
3218   if (pick_mode == CLUTTER_PICK_NONE)
3219     {
3220       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3221
3222       /* We check whether we need to add the flatten effect before
3223          each paint so that we can avoid having a mechanism for
3224          applications to notify when the value of the
3225          has_overlaps virtual changes. */
3226       add_or_remove_flatten_effect (self);
3227     }
3228   else
3229     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3230
3231   /* We save the current paint volume so that the next time the
3232    * actor queues a redraw we can constrain the redraw to just
3233    * cover the union of the new bounding box and the old.
3234    *
3235    * We also fetch the current paint volume to perform culling so
3236    * we can avoid painting actors outside the current clip region.
3237    *
3238    * If we are painting inside a clone, we should neither update
3239    * the paint volume or use it to cull painting, since the paint
3240    * box represents the location of the source actor on the
3241    * screen.
3242    *
3243    * XXX: We are starting to do a lot of vertex transforms on
3244    * the CPU in a typical paint, so at some point we should
3245    * audit these and consider caching some things.
3246    *
3247    * NB: We don't perform culling while picking at this point because
3248    * clutter-stage.c doesn't setup the clipping planes appropriately.
3249    *
3250    * NB: We don't want to update the last-paint-volume during picking
3251    * because the last-paint-volume is used to determine the old screen
3252    * space location of an actor that has moved so we can know the
3253    * minimal region to redraw to clear an old view of the actor. If we
3254    * update this during picking then by the time we come around to
3255    * paint then the last-paint-volume would likely represent the new
3256    * actor position not the old.
3257    */
3258   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3259     {
3260       gboolean success;
3261       /* annoyingly gcc warns if uninitialized even though
3262        * the initialization is redundant :-( */
3263       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3264
3265       if (G_LIKELY ((clutter_paint_debug_flags &
3266                      (CLUTTER_DEBUG_DISABLE_CULLING |
3267                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3268                     (CLUTTER_DEBUG_DISABLE_CULLING |
3269                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3270         _clutter_actor_update_last_paint_volume (self);
3271
3272       success = cull_actor (self, &result);
3273
3274       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3275         _clutter_actor_paint_cull_result (self, success, result);
3276       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3277         goto done;
3278     }
3279
3280   if (priv->effects == NULL)
3281     {
3282       if (pick_mode == CLUTTER_PICK_NONE &&
3283           actor_has_shader_data (self))
3284         {
3285           _clutter_actor_shader_pre_paint (self, FALSE);
3286           shader_applied = TRUE;
3287         }
3288
3289       priv->next_effect_to_paint = NULL;
3290     }
3291   else
3292     priv->next_effect_to_paint =
3293       _clutter_meta_group_peek_metas (priv->effects);
3294
3295   clutter_actor_continue_paint (self);
3296
3297   if (shader_applied)
3298     _clutter_actor_shader_post_paint (self);
3299
3300   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3301                   pick_mode == CLUTTER_PICK_NONE))
3302     _clutter_actor_draw_paint_volume (self);
3303
3304 done:
3305   /* If we make it here then the actor has run through a complete
3306      paint run including all the effects so it's no longer dirty */
3307   if (pick_mode == CLUTTER_PICK_NONE)
3308     priv->is_dirty = FALSE;
3309
3310   if (clip_set)
3311     cogl_clip_pop();
3312
3313   cogl_pop_matrix();
3314
3315   /* paint sequence complete */
3316   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3317 }
3318
3319 /**
3320  * clutter_actor_continue_paint:
3321  * @self: A #ClutterActor
3322  *
3323  * Run the next stage of the paint sequence. This function should only
3324  * be called within the implementation of the ‘run’ virtual of a
3325  * #ClutterEffect. It will cause the run method of the next effect to
3326  * be applied, or it will paint the actual actor if the current effect
3327  * is the last effect in the chain.
3328  *
3329  * Since: 1.8
3330  */
3331 void
3332 clutter_actor_continue_paint (ClutterActor *self)
3333 {
3334   ClutterActorPrivate *priv;
3335
3336   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3337   /* This should only be called from with in the ‘run’ implementation
3338      of a ClutterEffect */
3339   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3340
3341   priv = self->priv;
3342
3343   /* Skip any effects that are disabled */
3344   while (priv->next_effect_to_paint &&
3345          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3346     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3347
3348   /* If this has come from the last effect then we'll just paint the
3349      actual actor */
3350   if (priv->next_effect_to_paint == NULL)
3351     {
3352       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3353         {
3354           g_signal_emit (self, actor_signals[PAINT], 0);
3355         }
3356       else
3357         {
3358           ClutterColor col = { 0, };
3359
3360           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3361
3362           /* Actor will then paint silhouette of itself in supplied
3363            * color.  See clutter_stage_get_actor_at_pos() for where
3364            * picking is enabled.
3365            */
3366           g_signal_emit (self, actor_signals[PICK], 0, &col);
3367         }
3368     }
3369   else
3370     {
3371       ClutterEffect *old_current_effect;
3372       ClutterEffectPaintFlags run_flags = 0;
3373
3374       /* Cache the current effect so that we can put it back before
3375          returning */
3376       old_current_effect = priv->current_effect;
3377
3378       priv->current_effect = priv->next_effect_to_paint->data;
3379       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3380
3381       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3382         {
3383           if (priv->is_dirty)
3384             {
3385               /* If there's an effect queued with this redraw then all
3386                  effects up to that one will be considered dirty. It
3387                  is expected the queued effect will paint the cached
3388                  image and not call clutter_actor_continue_paint again
3389                  (although it should work ok if it does) */
3390               if (priv->effect_to_redraw == NULL ||
3391                   priv->current_effect != priv->effect_to_redraw)
3392                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3393             }
3394
3395           _clutter_effect_paint (priv->current_effect, run_flags);
3396         }
3397       else
3398         {
3399           /* We can't determine when an actor has been modified since
3400              its last pick so lets just assume it has always been
3401              modified */
3402           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3403
3404           _clutter_effect_pick (priv->current_effect, run_flags);
3405         }
3406
3407       priv->current_effect = old_current_effect;
3408     }
3409 }
3410
3411 static ClutterActorTraverseVisitFlags
3412 invalidate_queue_redraw_entry (ClutterActor *self,
3413                                int           depth,
3414                                gpointer      user_data)
3415 {
3416   ClutterActorPrivate *priv = self->priv;
3417
3418   if (priv->queue_redraw_entry != NULL)
3419     {
3420       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3421       priv->queue_redraw_entry = NULL;
3422     }
3423
3424   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3425 }
3426
3427 static inline void
3428 remove_child (ClutterActor *self,
3429               ClutterActor *child)
3430 {
3431   ClutterActor *prev_sibling, *next_sibling;
3432
3433   prev_sibling = child->priv->prev_sibling;
3434   next_sibling = child->priv->next_sibling;
3435
3436   if (prev_sibling != NULL)
3437     prev_sibling->priv->next_sibling = next_sibling;
3438
3439   if (next_sibling != NULL)
3440     next_sibling->priv->prev_sibling = prev_sibling;
3441
3442   if (self->priv->first_child == child)
3443     self->priv->first_child = next_sibling;
3444
3445   if (self->priv->last_child == child)
3446     self->priv->last_child = prev_sibling;
3447
3448   child->priv->parent = NULL;
3449   child->priv->prev_sibling = NULL;
3450   child->priv->next_sibling = NULL;
3451 }
3452
3453 typedef enum {
3454   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3455   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3456   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3457   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3458   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3459   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3460
3461   /* default flags for public API */
3462   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3463                                     REMOVE_CHILD_EMIT_PARENT_SET |
3464                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3465                                     REMOVE_CHILD_CHECK_STATE |
3466                                     REMOVE_CHILD_FLUSH_QUEUE |
3467                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3468
3469   /* flags for legacy/deprecated API */
3470   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3471                                     REMOVE_CHILD_FLUSH_QUEUE |
3472                                     REMOVE_CHILD_EMIT_PARENT_SET |
3473                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3474 } ClutterActorRemoveChildFlags;
3475
3476 /*< private >
3477  * clutter_actor_remove_child_internal:
3478  * @self: a #ClutterActor
3479  * @child: the child of @self that has to be removed
3480  * @flags: control the removal operations
3481  *
3482  * Removes @child from the list of children of @self.
3483  */
3484 static void
3485 clutter_actor_remove_child_internal (ClutterActor                 *self,
3486                                      ClutterActor                 *child,
3487                                      ClutterActorRemoveChildFlags  flags)
3488 {
3489   ClutterActor *old_first, *old_last;
3490   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3491   gboolean flush_queue;
3492   gboolean notify_first_last;
3493   gboolean was_mapped;
3494
3495   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3496   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3497   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3498   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3499   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3500   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3501
3502   g_object_freeze_notify (G_OBJECT (self));
3503
3504   if (destroy_meta)
3505     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3506
3507   if (check_state)
3508     {
3509       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3510
3511       /* we need to unrealize *before* we set parent_actor to NULL,
3512        * because in an unrealize method actors are dissociating from the
3513        * stage, which means they need to be able to
3514        * clutter_actor_get_stage().
3515        *
3516        * yhis should unmap and unrealize, unless we're reparenting.
3517        */
3518       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3519     }
3520   else
3521     was_mapped = FALSE;
3522
3523   if (flush_queue)
3524     {
3525       /* We take this opportunity to invalidate any queue redraw entry
3526        * associated with the actor and descendants since we won't be able to
3527        * determine the appropriate stage after this.
3528        *
3529        * we do this after we updated the mapped state because actors might
3530        * end up queueing redraws inside their mapped/unmapped virtual
3531        * functions, and if we invalidate the redraw entry we could end up
3532        * with an inconsistent state and weird memory corruption. see
3533        * bugs:
3534        *
3535        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3536        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3537        */
3538       _clutter_actor_traverse (child,
3539                                0,
3540                                invalidate_queue_redraw_entry,
3541                                NULL,
3542                                NULL);
3543     }
3544
3545   old_first = self->priv->first_child;
3546   old_last = self->priv->last_child;
3547
3548   remove_child (self, child);
3549
3550   self->priv->n_children -= 1;
3551
3552   self->priv->age += 1;
3553
3554   /* clutter_actor_reparent() will emit ::parent-set for us */
3555   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3556     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3557
3558   /* if the child was mapped then we need to relayout ourselves to account
3559    * for the removed child
3560    */
3561   if (was_mapped)
3562     clutter_actor_queue_relayout (self);
3563
3564   /* we need to emit the signal before dropping the reference */
3565   if (emit_actor_removed)
3566     g_signal_emit_by_name (self, "actor-removed", child);
3567
3568   if (notify_first_last)
3569     {
3570       if (old_first != self->priv->first_child)
3571         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3572
3573       if (old_last != self->priv->last_child)
3574         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3575     }
3576
3577   g_object_thaw_notify (G_OBJECT (self));
3578
3579   /* remove the reference we acquired in clutter_actor_add_child() */
3580   g_object_unref (child);
3581 }
3582
3583 static const ClutterTransformInfo default_transform_info = {
3584   0.0, { 0, },          /* rotation-x */
3585   0.0, { 0, },          /* rotation-y */
3586   0.0, { 0, },          /* rotation-z */
3587
3588   1.0, 1.0, { 0, },     /* scale */
3589
3590   { 0, },               /* anchor */
3591 };
3592
3593 /*< private >
3594  * _clutter_actor_get_transform_info_or_defaults:
3595  * @self: a #ClutterActor
3596  *
3597  * Retrieves the ClutterTransformInfo structure associated to an actor.
3598  *
3599  * If the actor does not have a ClutterTransformInfo structure associated
3600  * to it, then the default structure will be returned.
3601  *
3602  * This function should only be used for getters.
3603  *
3604  * Return value: a const pointer to the ClutterTransformInfo structure
3605  */
3606 const ClutterTransformInfo *
3607 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3608 {
3609   ClutterTransformInfo *info;
3610
3611   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3612   if (info != NULL)
3613     return info;
3614
3615   return &default_transform_info;
3616 }
3617
3618 static void
3619 clutter_transform_info_free (gpointer data)
3620 {
3621   if (data != NULL)
3622     g_slice_free (ClutterTransformInfo, data);
3623 }
3624
3625 /*< private >
3626  * _clutter_actor_get_transform_info:
3627  * @self: a #ClutterActor
3628  *
3629  * Retrieves a pointer to the ClutterTransformInfo structure.
3630  *
3631  * If the actor does not have a ClutterTransformInfo associated to it, one
3632  * will be created and initialized to the default values.
3633  *
3634  * This function should be used for setters.
3635  *
3636  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3637  * instead.
3638  *
3639  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3640  *   structure
3641  */
3642 ClutterTransformInfo *
3643 _clutter_actor_get_transform_info (ClutterActor *self)
3644 {
3645   ClutterTransformInfo *info;
3646
3647   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3648   if (info == NULL)
3649     {
3650       info = g_slice_new (ClutterTransformInfo);
3651
3652       *info = default_transform_info;
3653
3654       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3655                                info,
3656                                clutter_transform_info_free);
3657     }
3658
3659   return info;
3660 }
3661
3662 /*< private >
3663  * clutter_actor_set_rotation_angle_internal:
3664  * @self: a #ClutterActor
3665  * @axis: the axis of the angle to change
3666  * @angle: the angle of rotation
3667  *
3668  * Sets the rotation angle on the given axis without affecting the
3669  * rotation center point.
3670  */
3671 static inline void
3672 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3673                                            ClutterRotateAxis  axis,
3674                                            gdouble            angle)
3675 {
3676   GObject *obj = G_OBJECT (self);
3677   ClutterTransformInfo *info;
3678
3679   info = _clutter_actor_get_transform_info (self);
3680
3681   g_object_freeze_notify (obj);
3682
3683   switch (axis)
3684     {
3685     case CLUTTER_X_AXIS:
3686       info->rx_angle = angle;
3687       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3688       break;
3689
3690     case CLUTTER_Y_AXIS:
3691       info->ry_angle = angle;
3692       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3693       break;
3694
3695     case CLUTTER_Z_AXIS:
3696       info->rz_angle = angle;
3697       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3698       break;
3699     }
3700
3701   self->priv->transform_valid = FALSE;
3702
3703   g_object_thaw_notify (obj);
3704
3705   clutter_actor_queue_redraw (self);
3706 }
3707
3708 /*< private >
3709  * clutter_actor_set_rotation_center_internal:
3710  * @self: a #ClutterActor
3711  * @axis: the axis of the center to change
3712  * @center: the coordinates of the rotation center
3713  *
3714  * Sets the rotation center on the given axis without affecting the
3715  * rotation angle.
3716  */
3717 static inline void
3718 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3719                                             ClutterRotateAxis    axis,
3720                                             const ClutterVertex *center)
3721 {
3722   GObject *obj = G_OBJECT (self);
3723   ClutterTransformInfo *info;
3724   ClutterVertex v = { 0, 0, 0 };
3725
3726   info = _clutter_actor_get_transform_info (self);
3727
3728   if (center != NULL)
3729     v = *center;
3730
3731   g_object_freeze_notify (obj);
3732
3733   switch (axis)
3734     {
3735     case CLUTTER_X_AXIS:
3736       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3737       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3738       break;
3739
3740     case CLUTTER_Y_AXIS:
3741       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3742       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3743       break;
3744
3745     case CLUTTER_Z_AXIS:
3746       /* if the previously set rotation center was fractional, then
3747        * setting explicit coordinates will have to notify the
3748        * :rotation-center-z-gravity property as well
3749        */
3750       if (info->rz_center.is_fractional)
3751         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3752
3753       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3754       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3755       break;
3756     }
3757
3758   self->priv->transform_valid = FALSE;
3759
3760   g_object_thaw_notify (obj);
3761
3762   clutter_actor_queue_redraw (self);
3763 }
3764
3765 static inline void
3766 clutter_actor_set_scale_factor (ClutterActor      *self,
3767                                 ClutterRotateAxis  axis,
3768                                 gdouble            factor)
3769 {
3770   GObject *obj = G_OBJECT (self);
3771   ClutterTransformInfo *info;
3772
3773   info = _clutter_actor_get_transform_info (self);
3774
3775   g_object_freeze_notify (obj);
3776
3777   switch (axis)
3778     {
3779     case CLUTTER_X_AXIS:
3780       info->scale_x = factor;
3781       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
3782       break;
3783
3784     case CLUTTER_Y_AXIS:
3785       info->scale_y = factor;
3786       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
3787       break;
3788
3789     default:
3790       g_assert_not_reached ();
3791     }
3792
3793   self->priv->transform_valid = FALSE;
3794
3795   clutter_actor_queue_redraw (self);
3796
3797   g_object_thaw_notify (obj);
3798 }
3799
3800 static inline void
3801 clutter_actor_set_scale_center (ClutterActor      *self,
3802                                 ClutterRotateAxis  axis,
3803                                 gfloat             coord)
3804 {
3805   GObject *obj = G_OBJECT (self);
3806   ClutterTransformInfo *info;
3807   gfloat center_x, center_y;
3808
3809   info = _clutter_actor_get_transform_info (self);
3810
3811   g_object_freeze_notify (obj);
3812
3813   /* get the current scale center coordinates */
3814   clutter_anchor_coord_get_units (self, &info->scale_center,
3815                                   &center_x,
3816                                   &center_y,
3817                                   NULL);
3818
3819   /* we need to notify this too, because setting explicit coordinates will
3820    * change the gravity as a side effect
3821    */
3822   if (info->scale_center.is_fractional)
3823     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3824
3825   switch (axis)
3826     {
3827     case CLUTTER_X_AXIS:
3828       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3829       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3830       break;
3831
3832     case CLUTTER_Y_AXIS:
3833       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3834       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3835       break;
3836
3837     default:
3838       g_assert_not_reached ();
3839     }
3840
3841   self->priv->transform_valid = FALSE;
3842
3843   clutter_actor_queue_redraw (self);
3844
3845   g_object_thaw_notify (obj);
3846 }
3847
3848 static inline void
3849 clutter_actor_set_anchor_coord (ClutterActor      *self,
3850                                 ClutterRotateAxis  axis,
3851                                 gfloat             coord)
3852 {
3853   GObject *obj = G_OBJECT (self);
3854   ClutterTransformInfo *info;
3855   gfloat anchor_x, anchor_y;
3856
3857   info = _clutter_actor_get_transform_info (self);
3858
3859   g_object_freeze_notify (obj);
3860
3861   clutter_anchor_coord_get_units (self, &info->anchor,
3862                                   &anchor_x,
3863                                   &anchor_y,
3864                                   NULL);
3865
3866   if (info->anchor.is_fractional)
3867     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
3868
3869   switch (axis)
3870     {
3871     case CLUTTER_X_AXIS:
3872       clutter_anchor_coord_set_units (&info->anchor,
3873                                       coord,
3874                                       anchor_y,
3875                                       0.0);
3876       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
3877       break;
3878
3879     case CLUTTER_Y_AXIS:
3880       clutter_anchor_coord_set_units (&info->anchor,
3881                                       anchor_x,
3882                                       coord,
3883                                       0.0);
3884       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
3885       break;
3886
3887     default:
3888       g_assert_not_reached ();
3889     }
3890
3891   self->priv->transform_valid = FALSE;
3892
3893   clutter_actor_queue_redraw (self);
3894
3895   g_object_thaw_notify (obj);
3896 }
3897
3898 static void
3899 clutter_actor_set_property (GObject      *object,
3900                             guint         prop_id,
3901                             const GValue *value,
3902                             GParamSpec   *pspec)
3903 {
3904   ClutterActor *actor = CLUTTER_ACTOR (object);
3905   ClutterActorPrivate *priv = actor->priv;
3906
3907   switch (prop_id)
3908     {
3909     case PROP_X:
3910       clutter_actor_set_x (actor, g_value_get_float (value));
3911       break;
3912
3913     case PROP_Y:
3914       clutter_actor_set_y (actor, g_value_get_float (value));
3915       break;
3916
3917     case PROP_WIDTH:
3918       clutter_actor_set_width (actor, g_value_get_float (value));
3919       break;
3920
3921     case PROP_HEIGHT:
3922       clutter_actor_set_height (actor, g_value_get_float (value));
3923       break;
3924
3925     case PROP_FIXED_X:
3926       clutter_actor_set_x (actor, g_value_get_float (value));
3927       break;
3928
3929     case PROP_FIXED_Y:
3930       clutter_actor_set_y (actor, g_value_get_float (value));
3931       break;
3932
3933     case PROP_FIXED_POSITION_SET:
3934       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
3935       break;
3936
3937     case PROP_MIN_WIDTH:
3938       clutter_actor_set_min_width (actor, g_value_get_float (value));
3939       break;
3940
3941     case PROP_MIN_HEIGHT:
3942       clutter_actor_set_min_height (actor, g_value_get_float (value));
3943       break;
3944
3945     case PROP_NATURAL_WIDTH:
3946       clutter_actor_set_natural_width (actor, g_value_get_float (value));
3947       break;
3948
3949     case PROP_NATURAL_HEIGHT:
3950       clutter_actor_set_natural_height (actor, g_value_get_float (value));
3951       break;
3952
3953     case PROP_MIN_WIDTH_SET:
3954       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
3955       break;
3956
3957     case PROP_MIN_HEIGHT_SET:
3958       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
3959       break;
3960
3961     case PROP_NATURAL_WIDTH_SET:
3962       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
3963       break;
3964
3965     case PROP_NATURAL_HEIGHT_SET:
3966       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
3967       break;
3968
3969     case PROP_REQUEST_MODE:
3970       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
3971       break;
3972
3973     case PROP_DEPTH:
3974       clutter_actor_set_depth (actor, g_value_get_float (value));
3975       break;
3976
3977     case PROP_OPACITY:
3978       clutter_actor_set_opacity (actor, g_value_get_uint (value));
3979       break;
3980
3981     case PROP_OFFSCREEN_REDIRECT:
3982       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
3983       break;
3984
3985     case PROP_NAME:
3986       clutter_actor_set_name (actor, g_value_get_string (value));
3987       break;
3988
3989     case PROP_VISIBLE:
3990       if (g_value_get_boolean (value) == TRUE)
3991         clutter_actor_show (actor);
3992       else
3993         clutter_actor_hide (actor);
3994       break;
3995
3996     case PROP_SCALE_X:
3997       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
3998                                       g_value_get_double (value));
3999       break;
4000
4001     case PROP_SCALE_Y:
4002       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4003                                       g_value_get_double (value));
4004       break;
4005
4006     case PROP_SCALE_CENTER_X:
4007       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4008                                       g_value_get_float (value));
4009       break;
4010
4011     case PROP_SCALE_CENTER_Y:
4012       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4013                                       g_value_get_float (value));
4014       break;
4015
4016     case PROP_SCALE_GRAVITY:
4017       {
4018         const ClutterTransformInfo *info;
4019         ClutterGravity gravity;
4020
4021         info = _clutter_actor_get_transform_info_or_defaults (actor);
4022         gravity = g_value_get_enum (value);
4023
4024         clutter_actor_set_scale_with_gravity (actor,
4025                                               info->scale_x,
4026                                               info->scale_y,
4027                                               gravity);
4028       }
4029       break;
4030
4031     case PROP_CLIP:
4032       {
4033         const ClutterGeometry *geom = g_value_get_boxed (value);
4034
4035         clutter_actor_set_clip (actor,
4036                                 geom->x, geom->y,
4037                                 geom->width, geom->height);
4038       }
4039       break;
4040
4041     case PROP_CLIP_TO_ALLOCATION:
4042       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4043       break;
4044
4045     case PROP_REACTIVE:
4046       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4047       break;
4048
4049     case PROP_ROTATION_ANGLE_X:
4050       clutter_actor_set_rotation_angle_internal (actor,
4051                                                  CLUTTER_X_AXIS,
4052                                                  g_value_get_double (value));
4053       break;
4054
4055     case PROP_ROTATION_ANGLE_Y:
4056       clutter_actor_set_rotation_angle_internal (actor,
4057                                                  CLUTTER_Y_AXIS,
4058                                                  g_value_get_double (value));
4059       break;
4060
4061     case PROP_ROTATION_ANGLE_Z:
4062       clutter_actor_set_rotation_angle_internal (actor,
4063                                                  CLUTTER_Z_AXIS,
4064                                                  g_value_get_double (value));
4065       break;
4066
4067     case PROP_ROTATION_CENTER_X:
4068       clutter_actor_set_rotation_center_internal (actor,
4069                                                   CLUTTER_X_AXIS,
4070                                                   g_value_get_boxed (value));
4071       break;
4072
4073     case PROP_ROTATION_CENTER_Y:
4074       clutter_actor_set_rotation_center_internal (actor,
4075                                                   CLUTTER_Y_AXIS,
4076                                                   g_value_get_boxed (value));
4077       break;
4078
4079     case PROP_ROTATION_CENTER_Z:
4080       clutter_actor_set_rotation_center_internal (actor,
4081                                                   CLUTTER_Z_AXIS,
4082                                                   g_value_get_boxed (value));
4083       break;
4084
4085     case PROP_ROTATION_CENTER_Z_GRAVITY:
4086       {
4087         const ClutterTransformInfo *info;
4088
4089         info = _clutter_actor_get_transform_info_or_defaults (actor);
4090         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4091                                                    g_value_get_enum (value));
4092       }
4093       break;
4094
4095     case PROP_ANCHOR_X:
4096       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4097                                       g_value_get_float (value));
4098       break;
4099
4100     case PROP_ANCHOR_Y:
4101       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4102                                       g_value_get_float (value));
4103       break;
4104
4105     case PROP_ANCHOR_GRAVITY:
4106       clutter_actor_set_anchor_point_from_gravity (actor,
4107                                                    g_value_get_enum (value));
4108       break;
4109
4110     case PROP_SHOW_ON_SET_PARENT:
4111       priv->show_on_set_parent = g_value_get_boolean (value);
4112       break;
4113
4114     case PROP_TEXT_DIRECTION:
4115       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4116       break;
4117
4118     case PROP_ACTIONS:
4119       clutter_actor_add_action (actor, g_value_get_object (value));
4120       break;
4121
4122     case PROP_CONSTRAINTS:
4123       clutter_actor_add_constraint (actor, g_value_get_object (value));
4124       break;
4125
4126     case PROP_EFFECT:
4127       clutter_actor_add_effect (actor, g_value_get_object (value));
4128       break;
4129
4130     case PROP_LAYOUT_MANAGER:
4131       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4132       break;
4133
4134     case PROP_X_ALIGN:
4135       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4136       break;
4137
4138     case PROP_Y_ALIGN:
4139       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4140       break;
4141
4142     case PROP_MARGIN_TOP:
4143       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4144       break;
4145
4146     case PROP_MARGIN_BOTTOM:
4147       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4148       break;
4149
4150     case PROP_MARGIN_LEFT:
4151       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4152       break;
4153
4154     case PROP_MARGIN_RIGHT:
4155       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4156       break;
4157
4158     case PROP_BACKGROUND_COLOR:
4159       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4160       break;
4161
4162     default:
4163       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4164       break;
4165     }
4166 }
4167
4168 static void
4169 clutter_actor_get_property (GObject    *object,
4170                             guint       prop_id,
4171                             GValue     *value,
4172                             GParamSpec *pspec)
4173 {
4174   ClutterActor *actor = CLUTTER_ACTOR (object);
4175   ClutterActorPrivate *priv = actor->priv;
4176
4177   switch (prop_id)
4178     {
4179     case PROP_X:
4180       g_value_set_float (value, clutter_actor_get_x (actor));
4181       break;
4182
4183     case PROP_Y:
4184       g_value_set_float (value, clutter_actor_get_y (actor));
4185       break;
4186
4187     case PROP_WIDTH:
4188       g_value_set_float (value, clutter_actor_get_width (actor));
4189       break;
4190
4191     case PROP_HEIGHT:
4192       g_value_set_float (value, clutter_actor_get_height (actor));
4193       break;
4194
4195     case PROP_FIXED_X:
4196       {
4197         const ClutterLayoutInfo *info;
4198
4199         info = _clutter_actor_get_layout_info_or_defaults (actor);
4200         g_value_set_float (value, info->fixed_x);
4201       }
4202       break;
4203
4204     case PROP_FIXED_Y:
4205       {
4206         const ClutterLayoutInfo *info;
4207
4208         info = _clutter_actor_get_layout_info_or_defaults (actor);
4209         g_value_set_float (value, info->fixed_y);
4210       }
4211       break;
4212
4213     case PROP_FIXED_POSITION_SET:
4214       g_value_set_boolean (value, priv->position_set);
4215       break;
4216
4217     case PROP_MIN_WIDTH:
4218       {
4219         const ClutterLayoutInfo *info;
4220
4221         info = _clutter_actor_get_layout_info_or_defaults (actor);
4222         g_value_set_float (value, info->min_width);
4223       }
4224       break;
4225
4226     case PROP_MIN_HEIGHT:
4227       {
4228         const ClutterLayoutInfo *info;
4229
4230         info = _clutter_actor_get_layout_info_or_defaults (actor);
4231         g_value_set_float (value, info->min_height);
4232       }
4233       break;
4234
4235     case PROP_NATURAL_WIDTH:
4236       {
4237         const ClutterLayoutInfo *info;
4238
4239         info = _clutter_actor_get_layout_info_or_defaults (actor);
4240         g_value_set_float (value, info->natural_width);
4241       }
4242       break;
4243
4244     case PROP_NATURAL_HEIGHT:
4245       {
4246         const ClutterLayoutInfo *info;
4247
4248         info = _clutter_actor_get_layout_info_or_defaults (actor);
4249         g_value_set_float (value, info->natural_height);
4250       }
4251       break;
4252
4253     case PROP_MIN_WIDTH_SET:
4254       g_value_set_boolean (value, priv->min_width_set);
4255       break;
4256
4257     case PROP_MIN_HEIGHT_SET:
4258       g_value_set_boolean (value, priv->min_height_set);
4259       break;
4260
4261     case PROP_NATURAL_WIDTH_SET:
4262       g_value_set_boolean (value, priv->natural_width_set);
4263       break;
4264
4265     case PROP_NATURAL_HEIGHT_SET:
4266       g_value_set_boolean (value, priv->natural_height_set);
4267       break;
4268
4269     case PROP_REQUEST_MODE:
4270       g_value_set_enum (value, priv->request_mode);
4271       break;
4272
4273     case PROP_ALLOCATION:
4274       g_value_set_boxed (value, &priv->allocation);
4275       break;
4276
4277     case PROP_DEPTH:
4278       g_value_set_float (value, clutter_actor_get_depth (actor));
4279       break;
4280
4281     case PROP_OPACITY:
4282       g_value_set_uint (value, priv->opacity);
4283       break;
4284
4285     case PROP_OFFSCREEN_REDIRECT:
4286       g_value_set_enum (value, priv->offscreen_redirect);
4287       break;
4288
4289     case PROP_NAME:
4290       g_value_set_string (value, priv->name);
4291       break;
4292
4293     case PROP_VISIBLE:
4294       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4295       break;
4296
4297     case PROP_MAPPED:
4298       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4299       break;
4300
4301     case PROP_REALIZED:
4302       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4303       break;
4304
4305     case PROP_HAS_CLIP:
4306       g_value_set_boolean (value, priv->has_clip);
4307       break;
4308
4309     case PROP_CLIP:
4310       {
4311         ClutterGeometry clip;
4312
4313         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4314         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4315         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4316         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4317
4318         g_value_set_boxed (value, &clip);
4319       }
4320       break;
4321
4322     case PROP_CLIP_TO_ALLOCATION:
4323       g_value_set_boolean (value, priv->clip_to_allocation);
4324       break;
4325
4326     case PROP_SCALE_X:
4327       {
4328         const ClutterTransformInfo *info;
4329
4330         info = _clutter_actor_get_transform_info_or_defaults (actor);
4331         g_value_set_double (value, info->scale_x);
4332       }
4333       break;
4334
4335     case PROP_SCALE_Y:
4336       {
4337         const ClutterTransformInfo *info;
4338
4339         info = _clutter_actor_get_transform_info_or_defaults (actor);
4340         g_value_set_double (value, info->scale_y);
4341       }
4342       break;
4343
4344     case PROP_SCALE_CENTER_X:
4345       {
4346         gfloat center;
4347
4348         clutter_actor_get_scale_center (actor, &center, NULL);
4349
4350         g_value_set_float (value, center);
4351       }
4352       break;
4353
4354     case PROP_SCALE_CENTER_Y:
4355       {
4356         gfloat center;
4357
4358         clutter_actor_get_scale_center (actor, NULL, &center);
4359
4360         g_value_set_float (value, center);
4361       }
4362       break;
4363
4364     case PROP_SCALE_GRAVITY:
4365       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4366       break;
4367
4368     case PROP_REACTIVE:
4369       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4370       break;
4371
4372     case PROP_ROTATION_ANGLE_X:
4373       {
4374         const ClutterTransformInfo *info;
4375
4376         info = _clutter_actor_get_transform_info_or_defaults (actor);
4377         g_value_set_double (value, info->rx_angle);
4378       }
4379       break;
4380
4381     case PROP_ROTATION_ANGLE_Y:
4382       {
4383         const ClutterTransformInfo *info;
4384
4385         info = _clutter_actor_get_transform_info_or_defaults (actor);
4386         g_value_set_double (value, info->ry_angle);
4387       }
4388       break;
4389
4390     case PROP_ROTATION_ANGLE_Z:
4391       {
4392         const ClutterTransformInfo *info;
4393
4394         info = _clutter_actor_get_transform_info_or_defaults (actor);
4395         g_value_set_double (value, info->rz_angle);
4396       }
4397       break;
4398
4399     case PROP_ROTATION_CENTER_X:
4400       {
4401         ClutterVertex center;
4402
4403         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4404                                     &center.x,
4405                                     &center.y,
4406                                     &center.z);
4407
4408         g_value_set_boxed (value, &center);
4409       }
4410       break;
4411
4412     case PROP_ROTATION_CENTER_Y:
4413       {
4414         ClutterVertex center;
4415
4416         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4417                                     &center.x,
4418                                     &center.y,
4419                                     &center.z);
4420
4421         g_value_set_boxed (value, &center);
4422       }
4423       break;
4424
4425     case PROP_ROTATION_CENTER_Z:
4426       {
4427         ClutterVertex center;
4428
4429         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4430                                     &center.x,
4431                                     &center.y,
4432                                     &center.z);
4433
4434         g_value_set_boxed (value, &center);
4435       }
4436       break;
4437
4438     case PROP_ROTATION_CENTER_Z_GRAVITY:
4439       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4440       break;
4441
4442     case PROP_ANCHOR_X:
4443       {
4444         const ClutterTransformInfo *info;
4445         gfloat anchor_x;
4446
4447         info = _clutter_actor_get_transform_info_or_defaults (actor);
4448         clutter_anchor_coord_get_units (actor, &info->anchor,
4449                                         &anchor_x,
4450                                         NULL,
4451                                         NULL);
4452         g_value_set_float (value, anchor_x);
4453       }
4454       break;
4455
4456     case PROP_ANCHOR_Y:
4457       {
4458         const ClutterTransformInfo *info;
4459         gfloat anchor_y;
4460
4461         info = _clutter_actor_get_transform_info_or_defaults (actor);
4462         clutter_anchor_coord_get_units (actor, &info->anchor,
4463                                         NULL,
4464                                         &anchor_y,
4465                                         NULL);
4466         g_value_set_float (value, anchor_y);
4467       }
4468       break;
4469
4470     case PROP_ANCHOR_GRAVITY:
4471       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4472       break;
4473
4474     case PROP_SHOW_ON_SET_PARENT:
4475       g_value_set_boolean (value, priv->show_on_set_parent);
4476       break;
4477
4478     case PROP_TEXT_DIRECTION:
4479       g_value_set_enum (value, priv->text_direction);
4480       break;
4481
4482     case PROP_HAS_POINTER:
4483       g_value_set_boolean (value, priv->has_pointer);
4484       break;
4485
4486     case PROP_LAYOUT_MANAGER:
4487       g_value_set_object (value, priv->layout_manager);
4488       break;
4489
4490     case PROP_X_ALIGN:
4491       {
4492         const ClutterLayoutInfo *info;
4493
4494         info = _clutter_actor_get_layout_info_or_defaults (actor);
4495         g_value_set_enum (value, info->x_align);
4496       }
4497       break;
4498
4499     case PROP_Y_ALIGN:
4500       {
4501         const ClutterLayoutInfo *info;
4502
4503         info = _clutter_actor_get_layout_info_or_defaults (actor);
4504         g_value_set_enum (value, info->y_align);
4505       }
4506       break;
4507
4508     case PROP_MARGIN_TOP:
4509       {
4510         const ClutterLayoutInfo *info;
4511
4512         info = _clutter_actor_get_layout_info_or_defaults (actor);
4513         g_value_set_float (value, info->margin.top);
4514       }
4515       break;
4516
4517     case PROP_MARGIN_BOTTOM:
4518       {
4519         const ClutterLayoutInfo *info;
4520
4521         info = _clutter_actor_get_layout_info_or_defaults (actor);
4522         g_value_set_float (value, info->margin.bottom);
4523       }
4524       break;
4525
4526     case PROP_MARGIN_LEFT:
4527       {
4528         const ClutterLayoutInfo *info;
4529
4530         info = _clutter_actor_get_layout_info_or_defaults (actor);
4531         g_value_set_float (value, info->margin.left);
4532       }
4533       break;
4534
4535     case PROP_MARGIN_RIGHT:
4536       {
4537         const ClutterLayoutInfo *info;
4538
4539         info = _clutter_actor_get_layout_info_or_defaults (actor);
4540         g_value_set_float (value, info->margin.right);
4541       }
4542       break;
4543
4544     case PROP_BACKGROUND_COLOR_SET:
4545       g_value_set_boolean (value, priv->bg_color_set);
4546       break;
4547
4548     case PROP_BACKGROUND_COLOR:
4549       g_value_set_boxed (value, &priv->bg_color);
4550       break;
4551
4552     case PROP_FIRST_CHILD:
4553       g_value_set_object (value, priv->first_child);
4554       break;
4555
4556     case PROP_LAST_CHILD:
4557       g_value_set_object (value, priv->last_child);
4558       break;
4559
4560     default:
4561       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4562       break;
4563     }
4564 }
4565
4566 static void
4567 clutter_actor_dispose (GObject *object)
4568 {
4569   ClutterActor *self = CLUTTER_ACTOR (object);
4570   ClutterActorPrivate *priv = self->priv;
4571
4572   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4573                 priv->id,
4574                 g_type_name (G_OBJECT_TYPE (self)),
4575                 object->ref_count);
4576
4577   g_signal_emit (self, actor_signals[DESTROY], 0);
4578
4579   /* avoid recursing when called from clutter_actor_destroy() */
4580   if (priv->parent != NULL)
4581     {
4582       ClutterActor *parent = priv->parent;
4583
4584       /* go through the Container implementation unless this
4585        * is an internal child and has been marked as such.
4586        *
4587        * removing the actor from its parent will reset the
4588        * realized and mapped states.
4589        */
4590       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4591         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4592       else
4593         clutter_actor_remove_child_internal (parent, self,
4594                                              REMOVE_CHILD_LEGACY_FLAGS);
4595     }
4596
4597   /* parent must be gone at this point */
4598   g_assert (priv->parent == NULL);
4599
4600   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4601     {
4602       /* can't be mapped or realized with no parent */
4603       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4604       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4605     }
4606
4607   g_clear_object (&priv->pango_context);
4608   g_clear_object (&priv->actions);
4609   g_clear_object (&priv->constraints);
4610   g_clear_object (&priv->effects);
4611   g_clear_object (&priv->flatten_effect);
4612
4613   if (priv->layout_manager != NULL)
4614     {
4615       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4616       g_object_unref (priv->layout_manager);
4617       priv->layout_manager = NULL;
4618     }
4619
4620   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4621 }
4622
4623 static void
4624 clutter_actor_finalize (GObject *object)
4625 {
4626   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4627
4628   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4629                 priv->name != NULL ? priv->name : "<none>",
4630                 priv->id,
4631                 g_type_name (G_OBJECT_TYPE (object)));
4632
4633   _clutter_context_release_id (priv->id);
4634
4635   g_free (priv->name);
4636
4637   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4638 }
4639
4640
4641 /**
4642  * clutter_actor_get_accessible:
4643  * @self: a #ClutterActor
4644  *
4645  * Returns the accessible object that describes the actor to an
4646  * assistive technology.
4647  *
4648  * If no class-specific #AtkObject implementation is available for the
4649  * actor instance in question, it will inherit an #AtkObject
4650  * implementation from the first ancestor class for which such an
4651  * implementation is defined.
4652  *
4653  * The documentation of the <ulink
4654  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4655  * library contains more information about accessible objects and
4656  * their uses.
4657  *
4658  * Returns: (transfer none): the #AtkObject associated with @actor
4659  */
4660 AtkObject *
4661 clutter_actor_get_accessible (ClutterActor *self)
4662 {
4663   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4664
4665   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4666 }
4667
4668 static AtkObject *
4669 clutter_actor_real_get_accessible (ClutterActor *actor)
4670 {
4671   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4672 }
4673
4674 static AtkObject *
4675 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4676 {
4677   AtkObject *accessible;
4678
4679   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4680   if (accessible != NULL)
4681     g_object_ref (accessible);
4682
4683   return accessible;
4684 }
4685
4686 static void
4687 atk_implementor_iface_init (AtkImplementorIface *iface)
4688 {
4689   iface->ref_accessible = _clutter_actor_ref_accessible;
4690 }
4691
4692 static gboolean
4693 clutter_actor_update_default_paint_volume (ClutterActor       *self,
4694                                            ClutterPaintVolume *volume)
4695 {
4696   ClutterActorPrivate *priv = self->priv;
4697   gboolean res = FALSE;
4698
4699   /* we start from the allocation */
4700   clutter_paint_volume_set_width (volume,
4701                                   priv->allocation.x2 - priv->allocation.x1);
4702   clutter_paint_volume_set_height (volume,
4703                                    priv->allocation.y2 - priv->allocation.y1);
4704
4705   /* if the actor has a clip set then we have a pretty definite
4706    * size for the paint volume: the actor cannot possibly paint
4707    * outside the clip region.
4708    */
4709   if (priv->clip_to_allocation)
4710     {
4711       /* the allocation has already been set, so we just flip the
4712        * return value
4713        */
4714       res = TRUE;
4715     }
4716   else
4717     {
4718       ClutterActor *child;
4719
4720       if (priv->has_clip &&
4721           priv->clip.width >= 0 &&
4722           priv->clip.height >= 0)
4723         {
4724           ClutterVertex origin;
4725
4726           origin.x = priv->clip.x;
4727           origin.y = priv->clip.y;
4728           origin.z = 0;
4729
4730           clutter_paint_volume_set_origin (volume, &origin);
4731           clutter_paint_volume_set_width (volume, priv->clip.width);
4732           clutter_paint_volume_set_height (volume, priv->clip.height);
4733
4734           res = TRUE;
4735         }
4736
4737       /* if we don't have children we just bail out here... */
4738       if (priv->n_children == 0)
4739         return res;
4740
4741       /* ...but if we have children then we ask for their paint volume in
4742        * our coordinates. if any of our children replies that it doesn't
4743        * have a paint volume, we bail out
4744        */
4745       for (child = priv->first_child;
4746            child != NULL;
4747            child = child->priv->next_sibling)
4748         {
4749           const ClutterPaintVolume *child_volume;
4750
4751           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4752           if (child_volume == NULL)
4753             {
4754               res = FALSE;
4755               break;
4756             }
4757
4758           clutter_paint_volume_union (volume, child_volume);
4759           res = TRUE;
4760         }
4761     }
4762
4763   return res;
4764
4765 }
4766
4767 static gboolean
4768 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4769                                      ClutterPaintVolume *volume)
4770 {
4771   ClutterActorClass *klass;
4772   gboolean res;
4773
4774   klass = CLUTTER_ACTOR_GET_CLASS (self);
4775
4776   /* XXX - this thoroughly sucks, but we don't want to penalize users
4777    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
4778    * redraw. This should go away in 2.0.
4779    */
4780   if (klass->paint == clutter_actor_real_paint &&
4781       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
4782     {
4783       res = TRUE;
4784     }
4785   else
4786     {
4787       /* this is the default return value: we cannot know if a class
4788        * is going to paint outside its allocation, so we take the
4789        * conservative approach.
4790        */
4791       res = FALSE;
4792     }
4793
4794   if (clutter_actor_update_default_paint_volume (self, volume))
4795     return res;
4796
4797   return FALSE;
4798 }
4799
4800 /**
4801  * clutter_actor_get_default_paint_volume:
4802  * @self: a #ClutterActor
4803  *
4804  * Retrieves the default paint volume for @self.
4805  *
4806  * This function provides the same #ClutterPaintVolume that would be
4807  * computed by the default implementation inside #ClutterActor of the
4808  * #ClutterActorClass.get_paint_volume() virtual function.
4809  *
4810  * This function should only be used by #ClutterActor subclasses that
4811  * cannot chain up to the parent implementation when computing their
4812  * paint volume.
4813  *
4814  * Return value: (transfer none): a pointer to the default
4815  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
4816  *   the actor could not compute a valid paint volume. The returned value
4817  *   is not guaranteed to be stable across multiple frames, so if you
4818  *   want to retain it, you will need to copy it using
4819  *   clutter_paint_volume_copy().
4820  *
4821  * Since: 1.10
4822  */
4823 const ClutterPaintVolume *
4824 clutter_actor_get_default_paint_volume (ClutterActor *self)
4825 {
4826   ClutterPaintVolume volume;
4827   ClutterPaintVolume *res;
4828
4829   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4830
4831   res = NULL;
4832   _clutter_paint_volume_init_static (&volume, self);
4833   if (clutter_actor_update_default_paint_volume (self, &volume))
4834     {
4835       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
4836
4837       if (stage != NULL)
4838         {
4839           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
4840           _clutter_paint_volume_copy_static (&volume, res);
4841         }
4842     }
4843
4844   clutter_paint_volume_free (&volume);
4845
4846   return res;
4847 }
4848
4849 static gboolean
4850 clutter_actor_real_has_overlaps (ClutterActor *self)
4851 {
4852   /* By default we'll assume that all actors need an offscreen redirect to get
4853    * the correct opacity. Actors such as ClutterTexture that would never need
4854    * an offscreen redirect can override this to return FALSE. */
4855   return TRUE;
4856 }
4857
4858 static void
4859 clutter_actor_real_destroy (ClutterActor *actor)
4860 {
4861   ClutterActorIter iter;
4862
4863   clutter_actor_iter_init (&iter, actor);
4864   while (clutter_actor_iter_next (&iter, NULL))
4865     clutter_actor_iter_destroy (&iter);
4866 }
4867
4868 static GObject *
4869 clutter_actor_constructor (GType gtype,
4870                            guint n_props,
4871                            GObjectConstructParam *props)
4872 {
4873   GObjectClass *gobject_class;
4874   ClutterActor *self;
4875   GObject *retval;
4876
4877   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
4878   retval = gobject_class->constructor (gtype, n_props, props);
4879   self = CLUTTER_ACTOR (retval);
4880
4881   if (self->priv->layout_manager == NULL)
4882     {
4883       ClutterLayoutManager *default_layout;
4884
4885       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
4886
4887       default_layout = clutter_fixed_layout_new ();
4888       clutter_actor_set_layout_manager (self, default_layout);
4889     }
4890
4891   return retval;
4892 }
4893
4894 static void
4895 clutter_actor_class_init (ClutterActorClass *klass)
4896 {
4897   GObjectClass *object_class = G_OBJECT_CLASS (klass);
4898
4899   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
4900   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
4901   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
4902
4903   object_class->constructor = clutter_actor_constructor;
4904   object_class->set_property = clutter_actor_set_property;
4905   object_class->get_property = clutter_actor_get_property;
4906   object_class->dispose = clutter_actor_dispose;
4907   object_class->finalize = clutter_actor_finalize;
4908
4909   klass->show = clutter_actor_real_show;
4910   klass->show_all = clutter_actor_show;
4911   klass->hide = clutter_actor_real_hide;
4912   klass->hide_all = clutter_actor_hide;
4913   klass->map = clutter_actor_real_map;
4914   klass->unmap = clutter_actor_real_unmap;
4915   klass->unrealize = clutter_actor_real_unrealize;
4916   klass->pick = clutter_actor_real_pick;
4917   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
4918   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4919   klass->allocate = clutter_actor_real_allocate;
4920   klass->queue_redraw = clutter_actor_real_queue_redraw;
4921   klass->queue_relayout = clutter_actor_real_queue_relayout;
4922   klass->apply_transform = clutter_actor_real_apply_transform;
4923   klass->get_accessible = clutter_actor_real_get_accessible;
4924   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
4925   klass->has_overlaps = clutter_actor_real_has_overlaps;
4926   klass->paint = clutter_actor_real_paint;
4927   klass->destroy = clutter_actor_real_destroy;
4928
4929   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
4930
4931   /**
4932    * ClutterActor:x:
4933    *
4934    * X coordinate of the actor in pixels. If written, forces a fixed
4935    * position for the actor. If read, returns the fixed position if any,
4936    * otherwise the allocation if available, otherwise 0.
4937    */
4938   obj_props[PROP_X] =
4939     g_param_spec_float ("x",
4940                         P_("X coordinate"),
4941                         P_("X coordinate of the actor"),
4942                         -G_MAXFLOAT, G_MAXFLOAT,
4943                         0.0,
4944                         CLUTTER_PARAM_READWRITE);
4945
4946   /**
4947    * ClutterActor:y:
4948    *
4949    * Y coordinate of the actor in pixels. If written, forces a fixed
4950    * position for the actor.  If read, returns the fixed position if
4951    * any, otherwise the allocation if available, otherwise 0.
4952    */
4953   obj_props[PROP_Y] =
4954     g_param_spec_float ("y",
4955                         P_("Y coordinate"),
4956                         P_("Y coordinate of the actor"),
4957                         -G_MAXFLOAT, G_MAXFLOAT,
4958                         0.0,
4959                         CLUTTER_PARAM_READWRITE);
4960
4961   /**
4962    * ClutterActor:width:
4963    *
4964    * Width of the actor (in pixels). If written, forces the minimum and
4965    * natural size request of the actor to the given width. If read, returns
4966    * the allocated width if available, otherwise the width request.
4967    */
4968   obj_props[PROP_WIDTH] =
4969     g_param_spec_float ("width",
4970                         P_("Width"),
4971                         P_("Width of the actor"),
4972                         0.0, G_MAXFLOAT,
4973                         0.0,
4974                         CLUTTER_PARAM_READWRITE);
4975
4976   /**
4977    * ClutterActor:height:
4978    *
4979    * Height of the actor (in pixels).  If written, forces the minimum and
4980    * natural size request of the actor to the given height. If read, returns
4981    * the allocated height if available, otherwise the height request.
4982    */
4983   obj_props[PROP_HEIGHT] =
4984     g_param_spec_float ("height",
4985                         P_("Height"),
4986                         P_("Height of the actor"),
4987                         0.0, G_MAXFLOAT,
4988                         0.0,
4989                         CLUTTER_PARAM_READWRITE);
4990
4991   /**
4992    * ClutterActor:fixed-x:
4993    *
4994    * The fixed X position of the actor in pixels.
4995    *
4996    * Writing this property sets #ClutterActor:fixed-position-set
4997    * property as well, as a side effect
4998    *
4999    * Since: 0.8
5000    */
5001   obj_props[PROP_FIXED_X] =
5002     g_param_spec_float ("fixed-x",
5003                         P_("Fixed X"),
5004                         P_("Forced X position of the actor"),
5005                         -G_MAXFLOAT, G_MAXFLOAT,
5006                         0.0,
5007                         CLUTTER_PARAM_READWRITE);
5008
5009   /**
5010    * ClutterActor:fixed-y:
5011    *
5012    * The fixed Y position of the actor in pixels.
5013    *
5014    * Writing this property sets the #ClutterActor:fixed-position-set
5015    * property as well, as a side effect
5016    *
5017    * Since: 0.8
5018    */
5019   obj_props[PROP_FIXED_Y] =
5020     g_param_spec_float ("fixed-y",
5021                         P_("Fixed Y"),
5022                         P_("Forced Y position of the actor"),
5023                         -G_MAXFLOAT, G_MAXFLOAT,
5024                         0,
5025                         CLUTTER_PARAM_READWRITE);
5026
5027   /**
5028    * ClutterActor:fixed-position-set:
5029    *
5030    * This flag controls whether the #ClutterActor:fixed-x and
5031    * #ClutterActor:fixed-y properties are used
5032    *
5033    * Since: 0.8
5034    */
5035   obj_props[PROP_FIXED_POSITION_SET] =
5036     g_param_spec_boolean ("fixed-position-set",
5037                           P_("Fixed position set"),
5038                           P_("Whether to use fixed positioning for the actor"),
5039                           FALSE,
5040                           CLUTTER_PARAM_READWRITE);
5041
5042   /**
5043    * ClutterActor:min-width:
5044    *
5045    * A forced minimum width request for the actor, in pixels
5046    *
5047    * Writing this property sets the #ClutterActor:min-width-set property
5048    * as well, as a side effect.
5049    *
5050    *This property overrides the usual width request of the actor.
5051    *
5052    * Since: 0.8
5053    */
5054   obj_props[PROP_MIN_WIDTH] =
5055     g_param_spec_float ("min-width",
5056                         P_("Min Width"),
5057                         P_("Forced minimum width request for the actor"),
5058                         0.0, G_MAXFLOAT,
5059                         0.0,
5060                         CLUTTER_PARAM_READWRITE);
5061
5062   /**
5063    * ClutterActor:min-height:
5064    *
5065    * A forced minimum height request for the actor, in pixels
5066    *
5067    * Writing this property sets the #ClutterActor:min-height-set property
5068    * as well, as a side effect. This property overrides the usual height
5069    * request of the actor.
5070    *
5071    * Since: 0.8
5072    */
5073   obj_props[PROP_MIN_HEIGHT] =
5074     g_param_spec_float ("min-height",
5075                         P_("Min Height"),
5076                         P_("Forced minimum height request for the actor"),
5077                         0.0, G_MAXFLOAT,
5078                         0.0,
5079                         CLUTTER_PARAM_READWRITE);
5080
5081   /**
5082    * ClutterActor:natural-width:
5083    *
5084    * A forced natural width request for the actor, in pixels
5085    *
5086    * Writing this property sets the #ClutterActor:natural-width-set
5087    * property as well, as a side effect. This property overrides the
5088    * usual width request of the actor
5089    *
5090    * Since: 0.8
5091    */
5092   obj_props[PROP_NATURAL_WIDTH] =
5093     g_param_spec_float ("natural-width",
5094                         P_("Natural Width"),
5095                         P_("Forced natural width request for the actor"),
5096                         0.0, G_MAXFLOAT,
5097                         0.0,
5098                         CLUTTER_PARAM_READWRITE);
5099
5100   /**
5101    * ClutterActor:natural-height:
5102    *
5103    * A forced natural height request for the actor, in pixels
5104    *
5105    * Writing this property sets the #ClutterActor:natural-height-set
5106    * property as well, as a side effect. This property overrides the
5107    * usual height request of the actor
5108    *
5109    * Since: 0.8
5110    */
5111   obj_props[PROP_NATURAL_HEIGHT] =
5112     g_param_spec_float ("natural-height",
5113                         P_("Natural Height"),
5114                         P_("Forced natural height request for the actor"),
5115                         0.0, G_MAXFLOAT,
5116                         0.0,
5117                         CLUTTER_PARAM_READWRITE);
5118
5119   /**
5120    * ClutterActor:min-width-set:
5121    *
5122    * This flag controls whether the #ClutterActor:min-width property
5123    * is used
5124    *
5125    * Since: 0.8
5126    */
5127   obj_props[PROP_MIN_WIDTH_SET] =
5128     g_param_spec_boolean ("min-width-set",
5129                           P_("Minimum width set"),
5130                           P_("Whether to use the min-width property"),
5131                           FALSE,
5132                           CLUTTER_PARAM_READWRITE);
5133
5134   /**
5135    * ClutterActor:min-height-set:
5136    *
5137    * This flag controls whether the #ClutterActor:min-height property
5138    * is used
5139    *
5140    * Since: 0.8
5141    */
5142   obj_props[PROP_MIN_HEIGHT_SET] =
5143     g_param_spec_boolean ("min-height-set",
5144                           P_("Minimum height set"),
5145                           P_("Whether to use the min-height property"),
5146                           FALSE,
5147                           CLUTTER_PARAM_READWRITE);
5148
5149   /**
5150    * ClutterActor:natural-width-set:
5151    *
5152    * This flag controls whether the #ClutterActor:natural-width property
5153    * is used
5154    *
5155    * Since: 0.8
5156    */
5157   obj_props[PROP_NATURAL_WIDTH_SET] =
5158     g_param_spec_boolean ("natural-width-set",
5159                           P_("Natural width set"),
5160                           P_("Whether to use the natural-width property"),
5161                           FALSE,
5162                           CLUTTER_PARAM_READWRITE);
5163
5164   /**
5165    * ClutterActor:natural-height-set:
5166    *
5167    * This flag controls whether the #ClutterActor:natural-height property
5168    * is used
5169    *
5170    * Since: 0.8
5171    */
5172   obj_props[PROP_NATURAL_HEIGHT_SET] =
5173     g_param_spec_boolean ("natural-height-set",
5174                           P_("Natural height set"),
5175                           P_("Whether to use the natural-height property"),
5176                           FALSE,
5177                           CLUTTER_PARAM_READWRITE);
5178
5179   /**
5180    * ClutterActor:allocation:
5181    *
5182    * The allocation for the actor, in pixels
5183    *
5184    * This is property is read-only, but you might monitor it to know when an
5185    * actor moves or resizes
5186    *
5187    * Since: 0.8
5188    */
5189   obj_props[PROP_ALLOCATION] =
5190     g_param_spec_boxed ("allocation",
5191                         P_("Allocation"),
5192                         P_("The actor's allocation"),
5193                         CLUTTER_TYPE_ACTOR_BOX,
5194                         CLUTTER_PARAM_READABLE);
5195
5196   /**
5197    * ClutterActor:request-mode:
5198    *
5199    * Request mode for the #ClutterActor. The request mode determines the
5200    * type of geometry management used by the actor, either height for width
5201    * (the default) or width for height.
5202    *
5203    * For actors implementing height for width, the parent container should get
5204    * the preferred width first, and then the preferred height for that width.
5205    *
5206    * For actors implementing width for height, the parent container should get
5207    * the preferred height first, and then the preferred width for that height.
5208    *
5209    * For instance:
5210    *
5211    * |[
5212    *   ClutterRequestMode mode;
5213    *   gfloat natural_width, min_width;
5214    *   gfloat natural_height, min_height;
5215    *
5216    *   mode = clutter_actor_get_request_mode (child);
5217    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5218    *     {
5219    *       clutter_actor_get_preferred_width (child, -1,
5220    *                                          &amp;min_width,
5221    *                                          &amp;natural_width);
5222    *       clutter_actor_get_preferred_height (child, natural_width,
5223    *                                           &amp;min_height,
5224    *                                           &amp;natural_height);
5225    *     }
5226    *   else
5227    *     {
5228    *       clutter_actor_get_preferred_height (child, -1,
5229    *                                           &amp;min_height,
5230    *                                           &amp;natural_height);
5231    *       clutter_actor_get_preferred_width (child, natural_height,
5232    *                                          &amp;min_width,
5233    *                                          &amp;natural_width);
5234    *     }
5235    * ]|
5236    *
5237    * will retrieve the minimum and natural width and height depending on the
5238    * preferred request mode of the #ClutterActor "child".
5239    *
5240    * The clutter_actor_get_preferred_size() function will implement this
5241    * check for you.
5242    *
5243    * Since: 0.8
5244    */
5245   obj_props[PROP_REQUEST_MODE] =
5246     g_param_spec_enum ("request-mode",
5247                        P_("Request Mode"),
5248                        P_("The actor's request mode"),
5249                        CLUTTER_TYPE_REQUEST_MODE,
5250                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5251                        CLUTTER_PARAM_READWRITE);
5252
5253   /**
5254    * ClutterActor:depth:
5255    *
5256    * The position of the actor on the Z axis
5257    *
5258    * Since: 0.6
5259    */
5260   obj_props[PROP_DEPTH] =
5261     g_param_spec_float ("depth",
5262                         P_("Depth"),
5263                         P_("Position on the Z axis"),
5264                         -G_MAXFLOAT, G_MAXFLOAT,
5265                         0.0,
5266                         CLUTTER_PARAM_READWRITE);
5267
5268   /**
5269    * ClutterActor:opacity:
5270    *
5271    * Opacity of an actor, between 0 (fully transparent) and
5272    * 255 (fully opaque)
5273    */
5274   obj_props[PROP_OPACITY] =
5275     g_param_spec_uint ("opacity",
5276                        P_("Opacity"),
5277                        P_("Opacity of an actor"),
5278                        0, 255,
5279                        255,
5280                        CLUTTER_PARAM_READWRITE);
5281
5282   /**
5283    * ClutterActor:offscreen-redirect:
5284    *
5285    * Determines the conditions in which the actor will be redirected
5286    * to an offscreen framebuffer while being painted. For example this
5287    * can be used to cache an actor in a framebuffer or for improved
5288    * handling of transparent actors. See
5289    * clutter_actor_set_offscreen_redirect() for details.
5290    *
5291    * Since: 1.8
5292    */
5293   obj_props[PROP_OFFSCREEN_REDIRECT] =
5294     g_param_spec_flags ("offscreen-redirect",
5295                         P_("Offscreen redirect"),
5296                         P_("Flags controlling when to flatten the actor into a single image"),
5297                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5298                         0,
5299                         CLUTTER_PARAM_READWRITE);
5300
5301   /**
5302    * ClutterActor:visible:
5303    *
5304    * Whether the actor is set to be visible or not
5305    *
5306    * See also #ClutterActor:mapped
5307    */
5308   obj_props[PROP_VISIBLE] =
5309     g_param_spec_boolean ("visible",
5310                           P_("Visible"),
5311                           P_("Whether the actor is visible or not"),
5312                           FALSE,
5313                           CLUTTER_PARAM_READWRITE);
5314
5315   /**
5316    * ClutterActor:mapped:
5317    *
5318    * Whether the actor is mapped (will be painted when the stage
5319    * to which it belongs is mapped)
5320    *
5321    * Since: 1.0
5322    */
5323   obj_props[PROP_MAPPED] =
5324     g_param_spec_boolean ("mapped",
5325                           P_("Mapped"),
5326                           P_("Whether the actor will be painted"),
5327                           FALSE,
5328                           CLUTTER_PARAM_READABLE);
5329
5330   /**
5331    * ClutterActor:realized:
5332    *
5333    * Whether the actor has been realized
5334    *
5335    * Since: 1.0
5336    */
5337   obj_props[PROP_REALIZED] =
5338     g_param_spec_boolean ("realized",
5339                           P_("Realized"),
5340                           P_("Whether the actor has been realized"),
5341                           FALSE,
5342                           CLUTTER_PARAM_READABLE);
5343
5344   /**
5345    * ClutterActor:reactive:
5346    *
5347    * Whether the actor is reactive to events or not
5348    *
5349    * Only reactive actors will emit event-related signals
5350    *
5351    * Since: 0.6
5352    */
5353   obj_props[PROP_REACTIVE] =
5354     g_param_spec_boolean ("reactive",
5355                           P_("Reactive"),
5356                           P_("Whether the actor is reactive to events"),
5357                           FALSE,
5358                           CLUTTER_PARAM_READWRITE);
5359
5360   /**
5361    * ClutterActor:has-clip:
5362    *
5363    * Whether the actor has the #ClutterActor:clip property set or not
5364    */
5365   obj_props[PROP_HAS_CLIP] =
5366     g_param_spec_boolean ("has-clip",
5367                           P_("Has Clip"),
5368                           P_("Whether the actor has a clip set"),
5369                           FALSE,
5370                           CLUTTER_PARAM_READABLE);
5371
5372   /**
5373    * ClutterActor:clip:
5374    *
5375    * The clip region for the actor, in actor-relative coordinates
5376    *
5377    * Every part of the actor outside the clip region will not be
5378    * painted
5379    */
5380   obj_props[PROP_CLIP] =
5381     g_param_spec_boxed ("clip",
5382                         P_("Clip"),
5383                         P_("The clip region for the actor"),
5384                         CLUTTER_TYPE_GEOMETRY,
5385                         CLUTTER_PARAM_READWRITE);
5386
5387   /**
5388    * ClutterActor:name:
5389    *
5390    * The name of the actor
5391    *
5392    * Since: 0.2
5393    */
5394   obj_props[PROP_NAME] =
5395     g_param_spec_string ("name",
5396                          P_("Name"),
5397                          P_("Name of the actor"),
5398                          NULL,
5399                          CLUTTER_PARAM_READWRITE);
5400
5401   /**
5402    * ClutterActor:scale-x:
5403    *
5404    * The horizontal scale of the actor
5405    *
5406    * Since: 0.6
5407    */
5408   obj_props[PROP_SCALE_X] =
5409     g_param_spec_double ("scale-x",
5410                          P_("Scale X"),
5411                          P_("Scale factor on the X axis"),
5412                          0.0, G_MAXDOUBLE,
5413                          1.0,
5414                          CLUTTER_PARAM_READWRITE);
5415
5416   /**
5417    * ClutterActor:scale-y:
5418    *
5419    * The vertical scale of the actor
5420    *
5421    * Since: 0.6
5422    */
5423   obj_props[PROP_SCALE_Y] =
5424     g_param_spec_double ("scale-y",
5425                          P_("Scale Y"),
5426                          P_("Scale factor on the Y axis"),
5427                          0.0, G_MAXDOUBLE,
5428                          1.0,
5429                          CLUTTER_PARAM_READWRITE);
5430
5431   /**
5432    * ClutterActor:scale-center-x:
5433    *
5434    * The horizontal center point for scaling
5435    *
5436    * Since: 1.0
5437    */
5438   obj_props[PROP_SCALE_CENTER_X] =
5439     g_param_spec_float ("scale-center-x",
5440                         P_("Scale Center X"),
5441                         P_("Horizontal scale center"),
5442                         -G_MAXFLOAT, G_MAXFLOAT,
5443                         0.0,
5444                         CLUTTER_PARAM_READWRITE);
5445
5446   /**
5447    * ClutterActor:scale-center-y:
5448    *
5449    * The vertical center point for scaling
5450    *
5451    * Since: 1.0
5452    */
5453   obj_props[PROP_SCALE_CENTER_Y] =
5454     g_param_spec_float ("scale-center-y",
5455                         P_("Scale Center Y"),
5456                         P_("Vertical scale center"),
5457                         -G_MAXFLOAT, G_MAXFLOAT,
5458                         0.0,
5459                         CLUTTER_PARAM_READWRITE);
5460
5461   /**
5462    * ClutterActor:scale-gravity:
5463    *
5464    * The center point for scaling expressed as a #ClutterGravity
5465    *
5466    * Since: 1.0
5467    */
5468   obj_props[PROP_SCALE_GRAVITY] =
5469     g_param_spec_enum ("scale-gravity",
5470                        P_("Scale Gravity"),
5471                        P_("The center of scaling"),
5472                        CLUTTER_TYPE_GRAVITY,
5473                        CLUTTER_GRAVITY_NONE,
5474                        CLUTTER_PARAM_READWRITE);
5475
5476   /**
5477    * ClutterActor:rotation-angle-x:
5478    *
5479    * The rotation angle on the X axis
5480    *
5481    * Since: 0.6
5482    */
5483   obj_props[PROP_ROTATION_ANGLE_X] =
5484     g_param_spec_double ("rotation-angle-x",
5485                          P_("Rotation Angle X"),
5486                          P_("The rotation angle on the X axis"),
5487                          -G_MAXDOUBLE, G_MAXDOUBLE,
5488                          0.0,
5489                          CLUTTER_PARAM_READWRITE);
5490
5491   /**
5492    * ClutterActor:rotation-angle-y:
5493    *
5494    * The rotation angle on the Y axis
5495    *
5496    * Since: 0.6
5497    */
5498   obj_props[PROP_ROTATION_ANGLE_Y] =
5499     g_param_spec_double ("rotation-angle-y",
5500                          P_("Rotation Angle Y"),
5501                          P_("The rotation angle on the Y axis"),
5502                          -G_MAXDOUBLE, G_MAXDOUBLE,
5503                          0.0,
5504                          CLUTTER_PARAM_READWRITE);
5505
5506   /**
5507    * ClutterActor:rotation-angle-z:
5508    *
5509    * The rotation angle on the Z axis
5510    *
5511    * Since: 0.6
5512    */
5513   obj_props[PROP_ROTATION_ANGLE_Z] =
5514     g_param_spec_double ("rotation-angle-z",
5515                          P_("Rotation Angle Z"),
5516                          P_("The rotation angle on the Z axis"),
5517                          -G_MAXDOUBLE, G_MAXDOUBLE,
5518                          0.0,
5519                          CLUTTER_PARAM_READWRITE);
5520
5521   /**
5522    * ClutterActor:rotation-center-x:
5523    *
5524    * The rotation center on the X axis.
5525    *
5526    * Since: 0.6
5527    */
5528   obj_props[PROP_ROTATION_CENTER_X] =
5529     g_param_spec_boxed ("rotation-center-x",
5530                         P_("Rotation Center X"),
5531                         P_("The rotation center on the X axis"),
5532                         CLUTTER_TYPE_VERTEX,
5533                         CLUTTER_PARAM_READWRITE);
5534
5535   /**
5536    * ClutterActor:rotation-center-y:
5537    *
5538    * The rotation center on the Y axis.
5539    *
5540    * Since: 0.6
5541    */
5542   obj_props[PROP_ROTATION_CENTER_Y] =
5543     g_param_spec_boxed ("rotation-center-y",
5544                         P_("Rotation Center Y"),
5545                         P_("The rotation center on the Y axis"),
5546                         CLUTTER_TYPE_VERTEX,
5547                         CLUTTER_PARAM_READWRITE);
5548
5549   /**
5550    * ClutterActor:rotation-center-z:
5551    *
5552    * The rotation center on the Z axis.
5553    *
5554    * Since: 0.6
5555    */
5556   obj_props[PROP_ROTATION_CENTER_Z] =
5557     g_param_spec_boxed ("rotation-center-z",
5558                         P_("Rotation Center Z"),
5559                         P_("The rotation center on the Z axis"),
5560                         CLUTTER_TYPE_VERTEX,
5561                         CLUTTER_PARAM_READWRITE);
5562
5563   /**
5564    * ClutterActor:rotation-center-z-gravity:
5565    *
5566    * The rotation center on the Z axis expressed as a #ClutterGravity.
5567    *
5568    * Since: 1.0
5569    */
5570   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5571     g_param_spec_enum ("rotation-center-z-gravity",
5572                        P_("Rotation Center Z Gravity"),
5573                        P_("Center point for rotation around the Z axis"),
5574                        CLUTTER_TYPE_GRAVITY,
5575                        CLUTTER_GRAVITY_NONE,
5576                        CLUTTER_PARAM_READWRITE);
5577
5578   /**
5579    * ClutterActor:anchor-x:
5580    *
5581    * The X coordinate of an actor's anchor point, relative to
5582    * the actor coordinate space, in pixels
5583    *
5584    * Since: 0.8
5585    */
5586   obj_props[PROP_ANCHOR_X] =
5587     g_param_spec_float ("anchor-x",
5588                         P_("Anchor X"),
5589                         P_("X coordinate of the anchor point"),
5590                         -G_MAXFLOAT, G_MAXFLOAT,
5591                         0,
5592                         CLUTTER_PARAM_READWRITE);
5593
5594   /**
5595    * ClutterActor:anchor-y:
5596    *
5597    * The Y coordinate of an actor's anchor point, relative to
5598    * the actor coordinate space, in pixels
5599    *
5600    * Since: 0.8
5601    */
5602   obj_props[PROP_ANCHOR_Y] =
5603     g_param_spec_float ("anchor-y",
5604                         P_("Anchor Y"),
5605                         P_("Y coordinate of the anchor point"),
5606                         -G_MAXFLOAT, G_MAXFLOAT,
5607                         0,
5608                         CLUTTER_PARAM_READWRITE);
5609
5610   /**
5611    * ClutterActor:anchor-gravity:
5612    *
5613    * The anchor point expressed as a #ClutterGravity
5614    *
5615    * Since: 1.0
5616    */
5617   obj_props[PROP_ANCHOR_GRAVITY] =
5618     g_param_spec_enum ("anchor-gravity",
5619                        P_("Anchor Gravity"),
5620                        P_("The anchor point as a ClutterGravity"),
5621                        CLUTTER_TYPE_GRAVITY,
5622                        CLUTTER_GRAVITY_NONE,
5623                        CLUTTER_PARAM_READWRITE);
5624
5625   /**
5626    * ClutterActor:show-on-set-parent:
5627    *
5628    * If %TRUE, the actor is automatically shown when parented.
5629    *
5630    * Calling clutter_actor_hide() on an actor which has not been
5631    * parented will set this property to %FALSE as a side effect.
5632    *
5633    * Since: 0.8
5634    */
5635   obj_props[PROP_SHOW_ON_SET_PARENT] =
5636     g_param_spec_boolean ("show-on-set-parent",
5637                           P_("Show on set parent"),
5638                           P_("Whether the actor is shown when parented"),
5639                           TRUE,
5640                           CLUTTER_PARAM_READWRITE);
5641
5642   /**
5643    * ClutterActor:clip-to-allocation:
5644    *
5645    * Whether the clip region should track the allocated area
5646    * of the actor.
5647    *
5648    * This property is ignored if a clip area has been explicitly
5649    * set using clutter_actor_set_clip().
5650    *
5651    * Since: 1.0
5652    */
5653   obj_props[PROP_CLIP_TO_ALLOCATION] =
5654     g_param_spec_boolean ("clip-to-allocation",
5655                           P_("Clip to Allocation"),
5656                           P_("Sets the clip region to track the actor's allocation"),
5657                           FALSE,
5658                           CLUTTER_PARAM_READWRITE);
5659
5660   /**
5661    * ClutterActor:text-direction:
5662    *
5663    * The direction of the text inside a #ClutterActor.
5664    *
5665    * Since: 1.0
5666    */
5667   obj_props[PROP_TEXT_DIRECTION] =
5668     g_param_spec_enum ("text-direction",
5669                        P_("Text Direction"),
5670                        P_("Direction of the text"),
5671                        CLUTTER_TYPE_TEXT_DIRECTION,
5672                        CLUTTER_TEXT_DIRECTION_LTR,
5673                        CLUTTER_PARAM_READWRITE);
5674
5675   /**
5676    * ClutterActor:has-pointer:
5677    *
5678    * Whether the actor contains the pointer of a #ClutterInputDevice
5679    * or not.
5680    *
5681    * Since: 1.2
5682    */
5683   obj_props[PROP_HAS_POINTER] =
5684     g_param_spec_boolean ("has-pointer",
5685                           P_("Has Pointer"),
5686                           P_("Whether the actor contains the pointer of an input device"),
5687                           FALSE,
5688                           CLUTTER_PARAM_READABLE);
5689
5690   /**
5691    * ClutterActor:actions:
5692    *
5693    * Adds a #ClutterAction to the actor
5694    *
5695    * Since: 1.4
5696    */
5697   obj_props[PROP_ACTIONS] =
5698     g_param_spec_object ("actions",
5699                          P_("Actions"),
5700                          P_("Adds an action to the actor"),
5701                          CLUTTER_TYPE_ACTION,
5702                          CLUTTER_PARAM_WRITABLE);
5703
5704   /**
5705    * ClutterActor:constraints:
5706    *
5707    * Adds a #ClutterConstraint to the actor
5708    *
5709    * Since: 1.4
5710    */
5711   obj_props[PROP_CONSTRAINTS] =
5712     g_param_spec_object ("constraints",
5713                          P_("Constraints"),
5714                          P_("Adds a constraint to the actor"),
5715                          CLUTTER_TYPE_CONSTRAINT,
5716                          CLUTTER_PARAM_WRITABLE);
5717
5718   /**
5719    * ClutterActor:effect:
5720    *
5721    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5722    *
5723    * Since: 1.4
5724    */
5725   obj_props[PROP_EFFECT] =
5726     g_param_spec_object ("effect",
5727                          P_("Effect"),
5728                          P_("Add an effect to be applied on the actor"),
5729                          CLUTTER_TYPE_EFFECT,
5730                          CLUTTER_PARAM_WRITABLE);
5731
5732   /**
5733    * ClutterActor:layout-manager:
5734    *
5735    * A delegate object for controlling the layout of the children of
5736    * an actor.
5737    *
5738    * Since: 1.10
5739    */
5740   obj_props[PROP_LAYOUT_MANAGER] =
5741     g_param_spec_object ("layout-manager",
5742                          P_("Layout Manager"),
5743                          P_("The object controlling the layout of an actor's children"),
5744                          CLUTTER_TYPE_LAYOUT_MANAGER,
5745                          CLUTTER_PARAM_READWRITE);
5746
5747
5748   /**
5749    * ClutterActor:x-align:
5750    *
5751    * The alignment of an actor on the X axis, if the actor has been given
5752    * extra space for its allocation.
5753    *
5754    * Since: 1.10
5755    */
5756   obj_props[PROP_X_ALIGN] =
5757     g_param_spec_enum ("x-align",
5758                        P_("X Alignment"),
5759                        P_("The alignment of the actor on the X axis within its allocation"),
5760                        CLUTTER_TYPE_ACTOR_ALIGN,
5761                        CLUTTER_ACTOR_ALIGN_FILL,
5762                        CLUTTER_PARAM_READWRITE);
5763
5764   /**
5765    * ClutterActor:y-align:
5766    *
5767    * The alignment of an actor on the Y axis, if the actor has been given
5768    * extra space for its allocation.
5769    *
5770    * Since: 1.10
5771    */
5772   obj_props[PROP_Y_ALIGN] =
5773     g_param_spec_enum ("y-align",
5774                        P_("Y Alignment"),
5775                        P_("The alignment of the actor on the Y axis within its allocation"),
5776                        CLUTTER_TYPE_ACTOR_ALIGN,
5777                        CLUTTER_ACTOR_ALIGN_FILL,
5778                        CLUTTER_PARAM_READWRITE);
5779
5780   /**
5781    * ClutterActor:margin-top:
5782    *
5783    * The margin (in pixels) from the top of the actor.
5784    *
5785    * This property adds a margin to the actor's preferred size; the margin
5786    * will be automatically taken into account when allocating the actor.
5787    *
5788    * Since: 1.10
5789    */
5790   obj_props[PROP_MARGIN_TOP] =
5791     g_param_spec_float ("margin-top",
5792                         P_("Margin Top"),
5793                         P_("Extra space at the top"),
5794                         0.0, G_MAXFLOAT,
5795                         0.0,
5796                         CLUTTER_PARAM_READWRITE);
5797
5798   /**
5799    * ClutterActor:margin-bottom:
5800    *
5801    * The margin (in pixels) from the bottom of the actor.
5802    *
5803    * This property adds a margin to the actor's preferred size; the margin
5804    * will be automatically taken into account when allocating the actor.
5805    *
5806    * Since: 1.10
5807    */
5808   obj_props[PROP_MARGIN_BOTTOM] =
5809     g_param_spec_float ("margin-bottom",
5810                         P_("Margin Bottom"),
5811                         P_("Extra space at the bottom"),
5812                         0.0, G_MAXFLOAT,
5813                         0.0,
5814                         CLUTTER_PARAM_READWRITE);
5815
5816   /**
5817    * ClutterActor:margin-left:
5818    *
5819    * The margin (in pixels) from the left of the actor.
5820    *
5821    * This property adds a margin to the actor's preferred size; the margin
5822    * will be automatically taken into account when allocating the actor.
5823    *
5824    * Since: 1.10
5825    */
5826   obj_props[PROP_MARGIN_LEFT] =
5827     g_param_spec_float ("margin-left",
5828                         P_("Margin Left"),
5829                         P_("Extra space at the left"),
5830                         0.0, G_MAXFLOAT,
5831                         0.0,
5832                         CLUTTER_PARAM_READWRITE);
5833
5834   /**
5835    * ClutterActor:margin-right:
5836    *
5837    * The margin (in pixels) from the right of the actor.
5838    *
5839    * This property adds a margin to the actor's preferred size; the margin
5840    * will be automatically taken into account when allocating the actor.
5841    *
5842    * Since: 1.10
5843    */
5844   obj_props[PROP_MARGIN_RIGHT] =
5845     g_param_spec_float ("margin-right",
5846                         P_("Margin Right"),
5847                         P_("Extra space at the right"),
5848                         0.0, G_MAXFLOAT,
5849                         0.0,
5850                         CLUTTER_PARAM_READWRITE);
5851
5852   /**
5853    * ClutterActor:background-color-set:
5854    *
5855    * Whether the #ClutterActor:background-color property has been set.
5856    *
5857    * Since: 1.10
5858    */
5859   obj_props[PROP_BACKGROUND_COLOR_SET] =
5860     g_param_spec_boolean ("background-color-set",
5861                           P_("Background Color Set"),
5862                           P_("Whether the background color is set"),
5863                           FALSE,
5864                           CLUTTER_PARAM_READABLE);
5865
5866   /**
5867    * ClutterActor:background-color:
5868    *
5869    * Paints a solid fill of the actor's allocation using the specified
5870    * color.
5871    *
5872    * Since: 1.10
5873    */
5874   obj_props[PROP_BACKGROUND_COLOR] =
5875     clutter_param_spec_color ("background-color",
5876                               P_("Background color"),
5877                               P_("The actor's background color"),
5878                               CLUTTER_COLOR_Transparent,
5879                               CLUTTER_PARAM_READWRITE);
5880
5881   /**
5882    * ClutterActor:first-child:
5883    *
5884    * The actor's first child.
5885    *
5886    * Since: 1.10
5887    */
5888   obj_props[PROP_FIRST_CHILD] =
5889     g_param_spec_object ("first-child",
5890                          P_("First Child"),
5891                          P_("The actor's first child"),
5892                          CLUTTER_TYPE_ACTOR,
5893                          CLUTTER_PARAM_READABLE);
5894
5895   /**
5896    * ClutterActor:last-child:
5897    *
5898    * The actor's last child.
5899    *
5900    * Since: 1.10
5901    */
5902   obj_props[PROP_LAST_CHILD] =
5903     g_param_spec_object ("last-child",
5904                          P_("Last Child"),
5905                          P_("The actor's last child"),
5906                          CLUTTER_TYPE_ACTOR,
5907                          CLUTTER_PARAM_READABLE);
5908
5909   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
5910
5911   /**
5912    * ClutterActor::destroy:
5913    * @actor: the #ClutterActor which emitted the signal
5914    *
5915    * The ::destroy signal notifies that all references held on the
5916    * actor which emitted it should be released.
5917    *
5918    * The ::destroy signal should be used by all holders of a reference
5919    * on @actor.
5920    *
5921    * This signal might result in the finalization of the #ClutterActor
5922    * if all references are released.
5923    *
5924    * Composite actors and actors implementing the #ClutterContainer
5925    * interface should override the default implementation of the
5926    * class handler of this signal and call clutter_actor_destroy() on
5927    * their children. When overriding the default class handler, it is
5928    * required to chain up to the parent's implementation.
5929    *
5930    * Since: 0.2
5931    */
5932   actor_signals[DESTROY] =
5933     g_signal_new (I_("destroy"),
5934                   G_TYPE_FROM_CLASS (object_class),
5935                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
5936                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
5937                   NULL, NULL,
5938                   _clutter_marshal_VOID__VOID,
5939                   G_TYPE_NONE, 0);
5940   /**
5941    * ClutterActor::show:
5942    * @actor: the object which received the signal
5943    *
5944    * The ::show signal is emitted when an actor is visible and
5945    * rendered on the stage.
5946    *
5947    * Since: 0.2
5948    */
5949   actor_signals[SHOW] =
5950     g_signal_new (I_("show"),
5951                   G_TYPE_FROM_CLASS (object_class),
5952                   G_SIGNAL_RUN_FIRST,
5953                   G_STRUCT_OFFSET (ClutterActorClass, show),
5954                   NULL, NULL,
5955                   _clutter_marshal_VOID__VOID,
5956                   G_TYPE_NONE, 0);
5957   /**
5958    * ClutterActor::hide:
5959    * @actor: the object which received the signal
5960    *
5961    * The ::hide signal is emitted when an actor is no longer rendered
5962    * on the stage.
5963    *
5964    * Since: 0.2
5965    */
5966   actor_signals[HIDE] =
5967     g_signal_new (I_("hide"),
5968                   G_TYPE_FROM_CLASS (object_class),
5969                   G_SIGNAL_RUN_FIRST,
5970                   G_STRUCT_OFFSET (ClutterActorClass, hide),
5971                   NULL, NULL,
5972                   _clutter_marshal_VOID__VOID,
5973                   G_TYPE_NONE, 0);
5974   /**
5975    * ClutterActor::parent-set:
5976    * @actor: the object which received the signal
5977    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
5978    *
5979    * This signal is emitted when the parent of the actor changes.
5980    *
5981    * Since: 0.2
5982    */
5983   actor_signals[PARENT_SET] =
5984     g_signal_new (I_("parent-set"),
5985                   G_TYPE_FROM_CLASS (object_class),
5986                   G_SIGNAL_RUN_LAST,
5987                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
5988                   NULL, NULL,
5989                   _clutter_marshal_VOID__OBJECT,
5990                   G_TYPE_NONE, 1,
5991                   CLUTTER_TYPE_ACTOR);
5992
5993   /**
5994    * ClutterActor::queue-redraw:
5995    * @actor: the actor we're bubbling the redraw request through
5996    * @origin: the actor which initiated the redraw request
5997    *
5998    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
5999    * is called on @origin.
6000    *
6001    * The default implementation for #ClutterActor chains up to the
6002    * parent actor and queues a redraw on the parent, thus "bubbling"
6003    * the redraw queue up through the actor graph. The default
6004    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6005    * in a main loop idle handler.
6006    *
6007    * Note that the @origin actor may be the stage, or a container; it
6008    * does not have to be a leaf node in the actor graph.
6009    *
6010    * Toolkits embedding a #ClutterStage which require a redraw and
6011    * relayout cycle can stop the emission of this signal using the
6012    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6013    * themselves, like:
6014    *
6015    * |[
6016    *   static void
6017    *   on_redraw_complete (gpointer data)
6018    *   {
6019    *     ClutterStage *stage = data;
6020    *
6021    *     /&ast; execute the Clutter drawing pipeline &ast;/
6022    *     clutter_stage_ensure_redraw (stage);
6023    *   }
6024    *
6025    *   static void
6026    *   on_stage_queue_redraw (ClutterStage *stage)
6027    *   {
6028    *     /&ast; this prevents the default handler to run &ast;/
6029    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6030    *
6031    *     /&ast; queue a redraw with the host toolkit and call
6032    *      &ast; a function when the redraw has been completed
6033    *      &ast;/
6034    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6035    *   }
6036    * ]|
6037    *
6038    * <note><para>This signal is emitted before the Clutter paint
6039    * pipeline is executed. If you want to know when the pipeline has
6040    * been completed you should connect to the ::paint signal on the
6041    * Stage with g_signal_connect_after().</para></note>
6042    *
6043    * Since: 1.0
6044    */
6045   actor_signals[QUEUE_REDRAW] =
6046     g_signal_new (I_("queue-redraw"),
6047                   G_TYPE_FROM_CLASS (object_class),
6048                   G_SIGNAL_RUN_LAST |
6049                   G_SIGNAL_NO_RECURSE |
6050                   G_SIGNAL_NO_HOOKS,
6051                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6052                   NULL, NULL,
6053                   _clutter_marshal_VOID__OBJECT,
6054                   G_TYPE_NONE, 1,
6055                   CLUTTER_TYPE_ACTOR);
6056
6057   /**
6058    * ClutterActor::queue-relayout
6059    * @actor: the actor being queued for relayout
6060    *
6061    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6062    * is called on an actor.
6063    *
6064    * The default implementation for #ClutterActor chains up to the
6065    * parent actor and queues a relayout on the parent, thus "bubbling"
6066    * the relayout queue up through the actor graph.
6067    *
6068    * The main purpose of this signal is to allow relayout to be propagated
6069    * properly in the procense of #ClutterClone actors. Applications will
6070    * not normally need to connect to this signal.
6071    *
6072    * Since: 1.2
6073    */
6074   actor_signals[QUEUE_RELAYOUT] =
6075     g_signal_new (I_("queue-relayout"),
6076                   G_TYPE_FROM_CLASS (object_class),
6077                   G_SIGNAL_RUN_LAST |
6078                   G_SIGNAL_NO_RECURSE |
6079                   G_SIGNAL_NO_HOOKS,
6080                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6081                   NULL, NULL,
6082                   _clutter_marshal_VOID__VOID,
6083                   G_TYPE_NONE, 0);
6084
6085   /**
6086    * ClutterActor::event:
6087    * @actor: the actor which received the event
6088    * @event: a #ClutterEvent
6089    *
6090    * The ::event signal is emitted each time an event is received
6091    * by the @actor. This signal will be emitted on every actor,
6092    * following the hierarchy chain, until it reaches the top-level
6093    * container (the #ClutterStage).
6094    *
6095    * Return value: %TRUE if the event has been handled by the actor,
6096    *   or %FALSE to continue the emission.
6097    *
6098    * Since: 0.6
6099    */
6100   actor_signals[EVENT] =
6101     g_signal_new (I_("event"),
6102                   G_TYPE_FROM_CLASS (object_class),
6103                   G_SIGNAL_RUN_LAST,
6104                   G_STRUCT_OFFSET (ClutterActorClass, event),
6105                   _clutter_boolean_handled_accumulator, NULL,
6106                   _clutter_marshal_BOOLEAN__BOXED,
6107                   G_TYPE_BOOLEAN, 1,
6108                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6109   /**
6110    * ClutterActor::button-press-event:
6111    * @actor: the actor which received the event
6112    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6113    *
6114    * The ::button-press-event signal is emitted each time a mouse button
6115    * is pressed on @actor.
6116    *
6117    * Return value: %TRUE if the event has been handled by the actor,
6118    *   or %FALSE to continue the emission.
6119    *
6120    * Since: 0.6
6121    */
6122   actor_signals[BUTTON_PRESS_EVENT] =
6123     g_signal_new (I_("button-press-event"),
6124                   G_TYPE_FROM_CLASS (object_class),
6125                   G_SIGNAL_RUN_LAST,
6126                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6127                   _clutter_boolean_handled_accumulator, NULL,
6128                   _clutter_marshal_BOOLEAN__BOXED,
6129                   G_TYPE_BOOLEAN, 1,
6130                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6131   /**
6132    * ClutterActor::button-release-event:
6133    * @actor: the actor which received the event
6134    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6135    *
6136    * The ::button-release-event signal is emitted each time a mouse button
6137    * is released on @actor.
6138    *
6139    * Return value: %TRUE if the event has been handled by the actor,
6140    *   or %FALSE to continue the emission.
6141    *
6142    * Since: 0.6
6143    */
6144   actor_signals[BUTTON_RELEASE_EVENT] =
6145     g_signal_new (I_("button-release-event"),
6146                   G_TYPE_FROM_CLASS (object_class),
6147                   G_SIGNAL_RUN_LAST,
6148                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6149                   _clutter_boolean_handled_accumulator, NULL,
6150                   _clutter_marshal_BOOLEAN__BOXED,
6151                   G_TYPE_BOOLEAN, 1,
6152                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6153   /**
6154    * ClutterActor::scroll-event:
6155    * @actor: the actor which received the event
6156    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6157    *
6158    * The ::scroll-event signal is emitted each time the mouse is
6159    * scrolled on @actor
6160    *
6161    * Return value: %TRUE if the event has been handled by the actor,
6162    *   or %FALSE to continue the emission.
6163    *
6164    * Since: 0.6
6165    */
6166   actor_signals[SCROLL_EVENT] =
6167     g_signal_new (I_("scroll-event"),
6168                   G_TYPE_FROM_CLASS (object_class),
6169                   G_SIGNAL_RUN_LAST,
6170                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6171                   _clutter_boolean_handled_accumulator, NULL,
6172                   _clutter_marshal_BOOLEAN__BOXED,
6173                   G_TYPE_BOOLEAN, 1,
6174                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6175   /**
6176    * ClutterActor::key-press-event:
6177    * @actor: the actor which received the event
6178    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6179    *
6180    * The ::key-press-event signal is emitted each time a keyboard button
6181    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6182    *
6183    * Return value: %TRUE if the event has been handled by the actor,
6184    *   or %FALSE to continue the emission.
6185    *
6186    * Since: 0.6
6187    */
6188   actor_signals[KEY_PRESS_EVENT] =
6189     g_signal_new (I_("key-press-event"),
6190                   G_TYPE_FROM_CLASS (object_class),
6191                   G_SIGNAL_RUN_LAST,
6192                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6193                   _clutter_boolean_handled_accumulator, NULL,
6194                   _clutter_marshal_BOOLEAN__BOXED,
6195                   G_TYPE_BOOLEAN, 1,
6196                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6197   /**
6198    * ClutterActor::key-release-event:
6199    * @actor: the actor which received the event
6200    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6201    *
6202    * The ::key-release-event signal is emitted each time a keyboard button
6203    * is released while @actor has key focus (see
6204    * clutter_stage_set_key_focus()).
6205    *
6206    * Return value: %TRUE if the event has been handled by the actor,
6207    *   or %FALSE to continue the emission.
6208    *
6209    * Since: 0.6
6210    */
6211   actor_signals[KEY_RELEASE_EVENT] =
6212     g_signal_new (I_("key-release-event"),
6213                   G_TYPE_FROM_CLASS (object_class),
6214                   G_SIGNAL_RUN_LAST,
6215                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6216                   _clutter_boolean_handled_accumulator, NULL,
6217                   _clutter_marshal_BOOLEAN__BOXED,
6218                   G_TYPE_BOOLEAN, 1,
6219                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6220   /**
6221    * ClutterActor::motion-event:
6222    * @actor: the actor which received the event
6223    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6224    *
6225    * The ::motion-event signal is emitted each time the mouse pointer is
6226    * moved over @actor.
6227    *
6228    * Return value: %TRUE if the event has been handled by the actor,
6229    *   or %FALSE to continue the emission.
6230    *
6231    * Since: 0.6
6232    */
6233   actor_signals[MOTION_EVENT] =
6234     g_signal_new (I_("motion-event"),
6235                   G_TYPE_FROM_CLASS (object_class),
6236                   G_SIGNAL_RUN_LAST,
6237                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6238                   _clutter_boolean_handled_accumulator, NULL,
6239                   _clutter_marshal_BOOLEAN__BOXED,
6240                   G_TYPE_BOOLEAN, 1,
6241                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6242
6243   /**
6244    * ClutterActor::key-focus-in:
6245    * @actor: the actor which now has key focus
6246    *
6247    * The ::key-focus-in signal is emitted when @actor receives key focus.
6248    *
6249    * Since: 0.6
6250    */
6251   actor_signals[KEY_FOCUS_IN] =
6252     g_signal_new (I_("key-focus-in"),
6253                   G_TYPE_FROM_CLASS (object_class),
6254                   G_SIGNAL_RUN_LAST,
6255                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6256                   NULL, NULL,
6257                   _clutter_marshal_VOID__VOID,
6258                   G_TYPE_NONE, 0);
6259
6260   /**
6261    * ClutterActor::key-focus-out:
6262    * @actor: the actor which now has key focus
6263    *
6264    * The ::key-focus-out signal is emitted when @actor loses key focus.
6265    *
6266    * Since: 0.6
6267    */
6268   actor_signals[KEY_FOCUS_OUT] =
6269     g_signal_new (I_("key-focus-out"),
6270                   G_TYPE_FROM_CLASS (object_class),
6271                   G_SIGNAL_RUN_LAST,
6272                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6273                   NULL, NULL,
6274                   _clutter_marshal_VOID__VOID,
6275                   G_TYPE_NONE, 0);
6276
6277   /**
6278    * ClutterActor::enter-event:
6279    * @actor: the actor which the pointer has entered.
6280    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6281    *
6282    * The ::enter-event signal is emitted when the pointer enters the @actor
6283    *
6284    * Return value: %TRUE if the event has been handled by the actor,
6285    *   or %FALSE to continue the emission.
6286    *
6287    * Since: 0.6
6288    */
6289   actor_signals[ENTER_EVENT] =
6290     g_signal_new (I_("enter-event"),
6291                   G_TYPE_FROM_CLASS (object_class),
6292                   G_SIGNAL_RUN_LAST,
6293                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6294                   _clutter_boolean_handled_accumulator, NULL,
6295                   _clutter_marshal_BOOLEAN__BOXED,
6296                   G_TYPE_BOOLEAN, 1,
6297                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6298
6299   /**
6300    * ClutterActor::leave-event:
6301    * @actor: the actor which the pointer has left
6302    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6303    *
6304    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6305    *
6306    * Return value: %TRUE if the event has been handled by the actor,
6307    *   or %FALSE to continue the emission.
6308    *
6309    * Since: 0.6
6310    */
6311   actor_signals[LEAVE_EVENT] =
6312     g_signal_new (I_("leave-event"),
6313                   G_TYPE_FROM_CLASS (object_class),
6314                   G_SIGNAL_RUN_LAST,
6315                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6316                   _clutter_boolean_handled_accumulator, NULL,
6317                   _clutter_marshal_BOOLEAN__BOXED,
6318                   G_TYPE_BOOLEAN, 1,
6319                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6320
6321   /**
6322    * ClutterActor::captured-event:
6323    * @actor: the actor which received the signal
6324    * @event: a #ClutterEvent
6325    *
6326    * The ::captured-event signal is emitted when an event is captured
6327    * by Clutter. This signal will be emitted starting from the top-level
6328    * container (the #ClutterStage) to the actor which received the event
6329    * going down the hierarchy. This signal can be used to intercept every
6330    * event before the specialized events (like
6331    * ClutterActor::button-press-event or ::key-released-event) are
6332    * emitted.
6333    *
6334    * Return value: %TRUE if the event has been handled by the actor,
6335    *   or %FALSE to continue the emission.
6336    *
6337    * Since: 0.6
6338    */
6339   actor_signals[CAPTURED_EVENT] =
6340     g_signal_new (I_("captured-event"),
6341                   G_TYPE_FROM_CLASS (object_class),
6342                   G_SIGNAL_RUN_LAST,
6343                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6344                   _clutter_boolean_handled_accumulator, NULL,
6345                   _clutter_marshal_BOOLEAN__BOXED,
6346                   G_TYPE_BOOLEAN, 1,
6347                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6348
6349   /**
6350    * ClutterActor::paint:
6351    * @actor: the #ClutterActor that received the signal
6352    *
6353    * The ::paint signal is emitted each time an actor is being painted.
6354    *
6355    * Subclasses of #ClutterActor should override the class signal handler
6356    * and paint themselves in that function.
6357    *
6358    * It is possible to connect a handler to the ::paint signal in order
6359    * to set up some custom aspect of a paint.
6360    *
6361    * Since: 0.8
6362    */
6363   actor_signals[PAINT] =
6364     g_signal_new (I_("paint"),
6365                   G_TYPE_FROM_CLASS (object_class),
6366                   G_SIGNAL_RUN_LAST |
6367                   G_SIGNAL_NO_RECURSE |
6368                   G_SIGNAL_NO_HOOKS,
6369                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6370                   NULL, NULL,
6371                   _clutter_marshal_VOID__VOID,
6372                   G_TYPE_NONE, 0);
6373   /**
6374    * ClutterActor::realize:
6375    * @actor: the #ClutterActor that received the signal
6376    *
6377    * The ::realize signal is emitted each time an actor is being
6378    * realized.
6379    *
6380    * Since: 0.8
6381    */
6382   actor_signals[REALIZE] =
6383     g_signal_new (I_("realize"),
6384                   G_TYPE_FROM_CLASS (object_class),
6385                   G_SIGNAL_RUN_LAST,
6386                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6387                   NULL, NULL,
6388                   _clutter_marshal_VOID__VOID,
6389                   G_TYPE_NONE, 0);
6390   /**
6391    * ClutterActor::unrealize:
6392    * @actor: the #ClutterActor that received the signal
6393    *
6394    * The ::unrealize signal is emitted each time an actor is being
6395    * unrealized.
6396    *
6397    * Since: 0.8
6398    */
6399   actor_signals[UNREALIZE] =
6400     g_signal_new (I_("unrealize"),
6401                   G_TYPE_FROM_CLASS (object_class),
6402                   G_SIGNAL_RUN_LAST,
6403                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6404                   NULL, NULL,
6405                   _clutter_marshal_VOID__VOID,
6406                   G_TYPE_NONE, 0);
6407
6408   /**
6409    * ClutterActor::pick:
6410    * @actor: the #ClutterActor that received the signal
6411    * @color: the #ClutterColor to be used when picking
6412    *
6413    * The ::pick signal is emitted each time an actor is being painted
6414    * in "pick mode". The pick mode is used to identify the actor during
6415    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6416    * The actor should paint its shape using the passed @pick_color.
6417    *
6418    * Subclasses of #ClutterActor should override the class signal handler
6419    * and paint themselves in that function.
6420    *
6421    * It is possible to connect a handler to the ::pick signal in order
6422    * to set up some custom aspect of a paint in pick mode.
6423    *
6424    * Since: 1.0
6425    */
6426   actor_signals[PICK] =
6427     g_signal_new (I_("pick"),
6428                   G_TYPE_FROM_CLASS (object_class),
6429                   G_SIGNAL_RUN_LAST,
6430                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6431                   NULL, NULL,
6432                   _clutter_marshal_VOID__BOXED,
6433                   G_TYPE_NONE, 1,
6434                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6435
6436   /**
6437    * ClutterActor::allocation-changed:
6438    * @actor: the #ClutterActor that emitted the signal
6439    * @box: a #ClutterActorBox with the new allocation
6440    * @flags: #ClutterAllocationFlags for the allocation
6441    *
6442    * The ::allocation-changed signal is emitted when the
6443    * #ClutterActor:allocation property changes. Usually, application
6444    * code should just use the notifications for the :allocation property
6445    * but if you want to track the allocation flags as well, for instance
6446    * to know whether the absolute origin of @actor changed, then you might
6447    * want use this signal instead.
6448    *
6449    * Since: 1.0
6450    */
6451   actor_signals[ALLOCATION_CHANGED] =
6452     g_signal_new (I_("allocation-changed"),
6453                   G_TYPE_FROM_CLASS (object_class),
6454                   G_SIGNAL_RUN_LAST,
6455                   0,
6456                   NULL, NULL,
6457                   _clutter_marshal_VOID__BOXED_FLAGS,
6458                   G_TYPE_NONE, 2,
6459                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6460                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6461 }
6462
6463 static void
6464 clutter_actor_init (ClutterActor *self)
6465 {
6466   ClutterActorPrivate *priv;
6467
6468   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6469
6470   priv->id = _clutter_context_acquire_id (self);
6471   priv->pick_id = -1;
6472
6473   priv->opacity = 0xff;
6474   priv->show_on_set_parent = TRUE;
6475
6476   priv->needs_width_request = TRUE;
6477   priv->needs_height_request = TRUE;
6478   priv->needs_allocation = TRUE;
6479
6480   priv->cached_width_age = 1;
6481   priv->cached_height_age = 1;
6482
6483   priv->opacity_override = -1;
6484   priv->enable_model_view_transform = TRUE;
6485
6486   /* Initialize an empty paint volume to start with */
6487   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6488   priv->last_paint_volume_valid = TRUE;
6489
6490   priv->transform_valid = FALSE;
6491 }
6492
6493 /**
6494  * clutter_actor_new:
6495  *
6496  * Creates a new #ClutterActor.
6497  *
6498  * A newly created actor has a floating reference, which will be sunk
6499  * when it is added to another actor.
6500  *
6501  * Return value: (transfer full): the newly created #ClutterActor
6502  *
6503  * Since: 1.10
6504  */
6505 ClutterActor *
6506 clutter_actor_new (void)
6507 {
6508   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6509 }
6510
6511 /**
6512  * clutter_actor_destroy:
6513  * @self: a #ClutterActor
6514  *
6515  * Destroys an actor.  When an actor is destroyed, it will break any
6516  * references it holds to other objects.  If the actor is inside a
6517  * container, the actor will be removed.
6518  *
6519  * When you destroy a container, its children will be destroyed as well.
6520  *
6521  * Note: you cannot destroy the #ClutterStage returned by
6522  * clutter_stage_get_default().
6523  */
6524 void
6525 clutter_actor_destroy (ClutterActor *self)
6526 {
6527   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6528
6529   g_object_ref (self);
6530
6531   /* avoid recursion while destroying */
6532   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6533     {
6534       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6535
6536       g_object_run_dispose (G_OBJECT (self));
6537
6538       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6539     }
6540
6541   g_object_unref (self);
6542 }
6543
6544 void
6545 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6546                                     ClutterPaintVolume *clip)
6547 {
6548   ClutterActorPrivate *priv = self->priv;
6549   ClutterPaintVolume *pv;
6550   gboolean clipped;
6551
6552   /* Remove queue entry early in the process, otherwise a new
6553      queue_redraw() during signal handling could put back this
6554      object in the stage redraw list (but the entry is freed as
6555      soon as we return from this function, causing a segfault
6556      later)
6557   */
6558   priv->queue_redraw_entry = NULL;
6559
6560   /* If we've been explicitly passed a clip volume then there's
6561    * nothing more to calculate, but otherwise the only thing we know
6562    * is that the change is constrained to the given actor.
6563    *
6564    * The idea is that if we know the paint volume for where the actor
6565    * was last drawn (in eye coordinates) and we also have the paint
6566    * volume for where it will be drawn next (in actor coordinates)
6567    * then if we queue a redraw for both these volumes that will cover
6568    * everything that needs to be redrawn to clear the old view and
6569    * show the latest view of the actor.
6570    *
6571    * Don't clip this redraw if we don't know what position we had for
6572    * the previous redraw since we don't know where to set the clip so
6573    * it will clear the actor as it is currently.
6574    */
6575   if (clip)
6576     {
6577       _clutter_actor_set_queue_redraw_clip (self, clip);
6578       clipped = TRUE;
6579     }
6580   else if (G_LIKELY (priv->last_paint_volume_valid))
6581     {
6582       pv = _clutter_actor_get_paint_volume_mutable (self);
6583       if (pv)
6584         {
6585           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6586
6587           /* make sure we redraw the actors old position... */
6588           _clutter_actor_set_queue_redraw_clip (stage,
6589                                                 &priv->last_paint_volume);
6590           _clutter_actor_signal_queue_redraw (stage, stage);
6591           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6592
6593           /* XXX: Ideally the redraw signal would take a clip volume
6594            * argument, but that would be an ABI break. Until we can
6595            * break the ABI we pass the argument out-of-band
6596            */
6597
6598           /* setup the clip for the actors new position... */
6599           _clutter_actor_set_queue_redraw_clip (self, pv);
6600           clipped = TRUE;
6601         }
6602       else
6603         clipped = FALSE;
6604     }
6605   else
6606     clipped = FALSE;
6607
6608   _clutter_actor_signal_queue_redraw (self, self);
6609
6610   /* Just in case anyone is manually firing redraw signals without
6611    * using the public queue_redraw() API we are careful to ensure that
6612    * our out-of-band clip member is cleared before returning...
6613    *
6614    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6615    */
6616   if (G_LIKELY (clipped))
6617     _clutter_actor_set_queue_redraw_clip (self, NULL);
6618 }
6619
6620 static void
6621 _clutter_actor_get_allocation_clip (ClutterActor *self,
6622                                     ClutterActorBox *clip)
6623 {
6624   ClutterActorBox allocation;
6625
6626   /* XXX: we don't care if we get an out of date allocation here
6627    * because clutter_actor_queue_redraw_with_clip knows to ignore
6628    * the clip if the actor's allocation is invalid.
6629    *
6630    * This is noted because clutter_actor_get_allocation_box does some
6631    * unnecessary work to support buggy code with a comment suggesting
6632    * that it could be changed later which would be good for this use
6633    * case!
6634    */
6635   clutter_actor_get_allocation_box (self, &allocation);
6636
6637   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6638    * actor's own coordinate space but the allocation is in parent
6639    * coordinates */
6640   clip->x1 = 0;
6641   clip->y1 = 0;
6642   clip->x2 = allocation.x2 - allocation.x1;
6643   clip->y2 = allocation.y2 - allocation.y1;
6644 }
6645
6646 void
6647 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6648                                   ClutterRedrawFlags  flags,
6649                                   ClutterPaintVolume *volume,
6650                                   ClutterEffect      *effect)
6651 {
6652   ClutterActorPrivate *priv = self->priv;
6653   ClutterPaintVolume allocation_pv;
6654   ClutterPaintVolume *pv;
6655   gboolean should_free_pv;
6656   ClutterActor *stage;
6657
6658   /* Here's an outline of the actor queue redraw mechanism:
6659    *
6660    * The process starts in one of the following two functions which
6661    * are wrappers for this function:
6662    * clutter_actor_queue_redraw
6663    * _clutter_actor_queue_redraw_with_clip
6664    *
6665    * additionally, an effect can queue a redraw by wrapping this
6666    * function in clutter_effect_queue_rerun
6667    *
6668    * This functions queues an entry in a list associated with the
6669    * stage which is a list of actors that queued a redraw while
6670    * updating the timelines, performing layouting and processing other
6671    * mainloop sources before the next paint starts.
6672    *
6673    * We aim to minimize the processing done at this point because
6674    * there is a good chance other events will happen while updating
6675    * the scenegraph that would invalidate any expensive work we might
6676    * otherwise try to do here. For example we don't try and resolve
6677    * the screen space bounding box of an actor at this stage so as to
6678    * minimize how much of the screen redraw because it's possible
6679    * something else will happen which will force a full redraw anyway.
6680    *
6681    * When all updates are complete and we come to paint the stage then
6682    * we iterate this list and actually emit the "queue-redraw" signals
6683    * for each of the listed actors which will bubble up to the stage
6684    * for each actor and at that point we will transform the actors
6685    * paint volume into screen coordinates to determine the clip region
6686    * for what needs to be redrawn in the next paint.
6687    *
6688    * Besides minimizing redundant work another reason for this
6689    * deferred design is that it's more likely we will be able to
6690    * determine the paint volume of an actor once we've finished
6691    * updating the scenegraph because its allocation should be up to
6692    * date. NB: If we can't determine an actors paint volume then we
6693    * can't automatically queue a clipped redraw which can make a big
6694    * difference to performance.
6695    *
6696    * So the control flow goes like this:
6697    * One of clutter_actor_queue_redraw,
6698    *        _clutter_actor_queue_redraw_with_clip
6699    *     or clutter_effect_queue_rerun
6700    *
6701    * then control moves to:
6702    *   _clutter_stage_queue_actor_redraw
6703    *
6704    * later during _clutter_stage_do_update, once relayouting is done
6705    * and the scenegraph has been updated we will call:
6706    * _clutter_stage_finish_queue_redraws
6707    *
6708    * _clutter_stage_finish_queue_redraws will call
6709    * _clutter_actor_finish_queue_redraw for each listed actor.
6710    * Note: actors *are* allowed to queue further redraws during this
6711    * process (considering clone actors or texture_new_from_actor which
6712    * respond to their source queueing a redraw by queuing a redraw
6713    * themselves). We repeat the process until the list is empty.
6714    *
6715    * This will result in the "queue-redraw" signal being fired for
6716    * each actor which will pass control to the default signal handler:
6717    * clutter_actor_real_queue_redraw
6718    *
6719    * This will bubble up to the stages handler:
6720    * clutter_stage_real_queue_redraw
6721    *
6722    * clutter_stage_real_queue_redraw will transform the actors paint
6723    * volume into screen space and add it as a clip region for the next
6724    * paint.
6725    */
6726
6727   /* ignore queueing a redraw for actors being destroyed */
6728   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6729     return;
6730
6731   stage = _clutter_actor_get_stage_internal (self);
6732
6733   /* Ignore queueing a redraw for actors not descended from a stage */
6734   if (stage == NULL)
6735     return;
6736
6737   /* ignore queueing a redraw on stages that are being destroyed */
6738   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6739     return;
6740
6741   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6742     {
6743       ClutterActorBox allocation_clip;
6744       ClutterVertex origin;
6745
6746       /* If the actor doesn't have a valid allocation then we will
6747        * queue a full stage redraw. */
6748       if (priv->needs_allocation)
6749         {
6750           /* NB: NULL denotes an undefined clip which will result in a
6751            * full redraw... */
6752           _clutter_actor_set_queue_redraw_clip (self, NULL);
6753           _clutter_actor_signal_queue_redraw (self, self);
6754           return;
6755         }
6756
6757       _clutter_paint_volume_init_static (&allocation_pv, self);
6758       pv = &allocation_pv;
6759
6760       _clutter_actor_get_allocation_clip (self, &allocation_clip);
6761
6762       origin.x = allocation_clip.x1;
6763       origin.y = allocation_clip.y1;
6764       origin.z = 0;
6765       clutter_paint_volume_set_origin (pv, &origin);
6766       clutter_paint_volume_set_width (pv,
6767                                       allocation_clip.x2 - allocation_clip.x1);
6768       clutter_paint_volume_set_height (pv,
6769                                        allocation_clip.y2 -
6770                                        allocation_clip.y1);
6771       should_free_pv = TRUE;
6772     }
6773   else
6774     {
6775       pv = volume;
6776       should_free_pv = FALSE;
6777     }
6778
6779   self->priv->queue_redraw_entry =
6780     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6781                                        priv->queue_redraw_entry,
6782                                        self,
6783                                        pv);
6784
6785   if (should_free_pv)
6786     clutter_paint_volume_free (pv);
6787
6788   /* If this is the first redraw queued then we can directly use the
6789      effect parameter */
6790   if (!priv->is_dirty)
6791     priv->effect_to_redraw = effect;
6792   /* Otherwise we need to merge it with the existing effect parameter */
6793   else if (effect != NULL)
6794     {
6795       /* If there's already an effect then we need to use whichever is
6796          later in the chain of actors. Otherwise a full redraw has
6797          already been queued on the actor so we need to ignore the
6798          effect parameter */
6799       if (priv->effect_to_redraw != NULL)
6800         {
6801           if (priv->effects == NULL)
6802             g_warning ("Redraw queued with an effect that is "
6803                        "not applied to the actor");
6804           else
6805             {
6806               const GList *l;
6807
6808               for (l = _clutter_meta_group_peek_metas (priv->effects);
6809                    l != NULL;
6810                    l = l->next)
6811                 {
6812                   if (l->data == priv->effect_to_redraw ||
6813                       l->data == effect)
6814                     priv->effect_to_redraw = l->data;
6815                 }
6816             }
6817         }
6818     }
6819   else
6820     {
6821       /* If no effect is specified then we need to redraw the whole
6822          actor */
6823       priv->effect_to_redraw = NULL;
6824     }
6825
6826   priv->is_dirty = TRUE;
6827 }
6828
6829 /**
6830  * clutter_actor_queue_redraw:
6831  * @self: A #ClutterActor
6832  *
6833  * Queues up a redraw of an actor and any children. The redraw occurs
6834  * once the main loop becomes idle (after the current batch of events
6835  * has been processed, roughly).
6836  *
6837  * Applications rarely need to call this, as redraws are handled
6838  * automatically by modification functions.
6839  *
6840  * This function will not do anything if @self is not visible, or
6841  * if the actor is inside an invisible part of the scenegraph.
6842  *
6843  * Also be aware that painting is a NOP for actors with an opacity of
6844  * 0
6845  *
6846  * When you are implementing a custom actor you must queue a redraw
6847  * whenever some private state changes that will affect painting or
6848  * picking of your actor.
6849  */
6850 void
6851 clutter_actor_queue_redraw (ClutterActor *self)
6852 {
6853   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6854
6855   _clutter_actor_queue_redraw_full (self,
6856                                     0, /* flags */
6857                                     NULL, /* clip volume */
6858                                     NULL /* effect */);
6859 }
6860
6861 /*< private >
6862  * _clutter_actor_queue_redraw_with_clip:
6863  * @self: A #ClutterActor
6864  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
6865  *   this queue redraw.
6866  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
6867  *   redrawn or %NULL if you are just using a @flag to state your
6868  *   desired clipping.
6869  *
6870  * Queues up a clipped redraw of an actor and any children. The redraw
6871  * occurs once the main loop becomes idle (after the current batch of
6872  * events has been processed, roughly).
6873  *
6874  * If no flags are given the clip volume is defined by @volume
6875  * specified in actor coordinates and tells Clutter that only content
6876  * within this volume has been changed so Clutter can optionally
6877  * optimize the redraw.
6878  *
6879  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
6880  * should be %NULL and this tells Clutter to use the actor's current
6881  * allocation as a clip box. This flag can only be used for 2D actors,
6882  * because any actor with depth may be projected outside its
6883  * allocation.
6884  *
6885  * Applications rarely need to call this, as redraws are handled
6886  * automatically by modification functions.
6887  *
6888  * This function will not do anything if @self is not visible, or if
6889  * the actor is inside an invisible part of the scenegraph.
6890  *
6891  * Also be aware that painting is a NOP for actors with an opacity of
6892  * 0
6893  *
6894  * When you are implementing a custom actor you must queue a redraw
6895  * whenever some private state changes that will affect painting or
6896  * picking of your actor.
6897  */
6898 void
6899 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
6900                                        ClutterRedrawFlags  flags,
6901                                        ClutterPaintVolume *volume)
6902 {
6903   _clutter_actor_queue_redraw_full (self,
6904                                     flags, /* flags */
6905                                     volume, /* clip volume */
6906                                     NULL /* effect */);
6907 }
6908
6909 static void
6910 _clutter_actor_queue_only_relayout (ClutterActor *self)
6911 {
6912   ClutterActorPrivate *priv = self->priv;
6913
6914   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6915     return;
6916
6917   if (priv->needs_width_request &&
6918       priv->needs_height_request &&
6919       priv->needs_allocation)
6920     return; /* save some cpu cycles */
6921
6922 #if CLUTTER_ENABLE_DEBUG
6923   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
6924     {
6925       g_warning ("The actor '%s' is currently inside an allocation "
6926                  "cycle; calling clutter_actor_queue_relayout() is "
6927                  "not recommended",
6928                  _clutter_actor_get_debug_name (self));
6929     }
6930 #endif /* CLUTTER_ENABLE_DEBUG */
6931
6932   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
6933 }
6934
6935 /**
6936  * clutter_actor_queue_redraw_with_clip:
6937  * @self: a #ClutterActor
6938  * @clip: (allow-none): a rectangular clip region, or %NULL
6939  *
6940  * Queues a redraw on @self limited to a specific, actor-relative
6941  * rectangular area.
6942  *
6943  * If @clip is %NULL this function is equivalent to
6944  * clutter_actor_queue_redraw().
6945  *
6946  * Since: 1.10
6947  */
6948 void
6949 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
6950                                       const cairo_rectangle_int_t *clip)
6951 {
6952   ClutterPaintVolume volume;
6953   ClutterVertex origin;
6954
6955   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6956
6957   if (clip == NULL)
6958     {
6959       clutter_actor_queue_redraw (self);
6960       return;
6961     }
6962
6963   _clutter_paint_volume_init_static (&volume, self);
6964
6965   origin.x = clip->x;
6966   origin.y = clip->y;
6967   origin.z = 0.0f;
6968
6969   clutter_paint_volume_set_origin (&volume, &origin);
6970   clutter_paint_volume_set_width (&volume, clip->width);
6971   clutter_paint_volume_set_height (&volume, clip->height);
6972
6973   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
6974
6975   clutter_paint_volume_free (&volume);
6976 }
6977
6978 /**
6979  * clutter_actor_queue_relayout:
6980  * @self: A #ClutterActor
6981  *
6982  * Indicates that the actor's size request or other layout-affecting
6983  * properties may have changed. This function is used inside #ClutterActor
6984  * subclass implementations, not by applications directly.
6985  *
6986  * Queueing a new layout automatically queues a redraw as well.
6987  *
6988  * Since: 0.8
6989  */
6990 void
6991 clutter_actor_queue_relayout (ClutterActor *self)
6992 {
6993   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6994
6995   _clutter_actor_queue_only_relayout (self);
6996   clutter_actor_queue_redraw (self);
6997 }
6998
6999 /**
7000  * clutter_actor_get_preferred_size:
7001  * @self: a #ClutterActor
7002  * @min_width_p: (out) (allow-none): return location for the minimum
7003  *   width, or %NULL
7004  * @min_height_p: (out) (allow-none): return location for the minimum
7005  *   height, or %NULL
7006  * @natural_width_p: (out) (allow-none): return location for the natural
7007  *   width, or %NULL
7008  * @natural_height_p: (out) (allow-none): return location for the natural
7009  *   height, or %NULL
7010  *
7011  * Computes the preferred minimum and natural size of an actor, taking into
7012  * account the actor's geometry management (either height-for-width
7013  * or width-for-height).
7014  *
7015  * The width and height used to compute the preferred height and preferred
7016  * width are the actor's natural ones.
7017  *
7018  * If you need to control the height for the preferred width, or the width for
7019  * the preferred height, you should use clutter_actor_get_preferred_width()
7020  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7021  * geometry management using the #ClutterActor:request-mode property.
7022  *
7023  * Since: 0.8
7024  */
7025 void
7026 clutter_actor_get_preferred_size (ClutterActor *self,
7027                                   gfloat       *min_width_p,
7028                                   gfloat       *min_height_p,
7029                                   gfloat       *natural_width_p,
7030                                   gfloat       *natural_height_p)
7031 {
7032   ClutterActorPrivate *priv;
7033   gfloat min_width, min_height;
7034   gfloat natural_width, natural_height;
7035
7036   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7037
7038   priv = self->priv;
7039
7040   min_width = min_height = 0;
7041   natural_width = natural_height = 0;
7042
7043   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7044     {
7045       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7046       clutter_actor_get_preferred_width (self, -1,
7047                                          &min_width,
7048                                          &natural_width);
7049       clutter_actor_get_preferred_height (self, natural_width,
7050                                           &min_height,
7051                                           &natural_height);
7052     }
7053   else
7054     {
7055       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7056       clutter_actor_get_preferred_height (self, -1,
7057                                           &min_height,
7058                                           &natural_height);
7059       clutter_actor_get_preferred_width (self, natural_height,
7060                                          &min_width,
7061                                          &natural_width);
7062     }
7063
7064   if (min_width_p)
7065     *min_width_p = min_width;
7066
7067   if (min_height_p)
7068     *min_height_p = min_height;
7069
7070   if (natural_width_p)
7071     *natural_width_p = natural_width;
7072
7073   if (natural_height_p)
7074     *natural_height_p = natural_height;
7075 }
7076
7077 /*< private >
7078  * effective_align:
7079  * @align: a #ClutterActorAlign
7080  * @direction: a #ClutterTextDirection
7081  *
7082  * Retrieves the correct alignment depending on the text direction
7083  *
7084  * Return value: the effective alignment
7085  */
7086 static ClutterActorAlign
7087 effective_align (ClutterActorAlign    align,
7088                  ClutterTextDirection direction)
7089 {
7090   ClutterActorAlign res;
7091
7092   switch (align)
7093     {
7094     case CLUTTER_ACTOR_ALIGN_START:
7095       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7096           ? CLUTTER_ACTOR_ALIGN_END
7097           : CLUTTER_ACTOR_ALIGN_START;
7098       break;
7099
7100     case CLUTTER_ACTOR_ALIGN_END:
7101       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7102           ? CLUTTER_ACTOR_ALIGN_START
7103           : CLUTTER_ACTOR_ALIGN_END;
7104       break;
7105
7106     default:
7107       res = align;
7108       break;
7109     }
7110
7111   return res;
7112 }
7113
7114 static inline void
7115 adjust_for_margin (float  margin_start,
7116                    float  margin_end,
7117                    float *minimum_size,
7118                    float *natural_size,
7119                    float *allocated_start,
7120                    float *allocated_end)
7121 {
7122   *minimum_size -= (margin_start + margin_end);
7123   *natural_size -= (margin_start + margin_end);
7124   *allocated_start += margin_start;
7125   *allocated_end -= margin_end;
7126 }
7127
7128 static inline void
7129 adjust_for_alignment (ClutterActorAlign  alignment,
7130                       float              natural_size,
7131                       float             *allocated_start,
7132                       float             *allocated_end)
7133 {
7134   float allocated_size = *allocated_end - *allocated_start;
7135
7136   switch (alignment)
7137     {
7138     case CLUTTER_ACTOR_ALIGN_FILL:
7139       /* do nothing */
7140       break;
7141
7142     case CLUTTER_ACTOR_ALIGN_START:
7143       /* keep start */
7144       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7145       break;
7146
7147     case CLUTTER_ACTOR_ALIGN_END:
7148       if (allocated_size > natural_size)
7149         {
7150           *allocated_start += (allocated_size - natural_size);
7151           *allocated_end = *allocated_start + natural_size;
7152         }
7153       break;
7154
7155     case CLUTTER_ACTOR_ALIGN_CENTER:
7156       if (allocated_size > natural_size)
7157         {
7158           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7159           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7160         }
7161       break;
7162     }
7163 }
7164
7165 /*< private >
7166  * clutter_actor_adjust_width:
7167  * @self: a #ClutterActor
7168  * @minimum_width: (inout): the actor's preferred minimum width, which
7169  *   will be adjusted depending on the margin
7170  * @natural_width: (inout): the actor's preferred natural width, which
7171  *   will be adjusted depending on the margin
7172  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7173  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7174  *
7175  * Adjusts the preferred and allocated position and size of an actor,
7176  * depending on the margin and alignment properties.
7177  */
7178 static void
7179 clutter_actor_adjust_width (ClutterActor *self,
7180                             gfloat       *minimum_width,
7181                             gfloat       *natural_width,
7182                             gfloat       *adjusted_x1,
7183                             gfloat       *adjusted_x2)
7184 {
7185   ClutterTextDirection text_dir;
7186   const ClutterLayoutInfo *info;
7187
7188   info = _clutter_actor_get_layout_info_or_defaults (self);
7189   text_dir = clutter_actor_get_text_direction (self);
7190
7191   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7192
7193   /* this will tweak natural_width to remove the margin, so that
7194    * adjust_for_alignment() will use the correct size
7195    */
7196   adjust_for_margin (info->margin.left, info->margin.right,
7197                      minimum_width, natural_width,
7198                      adjusted_x1, adjusted_x2);
7199
7200   adjust_for_alignment (effective_align (info->x_align, text_dir),
7201                         *natural_width,
7202                         adjusted_x1, adjusted_x2);
7203 }
7204
7205 /*< private >
7206  * clutter_actor_adjust_height:
7207  * @self: a #ClutterActor
7208  * @minimum_height: (inout): the actor's preferred minimum height, which
7209  *   will be adjusted depending on the margin
7210  * @natural_height: (inout): the actor's preferred natural height, which
7211  *   will be adjusted depending on the margin
7212  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7213  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7214  *
7215  * Adjusts the preferred and allocated position and size of an actor,
7216  * depending on the margin and alignment properties.
7217  */
7218 static void
7219 clutter_actor_adjust_height (ClutterActor *self,
7220                              gfloat       *minimum_height,
7221                              gfloat       *natural_height,
7222                              gfloat       *adjusted_y1,
7223                              gfloat       *adjusted_y2)
7224 {
7225   const ClutterLayoutInfo *info;
7226
7227   info = _clutter_actor_get_layout_info_or_defaults (self);
7228
7229   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7230
7231   /* this will tweak natural_height to remove the margin, so that
7232    * adjust_for_alignment() will use the correct size
7233    */
7234   adjust_for_margin (info->margin.top, info->margin.bottom,
7235                      minimum_height, natural_height,
7236                      adjusted_y1,
7237                      adjusted_y2);
7238
7239   /* we don't use effective_align() here, because text direction
7240    * only affects the horizontal axis
7241    */
7242   adjust_for_alignment (info->y_align,
7243                         *natural_height,
7244                         adjusted_y1,
7245                         adjusted_y2);
7246
7247 }
7248
7249 /* looks for a cached size request for this for_size. If not
7250  * found, returns the oldest entry so it can be overwritten */
7251 static gboolean
7252 _clutter_actor_get_cached_size_request (gfloat         for_size,
7253                                         SizeRequest   *cached_size_requests,
7254                                         SizeRequest  **result)
7255 {
7256   guint i;
7257
7258   *result = &cached_size_requests[0];
7259
7260   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7261     {
7262       SizeRequest *sr;
7263
7264       sr = &cached_size_requests[i];
7265
7266       if (sr->age > 0 &&
7267           sr->for_size == for_size)
7268         {
7269           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7270           *result = sr;
7271           return TRUE;
7272         }
7273       else if (sr->age < (*result)->age)
7274         {
7275           *result = sr;
7276         }
7277     }
7278
7279   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7280
7281   return FALSE;
7282 }
7283
7284 /**
7285  * clutter_actor_get_preferred_width:
7286  * @self: A #ClutterActor
7287  * @for_height: available height when computing the preferred width,
7288  *   or a negative value to indicate that no height is defined
7289  * @min_width_p: (out) (allow-none): return location for minimum width,
7290  *   or %NULL
7291  * @natural_width_p: (out) (allow-none): return location for the natural
7292  *   width, or %NULL
7293  *
7294  * Computes the requested minimum and natural widths for an actor,
7295  * optionally depending on the specified height, or if they are
7296  * already computed, returns the cached values.
7297  *
7298  * An actor may not get its request - depending on the layout
7299  * manager that's in effect.
7300  *
7301  * A request should not incorporate the actor's scale or anchor point;
7302  * those transformations do not affect layout, only rendering.
7303  *
7304  * Since: 0.8
7305  */
7306 void
7307 clutter_actor_get_preferred_width (ClutterActor *self,
7308                                    gfloat        for_height,
7309                                    gfloat       *min_width_p,
7310                                    gfloat       *natural_width_p)
7311 {
7312   float request_min_width, request_natural_width;
7313   SizeRequest *cached_size_request;
7314   const ClutterLayoutInfo *info;
7315   ClutterActorPrivate *priv;
7316   gboolean found_in_cache;
7317
7318   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7319
7320   priv = self->priv;
7321
7322   info = _clutter_actor_get_layout_info_or_defaults (self);
7323
7324   /* we shortcircuit the case of a fixed size set using set_width() */
7325   if (priv->min_width_set && priv->natural_width_set)
7326     {
7327       if (min_width_p != NULL)
7328         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7329
7330       if (natural_width_p != NULL)
7331         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7332
7333       return;
7334     }
7335
7336   /* the remaining cases are:
7337    *
7338    *   - either min_width or natural_width have been set
7339    *   - neither min_width or natural_width have been set
7340    *
7341    * in both cases, we go through the cache (and through the actor in case
7342    * of cache misses) and determine the authoritative value depending on
7343    * the *_set flags.
7344    */
7345
7346   if (!priv->needs_width_request)
7347     {
7348       found_in_cache =
7349         _clutter_actor_get_cached_size_request (for_height,
7350                                                 priv->width_requests,
7351                                                 &cached_size_request);
7352     }
7353   else
7354     {
7355       /* if the actor needs a width request we use the first slot */
7356       found_in_cache = FALSE;
7357       cached_size_request = &priv->width_requests[0];
7358     }
7359
7360   if (!found_in_cache)
7361     {
7362       gfloat minimum_width, natural_width;
7363       ClutterActorClass *klass;
7364
7365       minimum_width = natural_width = 0;
7366
7367       /* adjust for the margin */
7368       if (for_height >= 0)
7369         {
7370           for_height -= (info->margin.top + info->margin.bottom);
7371           if (for_height < 0)
7372             for_height = 0;
7373         }
7374
7375       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7376
7377       klass = CLUTTER_ACTOR_GET_CLASS (self);
7378       klass->get_preferred_width (self, for_height,
7379                                   &minimum_width,
7380                                   &natural_width);
7381
7382       /* adjust for the margin */
7383       minimum_width += (info->margin.left + info->margin.right);
7384       natural_width += (info->margin.left + info->margin.right);
7385
7386       /* Due to accumulated float errors, it's better not to warn
7387        * on this, but just fix it.
7388        */
7389       if (natural_width < minimum_width)
7390         natural_width = minimum_width;
7391
7392       cached_size_request->min_size = minimum_width;
7393       cached_size_request->natural_size = natural_width;
7394       cached_size_request->for_size = for_height;
7395       cached_size_request->age = priv->cached_width_age;
7396
7397       priv->cached_width_age += 1;
7398       priv->needs_width_request = FALSE;
7399     }
7400
7401   if (!priv->min_width_set)
7402     request_min_width = cached_size_request->min_size;
7403   else
7404     request_min_width = info->min_width;
7405
7406   if (!priv->natural_width_set)
7407     request_natural_width = cached_size_request->natural_size;
7408   else
7409     request_natural_width = info->natural_width;
7410
7411   if (min_width_p)
7412     *min_width_p = request_min_width;
7413
7414   if (natural_width_p)
7415     *natural_width_p = request_natural_width;
7416 }
7417
7418 /**
7419  * clutter_actor_get_preferred_height:
7420  * @self: A #ClutterActor
7421  * @for_width: available width to assume in computing desired height,
7422  *   or a negative value to indicate that no width is defined
7423  * @min_height_p: (out) (allow-none): return location for minimum height,
7424  *   or %NULL
7425  * @natural_height_p: (out) (allow-none): return location for natural
7426  *   height, or %NULL
7427  *
7428  * Computes the requested minimum and natural heights for an actor,
7429  * or if they are already computed, returns the cached values.
7430  *
7431  * An actor may not get its request - depending on the layout
7432  * manager that's in effect.
7433  *
7434  * A request should not incorporate the actor's scale or anchor point;
7435  * those transformations do not affect layout, only rendering.
7436  *
7437  * Since: 0.8
7438  */
7439 void
7440 clutter_actor_get_preferred_height (ClutterActor *self,
7441                                     gfloat        for_width,
7442                                     gfloat       *min_height_p,
7443                                     gfloat       *natural_height_p)
7444 {
7445   float request_min_height, request_natural_height;
7446   SizeRequest *cached_size_request;
7447   const ClutterLayoutInfo *info;
7448   ClutterActorPrivate *priv;
7449   gboolean found_in_cache;
7450
7451   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7452
7453   priv = self->priv;
7454
7455   info = _clutter_actor_get_layout_info_or_defaults (self);
7456
7457   /* we shortcircuit the case of a fixed size set using set_height() */
7458   if (priv->min_height_set && priv->natural_height_set)
7459     {
7460       if (min_height_p != NULL)
7461         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7462
7463       if (natural_height_p != NULL)
7464         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7465
7466       return;
7467     }
7468
7469   /* the remaining cases are:
7470    *
7471    *   - either min_height or natural_height have been set
7472    *   - neither min_height or natural_height have been set
7473    *
7474    * in both cases, we go through the cache (and through the actor in case
7475    * of cache misses) and determine the authoritative value depending on
7476    * the *_set flags.
7477    */
7478
7479   if (!priv->needs_height_request)
7480     {
7481       found_in_cache =
7482         _clutter_actor_get_cached_size_request (for_width,
7483                                                 priv->height_requests,
7484                                                 &cached_size_request);
7485     }
7486   else
7487     {
7488       found_in_cache = FALSE;
7489       cached_size_request = &priv->height_requests[0];
7490     }
7491
7492   if (!found_in_cache)
7493     {
7494       gfloat minimum_height, natural_height;
7495       ClutterActorClass *klass;
7496
7497       minimum_height = natural_height = 0;
7498
7499       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7500
7501       /* adjust for margin */
7502       if (for_width >= 0)
7503         {
7504           for_width -= (info->margin.left + info->margin.right);
7505           if (for_width < 0)
7506             for_width = 0;
7507         }
7508
7509       klass = CLUTTER_ACTOR_GET_CLASS (self);
7510       klass->get_preferred_height (self, for_width,
7511                                    &minimum_height,
7512                                    &natural_height);
7513
7514       /* adjust for margin */
7515       minimum_height += (info->margin.top + info->margin.bottom);
7516       natural_height += (info->margin.top + info->margin.bottom);
7517
7518       /* Due to accumulated float errors, it's better not to warn
7519        * on this, but just fix it.
7520        */
7521       if (natural_height < minimum_height)
7522         natural_height = minimum_height;
7523
7524       cached_size_request->min_size = minimum_height;
7525       cached_size_request->natural_size = natural_height;
7526       cached_size_request->for_size = for_width;
7527       cached_size_request->age = priv->cached_height_age;
7528
7529       priv->cached_height_age += 1;
7530       priv->needs_height_request = FALSE;
7531     }
7532
7533   if (!priv->min_height_set)
7534     request_min_height = cached_size_request->min_size;
7535   else
7536     request_min_height = info->min_height;
7537
7538   if (!priv->natural_height_set)
7539     request_natural_height = cached_size_request->natural_size;
7540   else
7541     request_natural_height = info->natural_height;
7542
7543   if (min_height_p)
7544     *min_height_p = request_min_height;
7545
7546   if (natural_height_p)
7547     *natural_height_p = request_natural_height;
7548 }
7549
7550 /**
7551  * clutter_actor_get_allocation_box:
7552  * @self: A #ClutterActor
7553  * @box: (out): the function fills this in with the actor's allocation
7554  *
7555  * Gets the layout box an actor has been assigned. The allocation can
7556  * only be assumed valid inside a paint() method; anywhere else, it
7557  * may be out-of-date.
7558  *
7559  * An allocation does not incorporate the actor's scale or anchor point;
7560  * those transformations do not affect layout, only rendering.
7561  *
7562  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7563  * of functions inside the implementation of the get_preferred_width()
7564  * or get_preferred_height() virtual functions.</note>
7565  *
7566  * Since: 0.8
7567  */
7568 void
7569 clutter_actor_get_allocation_box (ClutterActor    *self,
7570                                   ClutterActorBox *box)
7571 {
7572   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7573
7574   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7575    * which limits calling get_allocation to inside paint() basically; or
7576    * we can 2) force a layout, which could be expensive if someone calls
7577    * get_allocation somewhere silly; or we can 3) just return the latest
7578    * value, allowing it to be out-of-date, and assume people know what
7579    * they are doing.
7580    *
7581    * The least-surprises approach that keeps existing code working is
7582    * likely to be 2). People can end up doing some inefficient things,
7583    * though, and in general code that requires 2) is probably broken.
7584    */
7585
7586   /* this implements 2) */
7587   if (G_UNLIKELY (self->priv->needs_allocation))
7588     {
7589       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7590
7591       /* do not queue a relayout on an unparented actor */
7592       if (stage)
7593         _clutter_stage_maybe_relayout (stage);
7594     }
7595
7596   /* commenting out the code above and just keeping this assigment
7597    * implements 3)
7598    */
7599   *box = self->priv->allocation;
7600 }
7601
7602 /**
7603  * clutter_actor_get_allocation_geometry:
7604  * @self: A #ClutterActor
7605  * @geom: (out): allocation geometry in pixels
7606  *
7607  * Gets the layout box an actor has been assigned.  The allocation can
7608  * only be assumed valid inside a paint() method; anywhere else, it
7609  * may be out-of-date.
7610  *
7611  * An allocation does not incorporate the actor's scale or anchor point;
7612  * those transformations do not affect layout, only rendering.
7613  *
7614  * The returned rectangle is in pixels.
7615  *
7616  * Since: 0.8
7617  */
7618 void
7619 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7620                                        ClutterGeometry *geom)
7621 {
7622   ClutterActorBox box;
7623
7624   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7625   g_return_if_fail (geom != NULL);
7626
7627   clutter_actor_get_allocation_box (self, &box);
7628
7629   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7630   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7631   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7632   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7633 }
7634
7635 static void
7636 clutter_actor_update_constraints (ClutterActor    *self,
7637                                   ClutterActorBox *allocation)
7638 {
7639   ClutterActorPrivate *priv = self->priv;
7640   const GList *constraints, *l;
7641
7642   if (priv->constraints == NULL)
7643     return;
7644
7645   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7646   for (l = constraints; l != NULL; l = l->next)
7647     {
7648       ClutterConstraint *constraint = l->data;
7649       ClutterActorMeta *meta = l->data;
7650
7651       if (clutter_actor_meta_get_enabled (meta))
7652         {
7653           _clutter_constraint_update_allocation (constraint,
7654                                                  self,
7655                                                  allocation);
7656         }
7657     }
7658 }
7659
7660 /*< private >
7661  * clutter_actor_adjust_allocation:
7662  * @self: a #ClutterActor
7663  * @allocation: (inout): the allocation to adjust
7664  *
7665  * Adjusts the passed allocation box taking into account the actor's
7666  * layout information, like alignment, expansion, and margin.
7667  */
7668 static void
7669 clutter_actor_adjust_allocation (ClutterActor    *self,
7670                                  ClutterActorBox *allocation)
7671 {
7672   ClutterActorBox adj_allocation;
7673   float alloc_width, alloc_height;
7674   float min_width, min_height;
7675   float nat_width, nat_height;
7676   ClutterRequestMode req_mode;
7677
7678   adj_allocation = *allocation;
7679
7680   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7681
7682   /* we want to hit the cache, so we use the public API */
7683   req_mode = clutter_actor_get_request_mode (self);
7684
7685   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7686     {
7687       clutter_actor_get_preferred_width (self, -1,
7688                                          &min_width,
7689                                          &nat_width);
7690       clutter_actor_get_preferred_height (self, alloc_width,
7691                                           &min_height,
7692                                           &nat_height);
7693     }
7694   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7695     {
7696       clutter_actor_get_preferred_height (self, -1,
7697                                           &min_height,
7698                                           &nat_height);
7699       clutter_actor_get_preferred_height (self, alloc_height,
7700                                           &min_width,
7701                                           &nat_width);
7702     }
7703
7704 #ifdef CLUTTER_ENABLE_DEBUG
7705   /* warn about underallocations */
7706   if (_clutter_diagnostic_enabled () &&
7707       (floorf (min_width - alloc_width) > 0 ||
7708        floorf (min_height - alloc_height) > 0))
7709     {
7710       ClutterActor *parent = clutter_actor_get_parent (self);
7711
7712       /* the only actors that are allowed to be underallocated are the Stage,
7713        * as it doesn't have an implicit size, and Actors that specifically
7714        * told us that they want to opt-out from layout control mechanisms
7715        * through the NO_LAYOUT escape hatch.
7716        */
7717       if (parent != NULL &&
7718           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7719         {
7720           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7721                      "of %.2f x %.2f from its parent actor '%s', but its "
7722                      "requested minimum size is of %.2f x %.2f",
7723                      _clutter_actor_get_debug_name (self),
7724                      alloc_width, alloc_height,
7725                      _clutter_actor_get_debug_name (parent),
7726                      min_width, min_height);
7727         }
7728     }
7729 #endif
7730
7731   clutter_actor_adjust_width (self,
7732                               &min_width,
7733                               &nat_width,
7734                               &adj_allocation.x1,
7735                               &adj_allocation.x2);
7736
7737   clutter_actor_adjust_height (self,
7738                                &min_height,
7739                                &nat_height,
7740                                &adj_allocation.y1,
7741                                &adj_allocation.y2);
7742
7743   /* we maintain the invariant that an allocation cannot be adjusted
7744    * to be outside the parent-given box
7745    */
7746   if (adj_allocation.x1 < allocation->x1 ||
7747       adj_allocation.y1 < allocation->y1 ||
7748       adj_allocation.x2 > allocation->x2 ||
7749       adj_allocation.y2 > allocation->y2)
7750     {
7751       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7752                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7753                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7754                  _clutter_actor_get_debug_name (self),
7755                  adj_allocation.x1, adj_allocation.y1,
7756                  adj_allocation.x2 - adj_allocation.x1,
7757                  adj_allocation.y2 - adj_allocation.y1,
7758                  allocation->x1, allocation->y1,
7759                  allocation->x2 - allocation->x1,
7760                  allocation->y2 - allocation->y1);
7761       return;
7762     }
7763
7764   *allocation = adj_allocation;
7765 }
7766
7767 /**
7768  * clutter_actor_allocate:
7769  * @self: A #ClutterActor
7770  * @box: new allocation of the actor, in parent-relative coordinates
7771  * @flags: flags that control the allocation
7772  *
7773  * Called by the parent of an actor to assign the actor its size.
7774  * Should never be called by applications (except when implementing
7775  * a container or layout manager).
7776  *
7777  * Actors can know from their allocation box whether they have moved
7778  * with respect to their parent actor. The @flags parameter describes
7779  * additional information about the allocation, for instance whether
7780  * the parent has moved with respect to the stage, for example because
7781  * a grandparent's origin has moved.
7782  *
7783  * Since: 0.8
7784  */
7785 void
7786 clutter_actor_allocate (ClutterActor           *self,
7787                         const ClutterActorBox  *box,
7788                         ClutterAllocationFlags  flags)
7789 {
7790   ClutterActorPrivate *priv;
7791   ClutterActorClass *klass;
7792   ClutterActorBox old_allocation, real_allocation;
7793   gboolean origin_changed, child_moved, size_changed;
7794   gboolean stage_allocation_changed;
7795
7796   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7797   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
7798     {
7799       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
7800                  "which isn't a descendent of the stage!\n",
7801                  self, _clutter_actor_get_debug_name (self));
7802       return;
7803     }
7804
7805   priv = self->priv;
7806
7807   old_allocation = priv->allocation;
7808   real_allocation = *box;
7809
7810   /* constraints are allowed to modify the allocation only here; we do
7811    * this prior to all the other checks so that we can bail out if the
7812    * allocation did not change
7813    */
7814   clutter_actor_update_constraints (self, &real_allocation);
7815
7816   /* adjust the allocation depending on the align/margin properties */
7817   clutter_actor_adjust_allocation (self, &real_allocation);
7818
7819   if (real_allocation.x2 < real_allocation.x1 ||
7820       real_allocation.y2 < real_allocation.y1)
7821     {
7822       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
7823                  _clutter_actor_get_debug_name (self),
7824                  real_allocation.x2 - real_allocation.x1,
7825                  real_allocation.y2 - real_allocation.y1);
7826     }
7827
7828   /* we allow 0-sized actors, but not negative-sized ones */
7829   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
7830   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
7831
7832   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
7833
7834   child_moved = (real_allocation.x1 != old_allocation.x1 ||
7835                  real_allocation.y1 != old_allocation.y1);
7836
7837   size_changed = (real_allocation.x2 != old_allocation.x2 ||
7838                   real_allocation.y2 != old_allocation.y2);
7839
7840   if (origin_changed || child_moved || size_changed)
7841     stage_allocation_changed = TRUE;
7842   else
7843     stage_allocation_changed = FALSE;
7844
7845   /* If we get an allocation "out of the blue"
7846    * (we did not queue relayout), then we want to
7847    * ignore it. But if we have needs_allocation set,
7848    * we want to guarantee that allocate() virtual
7849    * method is always called, i.e. that queue_relayout()
7850    * always results in an allocate() invocation on
7851    * an actor.
7852    *
7853    * The optimization here is to avoid re-allocating
7854    * actors that did not queue relayout and were
7855    * not moved.
7856    */
7857   if (!priv->needs_allocation && !stage_allocation_changed)
7858     {
7859       CLUTTER_NOTE (LAYOUT, "No allocation needed");
7860       return;
7861     }
7862
7863   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
7864    * clutter_actor_allocate(), it indicates whether the parent has its
7865    * absolute origin moved; when passed in to ClutterActor::allocate()
7866    * virtual method though, it indicates whether the child has its
7867    * absolute origin moved.  So we set it when child_moved is TRUE
7868    */
7869   if (child_moved)
7870     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
7871
7872   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7873
7874   klass = CLUTTER_ACTOR_GET_CLASS (self);
7875   klass->allocate (self, &real_allocation, flags);
7876
7877   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7878
7879   if (stage_allocation_changed)
7880     clutter_actor_queue_redraw (self);
7881 }
7882
7883 /**
7884  * clutter_actor_set_allocation:
7885  * @self: a #ClutterActor
7886  * @box: a #ClutterActorBox
7887  * @flags: allocation flags
7888  *
7889  * Stores the allocation of @self as defined by @box.
7890  *
7891  * This function can only be called from within the implementation of
7892  * the #ClutterActorClass.allocate() virtual function.
7893  *
7894  * The allocation should have been adjusted to take into account constraints,
7895  * alignment, and margin properties. If you are implementing a #ClutterActor
7896  * subclass that provides its own layout management policy for its children
7897  * instead of using a #ClutterLayoutManager delegate, you should not call
7898  * this function on the children of @self; instead, you should call
7899  * clutter_actor_allocate(), which will adjust the allocation box for
7900  * you.
7901  *
7902  * This function should only be used by subclasses of #ClutterActor
7903  * that wish to store their allocation but cannot chain up to the
7904  * parent's implementation; the default implementation of the
7905  * #ClutterActorClass.allocate() virtual function will call this
7906  * function.
7907  *
7908  * It is important to note that, while chaining up was the recommended
7909  * behaviour for #ClutterActor subclasses prior to the introduction of
7910  * this function, it is recommended to call clutter_actor_set_allocation()
7911  * instead.
7912  *
7913  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
7914  * to handle the allocation of its children, this function will call
7915  * the clutter_layout_manager_allocate() function only if the
7916  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
7917  * expected that the subclass will call clutter_layout_manager_allocate()
7918  * by itself. For instance, the following code:
7919  *
7920  * |[
7921  * static void
7922  * my_actor_allocate (ClutterActor *actor,
7923  *                    const ClutterActorBox *allocation,
7924  *                    ClutterAllocationFlags flags)
7925  * {
7926  *   ClutterActorBox new_alloc;
7927  *   ClutterAllocationFlags new_flags;
7928  *
7929  *   adjust_allocation (allocation, &amp;new_alloc);
7930  *
7931  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
7932  *
7933  *   /&ast; this will use the layout manager set on the actor &ast;/
7934  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
7935  * }
7936  * ]|
7937  *
7938  * is equivalent to this:
7939  *
7940  * |[
7941  * static void
7942  * my_actor_allocate (ClutterActor *actor,
7943  *                    const ClutterActorBox *allocation,
7944  *                    ClutterAllocationFlags flags)
7945  * {
7946  *   ClutterLayoutManager *layout;
7947  *   ClutterActorBox new_alloc;
7948  *
7949  *   adjust_allocation (allocation, &amp;new_alloc);
7950  *
7951  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
7952  *
7953  *   layout = clutter_actor_get_layout_manager (actor);
7954  *   clutter_layout_manager_allocate (layout,
7955  *                                    CLUTTER_CONTAINER (actor),
7956  *                                    &amp;new_alloc,
7957  *                                    flags);
7958  * }
7959  * ]|
7960  *
7961  * Since: 1.10
7962  */
7963 void
7964 clutter_actor_set_allocation (ClutterActor           *self,
7965                               const ClutterActorBox  *box,
7966                               ClutterAllocationFlags  flags)
7967 {
7968   ClutterActorPrivate *priv;
7969   gboolean changed;
7970
7971   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7972   g_return_if_fail (box != NULL);
7973
7974   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
7975     {
7976       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
7977                   "can only be called from within the implementation of "
7978                   "the ClutterActor::allocate() virtual function.");
7979       return;
7980     }
7981
7982   priv = self->priv;
7983
7984   g_object_freeze_notify (G_OBJECT (self));
7985
7986   changed = clutter_actor_set_allocation_internal (self, box, flags);
7987
7988   /* we allocate our children before we notify changes in our geometry,
7989    * so that people connecting to properties will be able to get valid
7990    * data out of the sub-tree of the scene graph that has this actor at
7991    * the root.
7992    */
7993   clutter_actor_maybe_layout_children (self, box, flags);
7994
7995   if (changed)
7996     {
7997       ClutterActorBox signal_box = priv->allocation;
7998       ClutterAllocationFlags signal_flags = priv->allocation_flags;
7999
8000       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8001                      &signal_box,
8002                      signal_flags);
8003     }
8004
8005   g_object_thaw_notify (G_OBJECT (self));
8006 }
8007
8008 /**
8009  * clutter_actor_set_geometry:
8010  * @self: A #ClutterActor
8011  * @geometry: A #ClutterGeometry
8012  *
8013  * Sets the actor's fixed position and forces its minimum and natural
8014  * size, in pixels. This means the untransformed actor will have the
8015  * given geometry. This is the same as calling clutter_actor_set_position()
8016  * and clutter_actor_set_size().
8017  *
8018  * Deprecated: 1.10: Use clutter_actor_set_position() and
8019  *   clutter_actor_set_size() instead.
8020  */
8021 void
8022 clutter_actor_set_geometry (ClutterActor          *self,
8023                             const ClutterGeometry *geometry)
8024 {
8025   g_object_freeze_notify (G_OBJECT (self));
8026
8027   clutter_actor_set_position (self, geometry->x, geometry->y);
8028   clutter_actor_set_size (self, geometry->width, geometry->height);
8029
8030   g_object_thaw_notify (G_OBJECT (self));
8031 }
8032
8033 /**
8034  * clutter_actor_get_geometry:
8035  * @self: A #ClutterActor
8036  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8037  *
8038  * Gets the size and position of an actor relative to its parent
8039  * actor. This is the same as calling clutter_actor_get_position() and
8040  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8041  * requested size and position if the actor's allocation is invalid.
8042  *
8043  * Deprecated: 1.10: Use clutter_actor_get_position() and
8044  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8045  *   instead.
8046  */
8047 void
8048 clutter_actor_get_geometry (ClutterActor    *self,
8049                             ClutterGeometry *geometry)
8050 {
8051   gfloat x, y, width, height;
8052
8053   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8054   g_return_if_fail (geometry != NULL);
8055
8056   clutter_actor_get_position (self, &x, &y);
8057   clutter_actor_get_size (self, &width, &height);
8058
8059   geometry->x = (int) x;
8060   geometry->y = (int) y;
8061   geometry->width = (int) width;
8062   geometry->height = (int) height;
8063 }
8064
8065 /**
8066  * clutter_actor_set_position:
8067  * @self: A #ClutterActor
8068  * @x: New left position of actor in pixels.
8069  * @y: New top position of actor in pixels.
8070  *
8071  * Sets the actor's fixed position in pixels relative to any parent
8072  * actor.
8073  *
8074  * If a layout manager is in use, this position will override the
8075  * layout manager and force a fixed position.
8076  */
8077 void
8078 clutter_actor_set_position (ClutterActor *self,
8079                             gfloat        x,
8080                             gfloat        y)
8081 {
8082   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8083
8084   g_object_freeze_notify (G_OBJECT (self));
8085
8086   clutter_actor_set_x (self, x);
8087   clutter_actor_set_y (self, y);
8088
8089   g_object_thaw_notify (G_OBJECT (self));
8090 }
8091
8092 /**
8093  * clutter_actor_get_fixed_position_set:
8094  * @self: A #ClutterActor
8095  *
8096  * Checks whether an actor has a fixed position set (and will thus be
8097  * unaffected by any layout manager).
8098  *
8099  * Return value: %TRUE if the fixed position is set on the actor
8100  *
8101  * Since: 0.8
8102  */
8103 gboolean
8104 clutter_actor_get_fixed_position_set (ClutterActor *self)
8105 {
8106   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8107
8108   return self->priv->position_set;
8109 }
8110
8111 /**
8112  * clutter_actor_set_fixed_position_set:
8113  * @self: A #ClutterActor
8114  * @is_set: whether to use fixed position
8115  *
8116  * Sets whether an actor has a fixed position set (and will thus be
8117  * unaffected by any layout manager).
8118  *
8119  * Since: 0.8
8120  */
8121 void
8122 clutter_actor_set_fixed_position_set (ClutterActor *self,
8123                                       gboolean      is_set)
8124 {
8125   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8126
8127   if (self->priv->position_set == (is_set != FALSE))
8128     return;
8129
8130   self->priv->position_set = is_set != FALSE;
8131   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8132
8133   clutter_actor_queue_relayout (self);
8134 }
8135
8136 /**
8137  * clutter_actor_move_by:
8138  * @self: A #ClutterActor
8139  * @dx: Distance to move Actor on X axis.
8140  * @dy: Distance to move Actor on Y axis.
8141  *
8142  * Moves an actor by the specified distance relative to its current
8143  * position in pixels.
8144  *
8145  * This function modifies the fixed position of an actor and thus removes
8146  * it from any layout management. Another way to move an actor is with an
8147  * anchor point, see clutter_actor_set_anchor_point().
8148  *
8149  * Since: 0.2
8150  */
8151 void
8152 clutter_actor_move_by (ClutterActor *self,
8153                        gfloat        dx,
8154                        gfloat        dy)
8155 {
8156   const ClutterLayoutInfo *info;
8157   gfloat x, y;
8158
8159   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8160
8161   info = _clutter_actor_get_layout_info_or_defaults (self);
8162   x = info->fixed_x;
8163   y = info->fixed_y;
8164
8165   clutter_actor_set_position (self, x + dx, y + dy);
8166 }
8167
8168 static void
8169 clutter_actor_set_min_width (ClutterActor *self,
8170                              gfloat        min_width)
8171 {
8172   ClutterActorPrivate *priv = self->priv;
8173   ClutterActorBox old = { 0, };
8174   ClutterLayoutInfo *info;
8175
8176   /* if we are setting the size on a top-level actor and the
8177    * backend only supports static top-levels (e.g. framebuffers)
8178    * then we ignore the passed value and we override it with
8179    * the stage implementation's preferred size.
8180    */
8181   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8182       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8183     return;
8184
8185   info = _clutter_actor_get_layout_info (self);
8186
8187   if (priv->min_width_set && min_width == info->min_width)
8188     return;
8189
8190   g_object_freeze_notify (G_OBJECT (self));
8191
8192   clutter_actor_store_old_geometry (self, &old);
8193
8194   info->min_width = min_width;
8195   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8196   clutter_actor_set_min_width_set (self, TRUE);
8197
8198   clutter_actor_notify_if_geometry_changed (self, &old);
8199
8200   g_object_thaw_notify (G_OBJECT (self));
8201
8202   clutter_actor_queue_relayout (self);
8203 }
8204
8205 static void
8206 clutter_actor_set_min_height (ClutterActor *self,
8207                               gfloat        min_height)
8208
8209 {
8210   ClutterActorPrivate *priv = self->priv;
8211   ClutterActorBox old = { 0, };
8212   ClutterLayoutInfo *info;
8213
8214   /* if we are setting the size on a top-level actor and the
8215    * backend only supports static top-levels (e.g. framebuffers)
8216    * then we ignore the passed value and we override it with
8217    * the stage implementation's preferred size.
8218    */
8219   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8220       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8221     return;
8222
8223   info = _clutter_actor_get_layout_info (self);
8224
8225   if (priv->min_height_set && min_height == info->min_height)
8226     return;
8227
8228   g_object_freeze_notify (G_OBJECT (self));
8229
8230   clutter_actor_store_old_geometry (self, &old);
8231
8232   info->min_height = min_height;
8233   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8234   clutter_actor_set_min_height_set (self, TRUE);
8235
8236   clutter_actor_notify_if_geometry_changed (self, &old);
8237
8238   g_object_thaw_notify (G_OBJECT (self));
8239
8240   clutter_actor_queue_relayout (self);
8241 }
8242
8243 static void
8244 clutter_actor_set_natural_width (ClutterActor *self,
8245                                  gfloat        natural_width)
8246 {
8247   ClutterActorPrivate *priv = self->priv;
8248   ClutterActorBox old = { 0, };
8249   ClutterLayoutInfo *info;
8250
8251   /* if we are setting the size on a top-level actor and the
8252    * backend only supports static top-levels (e.g. framebuffers)
8253    * then we ignore the passed value and we override it with
8254    * the stage implementation's preferred size.
8255    */
8256   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8257       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8258     return;
8259
8260   info = _clutter_actor_get_layout_info (self);
8261
8262   if (priv->natural_width_set && natural_width == info->natural_width)
8263     return;
8264
8265   g_object_freeze_notify (G_OBJECT (self));
8266
8267   clutter_actor_store_old_geometry (self, &old);
8268
8269   info->natural_width = natural_width;
8270   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8271   clutter_actor_set_natural_width_set (self, TRUE);
8272
8273   clutter_actor_notify_if_geometry_changed (self, &old);
8274
8275   g_object_thaw_notify (G_OBJECT (self));
8276
8277   clutter_actor_queue_relayout (self);
8278 }
8279
8280 static void
8281 clutter_actor_set_natural_height (ClutterActor *self,
8282                                   gfloat        natural_height)
8283 {
8284   ClutterActorPrivate *priv = self->priv;
8285   ClutterActorBox old = { 0, };
8286   ClutterLayoutInfo *info;
8287
8288   /* if we are setting the size on a top-level actor and the
8289    * backend only supports static top-levels (e.g. framebuffers)
8290    * then we ignore the passed value and we override it with
8291    * the stage implementation's preferred size.
8292    */
8293   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8294       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8295     return;
8296
8297   info = _clutter_actor_get_layout_info (self);
8298
8299   if (priv->natural_height_set && natural_height == info->natural_height)
8300     return;
8301
8302   g_object_freeze_notify (G_OBJECT (self));
8303
8304   clutter_actor_store_old_geometry (self, &old);
8305
8306   info->natural_height = natural_height;
8307   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8308   clutter_actor_set_natural_height_set (self, TRUE);
8309
8310   clutter_actor_notify_if_geometry_changed (self, &old);
8311
8312   g_object_thaw_notify (G_OBJECT (self));
8313
8314   clutter_actor_queue_relayout (self);
8315 }
8316
8317 static void
8318 clutter_actor_set_min_width_set (ClutterActor *self,
8319                                  gboolean      use_min_width)
8320 {
8321   ClutterActorPrivate *priv = self->priv;
8322   ClutterActorBox old = { 0, };
8323
8324   if (priv->min_width_set == (use_min_width != FALSE))
8325     return;
8326
8327   clutter_actor_store_old_geometry (self, &old);
8328
8329   priv->min_width_set = use_min_width != FALSE;
8330   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8331
8332   clutter_actor_notify_if_geometry_changed (self, &old);
8333
8334   clutter_actor_queue_relayout (self);
8335 }
8336
8337 static void
8338 clutter_actor_set_min_height_set (ClutterActor *self,
8339                                   gboolean      use_min_height)
8340 {
8341   ClutterActorPrivate *priv = self->priv;
8342   ClutterActorBox old = { 0, };
8343
8344   if (priv->min_height_set == (use_min_height != FALSE))
8345     return;
8346
8347   clutter_actor_store_old_geometry (self, &old);
8348
8349   priv->min_height_set = use_min_height != FALSE;
8350   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8351
8352   clutter_actor_notify_if_geometry_changed (self, &old);
8353
8354   clutter_actor_queue_relayout (self);
8355 }
8356
8357 static void
8358 clutter_actor_set_natural_width_set (ClutterActor *self,
8359                                      gboolean      use_natural_width)
8360 {
8361   ClutterActorPrivate *priv = self->priv;
8362   ClutterActorBox old = { 0, };
8363
8364   if (priv->natural_width_set == (use_natural_width != FALSE))
8365     return;
8366
8367   clutter_actor_store_old_geometry (self, &old);
8368
8369   priv->natural_width_set = use_natural_width != FALSE;
8370   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8371
8372   clutter_actor_notify_if_geometry_changed (self, &old);
8373
8374   clutter_actor_queue_relayout (self);
8375 }
8376
8377 static void
8378 clutter_actor_set_natural_height_set (ClutterActor *self,
8379                                       gboolean      use_natural_height)
8380 {
8381   ClutterActorPrivate *priv = self->priv;
8382   ClutterActorBox old = { 0, };
8383
8384   if (priv->natural_height_set == (use_natural_height != FALSE))
8385     return;
8386
8387   clutter_actor_store_old_geometry (self, &old);
8388
8389   priv->natural_height_set = use_natural_height != FALSE;
8390   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8391
8392   clutter_actor_notify_if_geometry_changed (self, &old);
8393
8394   clutter_actor_queue_relayout (self);
8395 }
8396
8397 /**
8398  * clutter_actor_set_request_mode:
8399  * @self: a #ClutterActor
8400  * @mode: the request mode
8401  *
8402  * Sets the geometry request mode of @self.
8403  *
8404  * The @mode determines the order for invoking
8405  * clutter_actor_get_preferred_width() and
8406  * clutter_actor_get_preferred_height()
8407  *
8408  * Since: 1.2
8409  */
8410 void
8411 clutter_actor_set_request_mode (ClutterActor       *self,
8412                                 ClutterRequestMode  mode)
8413 {
8414   ClutterActorPrivate *priv;
8415
8416   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8417
8418   priv = self->priv;
8419
8420   if (priv->request_mode == mode)
8421     return;
8422
8423   priv->request_mode = mode;
8424
8425   priv->needs_width_request = TRUE;
8426   priv->needs_height_request = TRUE;
8427
8428   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8429
8430   clutter_actor_queue_relayout (self);
8431 }
8432
8433 /**
8434  * clutter_actor_get_request_mode:
8435  * @self: a #ClutterActor
8436  *
8437  * Retrieves the geometry request mode of @self
8438  *
8439  * Return value: the request mode for the actor
8440  *
8441  * Since: 1.2
8442  */
8443 ClutterRequestMode
8444 clutter_actor_get_request_mode (ClutterActor *self)
8445 {
8446   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8447                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8448
8449   return self->priv->request_mode;
8450 }
8451
8452 /* variant of set_width() without checks and without notification
8453  * freeze+thaw, for internal usage only
8454  */
8455 static inline void
8456 clutter_actor_set_width_internal (ClutterActor *self,
8457                                   gfloat        width)
8458 {
8459   if (width >= 0)
8460     {
8461       /* the Stage will use the :min-width to control the minimum
8462        * width to be resized to, so we should not be setting it
8463        * along with the :natural-width
8464        */
8465       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8466         clutter_actor_set_min_width (self, width);
8467
8468       clutter_actor_set_natural_width (self, width);
8469     }
8470   else
8471     {
8472       /* we only unset the :natural-width for the Stage */
8473       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8474         clutter_actor_set_min_width_set (self, FALSE);
8475
8476       clutter_actor_set_natural_width_set (self, FALSE);
8477     }
8478 }
8479
8480 /* variant of set_height() without checks and without notification
8481  * freeze+thaw, for internal usage only
8482  */
8483 static inline void
8484 clutter_actor_set_height_internal (ClutterActor *self,
8485                                    gfloat        height)
8486 {
8487   if (height >= 0)
8488     {
8489       /* see the comment above in set_width_internal() */
8490       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8491         clutter_actor_set_min_height (self, height);
8492
8493       clutter_actor_set_natural_height (self, height);
8494     }
8495   else
8496     {
8497       /* see the comment above in set_width_internal() */
8498       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8499         clutter_actor_set_min_height_set (self, FALSE);
8500
8501       clutter_actor_set_natural_height_set (self, FALSE);
8502     }
8503 }
8504
8505 /**
8506  * clutter_actor_set_size:
8507  * @self: A #ClutterActor
8508  * @width: New width of actor in pixels, or -1
8509  * @height: New height of actor in pixels, or -1
8510  *
8511  * Sets the actor's size request in pixels. This overrides any
8512  * "normal" size request the actor would have. For example
8513  * a text actor might normally request the size of the text;
8514  * this function would force a specific size instead.
8515  *
8516  * If @width and/or @height are -1 the actor will use its
8517  * "normal" size request instead of overriding it, i.e.
8518  * you can "unset" the size with -1.
8519  *
8520  * This function sets or unsets both the minimum and natural size.
8521  */
8522 void
8523 clutter_actor_set_size (ClutterActor *self,
8524                         gfloat        width,
8525                         gfloat        height)
8526 {
8527   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8528
8529   g_object_freeze_notify (G_OBJECT (self));
8530
8531   clutter_actor_set_width_internal (self, width);
8532   clutter_actor_set_height_internal (self, height);
8533
8534   g_object_thaw_notify (G_OBJECT (self));
8535 }
8536
8537 /**
8538  * clutter_actor_get_size:
8539  * @self: A #ClutterActor
8540  * @width: (out) (allow-none): return location for the width, or %NULL.
8541  * @height: (out) (allow-none): return location for the height, or %NULL.
8542  *
8543  * This function tries to "do what you mean" and return
8544  * the size an actor will have. If the actor has a valid
8545  * allocation, the allocation will be returned; otherwise,
8546  * the actors natural size request will be returned.
8547  *
8548  * If you care whether you get the request vs. the allocation, you
8549  * should probably call a different function like
8550  * clutter_actor_get_allocation_box() or
8551  * clutter_actor_get_preferred_width().
8552  *
8553  * Since: 0.2
8554  */
8555 void
8556 clutter_actor_get_size (ClutterActor *self,
8557                         gfloat       *width,
8558                         gfloat       *height)
8559 {
8560   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8561
8562   if (width)
8563     *width = clutter_actor_get_width (self);
8564
8565   if (height)
8566     *height = clutter_actor_get_height (self);
8567 }
8568
8569 /**
8570  * clutter_actor_get_position:
8571  * @self: a #ClutterActor
8572  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8573  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8574  *
8575  * This function tries to "do what you mean" and tell you where the
8576  * actor is, prior to any transformations. Retrieves the fixed
8577  * position of an actor in pixels, if one has been set; otherwise, if
8578  * the allocation is valid, returns the actor's allocated position;
8579  * otherwise, returns 0,0.
8580  *
8581  * The returned position is in pixels.
8582  *
8583  * Since: 0.6
8584  */
8585 void
8586 clutter_actor_get_position (ClutterActor *self,
8587                             gfloat       *x,
8588                             gfloat       *y)
8589 {
8590   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8591
8592   if (x)
8593     *x = clutter_actor_get_x (self);
8594
8595   if (y)
8596     *y = clutter_actor_get_y (self);
8597 }
8598
8599 /**
8600  * clutter_actor_get_transformed_position:
8601  * @self: A #ClutterActor
8602  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8603  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8604  *
8605  * Gets the absolute position of an actor, in pixels relative to the stage.
8606  *
8607  * Since: 0.8
8608  */
8609 void
8610 clutter_actor_get_transformed_position (ClutterActor *self,
8611                                         gfloat       *x,
8612                                         gfloat       *y)
8613 {
8614   ClutterVertex v1;
8615   ClutterVertex v2;
8616
8617   v1.x = v1.y = v1.z = 0;
8618   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8619
8620   if (x)
8621     *x = v2.x;
8622
8623   if (y)
8624     *y = v2.y;
8625 }
8626
8627 /**
8628  * clutter_actor_get_transformed_size:
8629  * @self: A #ClutterActor
8630  * @width: (out) (allow-none): return location for the width, or %NULL
8631  * @height: (out) (allow-none): return location for the height, or %NULL
8632  *
8633  * Gets the absolute size of an actor in pixels, taking into account the
8634  * scaling factors.
8635  *
8636  * If the actor has a valid allocation, the allocated size will be used.
8637  * If the actor has not a valid allocation then the preferred size will
8638  * be transformed and returned.
8639  *
8640  * If you want the transformed allocation, see
8641  * clutter_actor_get_abs_allocation_vertices() instead.
8642  *
8643  * <note>When the actor (or one of its ancestors) is rotated around the
8644  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8645  * as a generic quadrangle; in that case this function returns the size
8646  * of the smallest rectangle that encapsulates the entire quad. Please
8647  * note that in this case no assumptions can be made about the relative
8648  * position of this envelope to the absolute position of the actor, as
8649  * returned by clutter_actor_get_transformed_position(); if you need this
8650  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8651  * to get the coords of the actual quadrangle.</note>
8652  *
8653  * Since: 0.8
8654  */
8655 void
8656 clutter_actor_get_transformed_size (ClutterActor *self,
8657                                     gfloat       *width,
8658                                     gfloat       *height)
8659 {
8660   ClutterActorPrivate *priv;
8661   ClutterVertex v[4];
8662   gfloat x_min, x_max, y_min, y_max;
8663   gint i;
8664
8665   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8666
8667   priv = self->priv;
8668
8669   /* if the actor hasn't been allocated yet, get the preferred
8670    * size and transform that
8671    */
8672   if (priv->needs_allocation)
8673     {
8674       gfloat natural_width, natural_height;
8675       ClutterActorBox box;
8676
8677       /* Make a fake allocation to transform.
8678        *
8679        * NB: _clutter_actor_transform_and_project_box expects a box in
8680        * the actor's coordinate space... */
8681
8682       box.x1 = 0;
8683       box.y1 = 0;
8684
8685       natural_width = natural_height = 0;
8686       clutter_actor_get_preferred_size (self, NULL, NULL,
8687                                         &natural_width,
8688                                         &natural_height);
8689
8690       box.x2 = natural_width;
8691       box.y2 = natural_height;
8692
8693       _clutter_actor_transform_and_project_box (self, &box, v);
8694     }
8695   else
8696     clutter_actor_get_abs_allocation_vertices (self, v);
8697
8698   x_min = x_max = v[0].x;
8699   y_min = y_max = v[0].y;
8700
8701   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8702     {
8703       if (v[i].x < x_min)
8704         x_min = v[i].x;
8705
8706       if (v[i].x > x_max)
8707         x_max = v[i].x;
8708
8709       if (v[i].y < y_min)
8710         y_min = v[i].y;
8711
8712       if (v[i].y > y_max)
8713         y_max = v[i].y;
8714     }
8715
8716   if (width)
8717     *width  = x_max - x_min;
8718
8719   if (height)
8720     *height = y_max - y_min;
8721 }
8722
8723 /**
8724  * clutter_actor_get_width:
8725  * @self: A #ClutterActor
8726  *
8727  * Retrieves the width of a #ClutterActor.
8728  *
8729  * If the actor has a valid allocation, this function will return the
8730  * width of the allocated area given to the actor.
8731  *
8732  * If the actor does not have a valid allocation, this function will
8733  * return the actor's natural width, that is the preferred width of
8734  * the actor.
8735  *
8736  * If you care whether you get the preferred width or the width that
8737  * has been assigned to the actor, you should probably call a different
8738  * function like clutter_actor_get_allocation_box() to retrieve the
8739  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8740  * preferred width.
8741  *
8742  * If an actor has a fixed width, for instance a width that has been
8743  * assigned using clutter_actor_set_width(), the width returned will
8744  * be the same value.
8745  *
8746  * Return value: the width of the actor, in pixels
8747  */
8748 gfloat
8749 clutter_actor_get_width (ClutterActor *self)
8750 {
8751   ClutterActorPrivate *priv;
8752
8753   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8754
8755   priv = self->priv;
8756
8757   if (priv->needs_allocation)
8758     {
8759       gfloat natural_width = 0;
8760
8761       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8762         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8763       else
8764         {
8765           gfloat natural_height = 0;
8766
8767           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8768           clutter_actor_get_preferred_width (self, natural_height,
8769                                              NULL,
8770                                              &natural_width);
8771         }
8772
8773       return natural_width;
8774     }
8775   else
8776     return priv->allocation.x2 - priv->allocation.x1;
8777 }
8778
8779 /**
8780  * clutter_actor_get_height:
8781  * @self: A #ClutterActor
8782  *
8783  * Retrieves the height of a #ClutterActor.
8784  *
8785  * If the actor has a valid allocation, this function will return the
8786  * height of the allocated area given to the actor.
8787  *
8788  * If the actor does not have a valid allocation, this function will
8789  * return the actor's natural height, that is the preferred height of
8790  * the actor.
8791  *
8792  * If you care whether you get the preferred height or the height that
8793  * has been assigned to the actor, you should probably call a different
8794  * function like clutter_actor_get_allocation_box() to retrieve the
8795  * allocated size or clutter_actor_get_preferred_height() to retrieve the
8796  * preferred height.
8797  *
8798  * If an actor has a fixed height, for instance a height that has been
8799  * assigned using clutter_actor_set_height(), the height returned will
8800  * be the same value.
8801  *
8802  * Return value: the height of the actor, in pixels
8803  */
8804 gfloat
8805 clutter_actor_get_height (ClutterActor *self)
8806 {
8807   ClutterActorPrivate *priv;
8808
8809   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8810
8811   priv = self->priv;
8812
8813   if (priv->needs_allocation)
8814     {
8815       gfloat natural_height = 0;
8816
8817       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8818         {
8819           gfloat natural_width = 0;
8820
8821           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8822           clutter_actor_get_preferred_height (self, natural_width,
8823                                               NULL, &natural_height);
8824         }
8825       else
8826         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8827
8828       return natural_height;
8829     }
8830   else
8831     return priv->allocation.y2 - priv->allocation.y1;
8832 }
8833
8834 /**
8835  * clutter_actor_set_width:
8836  * @self: A #ClutterActor
8837  * @width: Requested new width for the actor, in pixels, or -1
8838  *
8839  * Forces a width on an actor, causing the actor's preferred width
8840  * and height (if any) to be ignored.
8841  *
8842  * If @width is -1 the actor will use its preferred width request
8843  * instead of overriding it, i.e. you can "unset" the width with -1.
8844  *
8845  * This function sets both the minimum and natural size of the actor.
8846  *
8847  * since: 0.2
8848  */
8849 void
8850 clutter_actor_set_width (ClutterActor *self,
8851                          gfloat        width)
8852 {
8853   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8854
8855   g_object_freeze_notify (G_OBJECT (self));
8856
8857   clutter_actor_set_width_internal (self, width);
8858
8859   g_object_thaw_notify (G_OBJECT (self));
8860 }
8861
8862 /**
8863  * clutter_actor_set_height:
8864  * @self: A #ClutterActor
8865  * @height: Requested new height for the actor, in pixels, or -1
8866  *
8867  * Forces a height on an actor, causing the actor's preferred width
8868  * and height (if any) to be ignored.
8869  *
8870  * If @height is -1 the actor will use its preferred height instead of
8871  * overriding it, i.e. you can "unset" the height with -1.
8872  *
8873  * This function sets both the minimum and natural size of the actor.
8874  *
8875  * since: 0.2
8876  */
8877 void
8878 clutter_actor_set_height (ClutterActor *self,
8879                           gfloat        height)
8880 {
8881   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8882
8883   g_object_freeze_notify (G_OBJECT (self));
8884
8885   clutter_actor_set_height_internal (self, height);
8886
8887   g_object_thaw_notify (G_OBJECT (self));
8888 }
8889
8890 /**
8891  * clutter_actor_set_x:
8892  * @self: a #ClutterActor
8893  * @x: the actor's position on the X axis
8894  *
8895  * Sets the actor's X coordinate, relative to its parent, in pixels.
8896  *
8897  * Overrides any layout manager and forces a fixed position for
8898  * the actor.
8899  *
8900  * Since: 0.6
8901  */
8902 void
8903 clutter_actor_set_x (ClutterActor *self,
8904                      gfloat        x)
8905 {
8906   ClutterActorBox old = { 0, };
8907   ClutterActorPrivate *priv;
8908   ClutterLayoutInfo *info;
8909
8910   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8911
8912   priv = self->priv;
8913
8914   info = _clutter_actor_get_layout_info (self);
8915
8916   if (priv->position_set && info->fixed_x == x)
8917     return;
8918
8919   clutter_actor_store_old_geometry (self, &old);
8920
8921   info->fixed_x = x;
8922   clutter_actor_set_fixed_position_set (self, TRUE);
8923
8924   clutter_actor_notify_if_geometry_changed (self, &old);
8925
8926   clutter_actor_queue_relayout (self);
8927 }
8928
8929 /**
8930  * clutter_actor_set_y:
8931  * @self: a #ClutterActor
8932  * @y: the actor's position on the Y axis
8933  *
8934  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
8935  *
8936  * Overrides any layout manager and forces a fixed position for
8937  * the actor.
8938  *
8939  * Since: 0.6
8940  */
8941 void
8942 clutter_actor_set_y (ClutterActor *self,
8943                      gfloat        y)
8944 {
8945   ClutterActorBox old = { 0, };
8946   ClutterActorPrivate *priv;
8947   ClutterLayoutInfo *info;
8948
8949   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8950
8951   priv = self->priv;
8952
8953   info = _clutter_actor_get_layout_info (self);
8954
8955   if (priv->position_set && info->fixed_y == y)
8956     return;
8957
8958   clutter_actor_store_old_geometry (self, &old);
8959
8960   info->fixed_y = y;
8961   clutter_actor_set_fixed_position_set (self, TRUE);
8962
8963   clutter_actor_notify_if_geometry_changed (self, &old);
8964
8965   clutter_actor_queue_relayout (self);
8966 }
8967
8968 /**
8969  * clutter_actor_get_x:
8970  * @self: A #ClutterActor
8971  *
8972  * Retrieves the X coordinate of a #ClutterActor.
8973  *
8974  * This function tries to "do what you mean", by returning the
8975  * correct value depending on the actor's state.
8976  *
8977  * If the actor has a valid allocation, this function will return
8978  * the X coordinate of the origin of the allocation box.
8979  *
8980  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
8981  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8982  * function will return that coordinate.
8983  *
8984  * If both the allocation and a fixed position are missing, this function
8985  * will return 0.
8986  *
8987  * Return value: the X coordinate, in pixels, ignoring any
8988  *   transformation (i.e. scaling, rotation)
8989  */
8990 gfloat
8991 clutter_actor_get_x (ClutterActor *self)
8992 {
8993   ClutterActorPrivate *priv;
8994
8995   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8996
8997   priv = self->priv;
8998
8999   if (priv->needs_allocation)
9000     {
9001       if (priv->position_set)
9002         {
9003           const ClutterLayoutInfo *info;
9004
9005           info = _clutter_actor_get_layout_info_or_defaults (self);
9006
9007           return info->fixed_x;
9008         }
9009       else
9010         return 0;
9011     }
9012   else
9013     return priv->allocation.x1;
9014 }
9015
9016 /**
9017  * clutter_actor_get_y:
9018  * @self: A #ClutterActor
9019  *
9020  * Retrieves the Y coordinate of a #ClutterActor.
9021  *
9022  * This function tries to "do what you mean", by returning the
9023  * correct value depending on the actor's state.
9024  *
9025  * If the actor has a valid allocation, this function will return
9026  * the Y coordinate of the origin of the allocation box.
9027  *
9028  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9029  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9030  * function will return that coordinate.
9031  *
9032  * If both the allocation and a fixed position are missing, this function
9033  * will return 0.
9034  *
9035  * Return value: the Y coordinate, in pixels, ignoring any
9036  *   transformation (i.e. scaling, rotation)
9037  */
9038 gfloat
9039 clutter_actor_get_y (ClutterActor *self)
9040 {
9041   ClutterActorPrivate *priv;
9042
9043   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9044
9045   priv = self->priv;
9046
9047   if (priv->needs_allocation)
9048     {
9049       if (priv->position_set)
9050         {
9051           const ClutterLayoutInfo *info;
9052
9053           info = _clutter_actor_get_layout_info_or_defaults (self);
9054
9055           return info->fixed_y;
9056         }
9057       else
9058         return 0;
9059     }
9060   else
9061     return priv->allocation.y1;
9062 }
9063
9064 /**
9065  * clutter_actor_set_scale:
9066  * @self: A #ClutterActor
9067  * @scale_x: double factor to scale actor by horizontally.
9068  * @scale_y: double factor to scale actor by vertically.
9069  *
9070  * Scales an actor with the given factors. The scaling is relative to
9071  * the scale center and the anchor point. The scale center is
9072  * unchanged by this function and defaults to 0,0.
9073  *
9074  * Since: 0.2
9075  */
9076 void
9077 clutter_actor_set_scale (ClutterActor *self,
9078                          gdouble       scale_x,
9079                          gdouble       scale_y)
9080 {
9081   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9082
9083   g_object_freeze_notify (G_OBJECT (self));
9084
9085   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9086   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9087
9088   g_object_thaw_notify (G_OBJECT (self));
9089 }
9090
9091 /**
9092  * clutter_actor_set_scale_full:
9093  * @self: A #ClutterActor
9094  * @scale_x: double factor to scale actor by horizontally.
9095  * @scale_y: double factor to scale actor by vertically.
9096  * @center_x: X coordinate of the center of the scale.
9097  * @center_y: Y coordinate of the center of the scale
9098  *
9099  * Scales an actor with the given factors around the given center
9100  * point. The center point is specified in pixels relative to the
9101  * anchor point (usually the top left corner of the actor).
9102  *
9103  * Since: 1.0
9104  */
9105 void
9106 clutter_actor_set_scale_full (ClutterActor *self,
9107                               gdouble       scale_x,
9108                               gdouble       scale_y,
9109                               gfloat        center_x,
9110                               gfloat        center_y)
9111 {
9112   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9113
9114   g_object_freeze_notify (G_OBJECT (self));
9115
9116   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9117   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9118   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9119   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9120
9121   g_object_thaw_notify (G_OBJECT (self));
9122 }
9123
9124 /**
9125  * clutter_actor_set_scale_with_gravity:
9126  * @self: A #ClutterActor
9127  * @scale_x: double factor to scale actor by horizontally.
9128  * @scale_y: double factor to scale actor by vertically.
9129  * @gravity: the location of the scale center expressed as a compass
9130  * direction.
9131  *
9132  * Scales an actor with the given factors around the given
9133  * center point. The center point is specified as one of the compass
9134  * directions in #ClutterGravity. For example, setting it to north
9135  * will cause the top of the actor to remain unchanged and the rest of
9136  * the actor to expand left, right and downwards.
9137  *
9138  * Since: 1.0
9139  */
9140 void
9141 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9142                                       gdouble         scale_x,
9143                                       gdouble         scale_y,
9144                                       ClutterGravity  gravity)
9145 {
9146   ClutterTransformInfo *info;
9147   GObject *obj;
9148
9149   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9150
9151   obj = G_OBJECT (self);
9152
9153   g_object_freeze_notify (obj);
9154
9155   info = _clutter_actor_get_transform_info (self);
9156   info->scale_x = scale_x;
9157   info->scale_y = scale_y;
9158
9159   if (gravity == CLUTTER_GRAVITY_NONE)
9160     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9161   else
9162     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9163
9164   self->priv->transform_valid = FALSE;
9165
9166   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9167   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9168   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9169   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9170   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9171
9172   clutter_actor_queue_redraw (self);
9173
9174   g_object_thaw_notify (obj);
9175 }
9176
9177 /**
9178  * clutter_actor_get_scale:
9179  * @self: A #ClutterActor
9180  * @scale_x: (out) (allow-none): Location to store horizonal
9181  *   scale factor, or %NULL.
9182  * @scale_y: (out) (allow-none): Location to store vertical
9183  *   scale factor, or %NULL.
9184  *
9185  * Retrieves an actors scale factors.
9186  *
9187  * Since: 0.2
9188  */
9189 void
9190 clutter_actor_get_scale (ClutterActor *self,
9191                          gdouble      *scale_x,
9192                          gdouble      *scale_y)
9193 {
9194   const ClutterTransformInfo *info;
9195
9196   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9197
9198   info = _clutter_actor_get_transform_info_or_defaults (self);
9199
9200   if (scale_x)
9201     *scale_x = info->scale_x;
9202
9203   if (scale_y)
9204     *scale_y = info->scale_y;
9205 }
9206
9207 /**
9208  * clutter_actor_get_scale_center:
9209  * @self: A #ClutterActor
9210  * @center_x: (out) (allow-none): Location to store the X position
9211  *   of the scale center, or %NULL.
9212  * @center_y: (out) (allow-none): Location to store the Y position
9213  *   of the scale center, or %NULL.
9214  *
9215  * Retrieves the scale center coordinate in pixels relative to the top
9216  * left corner of the actor. If the scale center was specified using a
9217  * #ClutterGravity this will calculate the pixel offset using the
9218  * current size of the actor.
9219  *
9220  * Since: 1.0
9221  */
9222 void
9223 clutter_actor_get_scale_center (ClutterActor *self,
9224                                 gfloat       *center_x,
9225                                 gfloat       *center_y)
9226 {
9227   const ClutterTransformInfo *info;
9228
9229   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9230
9231   info = _clutter_actor_get_transform_info_or_defaults (self);
9232
9233   clutter_anchor_coord_get_units (self, &info->scale_center,
9234                                   center_x,
9235                                   center_y,
9236                                   NULL);
9237 }
9238
9239 /**
9240  * clutter_actor_get_scale_gravity:
9241  * @self: A #ClutterActor
9242  *
9243  * Retrieves the scale center as a compass direction. If the scale
9244  * center was specified in pixels or units this will return
9245  * %CLUTTER_GRAVITY_NONE.
9246  *
9247  * Return value: the scale gravity
9248  *
9249  * Since: 1.0
9250  */
9251 ClutterGravity
9252 clutter_actor_get_scale_gravity (ClutterActor *self)
9253 {
9254   const ClutterTransformInfo *info;
9255
9256   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9257
9258   info = _clutter_actor_get_transform_info_or_defaults (self);
9259
9260   return clutter_anchor_coord_get_gravity (&info->scale_center);
9261 }
9262
9263 /**
9264  * clutter_actor_set_opacity:
9265  * @self: A #ClutterActor
9266  * @opacity: New opacity value for the actor.
9267  *
9268  * Sets the actor's opacity, with zero being completely transparent and
9269  * 255 (0xff) being fully opaque.
9270  */
9271 void
9272 clutter_actor_set_opacity (ClutterActor *self,
9273                            guint8        opacity)
9274 {
9275   ClutterActorPrivate *priv;
9276
9277   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9278
9279   priv = self->priv;
9280
9281   if (priv->opacity != opacity)
9282     {
9283       priv->opacity = opacity;
9284
9285       /* Queue a redraw from the flatten effect so that it can use
9286          its cached image if available instead of having to redraw the
9287          actual actor. If it doesn't end up using the FBO then the
9288          effect is still able to continue the paint anyway. If there
9289          is no flatten effect yet then this is equivalent to queueing
9290          a full redraw */
9291       _clutter_actor_queue_redraw_full (self,
9292                                         0, /* flags */
9293                                         NULL, /* clip */
9294                                         priv->flatten_effect);
9295
9296       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9297     }
9298 }
9299
9300 /*
9301  * clutter_actor_get_paint_opacity_internal:
9302  * @self: a #ClutterActor
9303  *
9304  * Retrieves the absolute opacity of the actor, as it appears on the stage
9305  *
9306  * This function does not do type checks
9307  *
9308  * Return value: the absolute opacity of the actor
9309  */
9310 static guint8
9311 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9312 {
9313   ClutterActorPrivate *priv = self->priv;
9314   ClutterActor *parent;
9315
9316   /* override the top-level opacity to always be 255; even in
9317    * case of ClutterStage:use-alpha being TRUE we want the rest
9318    * of the scene to be painted
9319    */
9320   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9321     return 255;
9322
9323   if (priv->opacity_override >= 0)
9324     return priv->opacity_override;
9325
9326   parent = priv->parent;
9327
9328   /* Factor in the actual actors opacity with parents */
9329   if (parent != NULL)
9330     {
9331       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9332
9333       if (opacity != 0xff)
9334         return (opacity * priv->opacity) / 0xff;
9335     }
9336
9337   return priv->opacity;
9338
9339 }
9340
9341 /**
9342  * clutter_actor_get_paint_opacity:
9343  * @self: A #ClutterActor
9344  *
9345  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9346  *
9347  * This function traverses the hierarchy chain and composites the opacity of
9348  * the actor with that of its parents.
9349  *
9350  * This function is intended for subclasses to use in the paint virtual
9351  * function, to paint themselves with the correct opacity.
9352  *
9353  * Return value: The actor opacity value.
9354  *
9355  * Since: 0.8
9356  */
9357 guint8
9358 clutter_actor_get_paint_opacity (ClutterActor *self)
9359 {
9360   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9361
9362   return clutter_actor_get_paint_opacity_internal (self);
9363 }
9364
9365 /**
9366  * clutter_actor_get_opacity:
9367  * @self: a #ClutterActor
9368  *
9369  * Retrieves the opacity value of an actor, as set by
9370  * clutter_actor_set_opacity().
9371  *
9372  * For retrieving the absolute opacity of the actor inside a paint
9373  * virtual function, see clutter_actor_get_paint_opacity().
9374  *
9375  * Return value: the opacity of the actor
9376  */
9377 guint8
9378 clutter_actor_get_opacity (ClutterActor *self)
9379 {
9380   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9381
9382   return self->priv->opacity;
9383 }
9384
9385 /**
9386  * clutter_actor_set_offscreen_redirect:
9387  * @self: A #ClutterActor
9388  * @redirect: New offscreen redirect flags for the actor.
9389  *
9390  * Defines the circumstances where the actor should be redirected into
9391  * an offscreen image. The offscreen image is used to flatten the
9392  * actor into a single image while painting for two main reasons.
9393  * Firstly, when the actor is painted a second time without any of its
9394  * contents changing it can simply repaint the cached image without
9395  * descending further down the actor hierarchy. Secondly, it will make
9396  * the opacity look correct even if there are overlapping primitives
9397  * in the actor.
9398  *
9399  * Caching the actor could in some cases be a performance win and in
9400  * some cases be a performance lose so it is important to determine
9401  * which value is right for an actor before modifying this value. For
9402  * example, there is never any reason to flatten an actor that is just
9403  * a single texture (such as a #ClutterTexture) because it is
9404  * effectively already cached in an image so the offscreen would be
9405  * redundant. Also if the actor contains primitives that are far apart
9406  * with a large transparent area in the middle (such as a large
9407  * CluterGroup with a small actor in the top left and a small actor in
9408  * the bottom right) then the cached image will contain the entire
9409  * image of the large area and the paint will waste time blending all
9410  * of the transparent pixels in the middle.
9411  *
9412  * The default method of implementing opacity on a container simply
9413  * forwards on the opacity to all of the children. If the children are
9414  * overlapping then it will appear as if they are two separate glassy
9415  * objects and there will be a break in the color where they
9416  * overlap. By redirecting to an offscreen buffer it will be as if the
9417  * two opaque objects are combined into one and then made transparent
9418  * which is usually what is expected.
9419  *
9420  * The image below demonstrates the difference between redirecting and
9421  * not. The image shows two Clutter groups, each containing a red and
9422  * a green rectangle which overlap. The opacity on the group is set to
9423  * 128 (which is 50%). When the offscreen redirect is not used, the
9424  * red rectangle can be seen through the blue rectangle as if the two
9425  * rectangles were separately transparent. When the redirect is used
9426  * the group as a whole is transparent instead so the red rectangle is
9427  * not visible where they overlap.
9428  *
9429  * <figure id="offscreen-redirect">
9430  *   <title>Sample of using an offscreen redirect for transparency</title>
9431  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9432  * </figure>
9433  *
9434  * The default value for this property is 0, so we effectively will
9435  * never redirect an actor offscreen by default. This means that there
9436  * are times that transparent actors may look glassy as described
9437  * above. The reason this is the default is because there is a
9438  * performance trade off between quality and performance here. In many
9439  * cases the default form of glassy opacity looks good enough, but if
9440  * it's not you will need to set the
9441  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9442  * redirection for opacity.
9443  *
9444  * Custom actors that don't contain any overlapping primitives are
9445  * recommended to override the has_overlaps() virtual to return %FALSE
9446  * for maximum efficiency.
9447  *
9448  * Since: 1.8
9449  */
9450 void
9451 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9452                                       ClutterOffscreenRedirect redirect)
9453 {
9454   ClutterActorPrivate *priv;
9455
9456   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9457
9458   priv = self->priv;
9459
9460   if (priv->offscreen_redirect != redirect)
9461     {
9462       priv->offscreen_redirect = redirect;
9463
9464       /* Queue a redraw from the effect so that it can use its cached
9465          image if available instead of having to redraw the actual
9466          actor. If it doesn't end up using the FBO then the effect is
9467          still able to continue the paint anyway. If there is no
9468          effect then this is equivalent to queuing a full redraw */
9469       _clutter_actor_queue_redraw_full (self,
9470                                         0, /* flags */
9471                                         NULL, /* clip */
9472                                         priv->flatten_effect);
9473
9474       g_object_notify_by_pspec (G_OBJECT (self),
9475                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9476     }
9477 }
9478
9479 /**
9480  * clutter_actor_get_offscreen_redirect:
9481  * @self: a #ClutterActor
9482  *
9483  * Retrieves whether to redirect the actor to an offscreen buffer, as
9484  * set by clutter_actor_set_offscreen_redirect().
9485  *
9486  * Return value: the value of the offscreen-redirect property of the actor
9487  *
9488  * Since: 1.8
9489  */
9490 ClutterOffscreenRedirect
9491 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9492 {
9493   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9494
9495   return self->priv->offscreen_redirect;
9496 }
9497
9498 /**
9499  * clutter_actor_set_name:
9500  * @self: A #ClutterActor
9501  * @name: Textual tag to apply to actor
9502  *
9503  * Sets the given name to @self. The name can be used to identify
9504  * a #ClutterActor.
9505  */
9506 void
9507 clutter_actor_set_name (ClutterActor *self,
9508                         const gchar  *name)
9509 {
9510   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9511
9512   g_free (self->priv->name);
9513   self->priv->name = g_strdup (name);
9514
9515   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9516 }
9517
9518 /**
9519  * clutter_actor_get_name:
9520  * @self: A #ClutterActor
9521  *
9522  * Retrieves the name of @self.
9523  *
9524  * Return value: the name of the actor, or %NULL. The returned string is
9525  *   owned by the actor and should not be modified or freed.
9526  */
9527 const gchar *
9528 clutter_actor_get_name (ClutterActor *self)
9529 {
9530   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9531
9532   return self->priv->name;
9533 }
9534
9535 /**
9536  * clutter_actor_get_gid:
9537  * @self: A #ClutterActor
9538  *
9539  * Retrieves the unique id for @self.
9540  *
9541  * Return value: Globally unique value for this object instance.
9542  *
9543  * Since: 0.6
9544  *
9545  * Deprecated: 1.8: The id is not used any longer.
9546  */
9547 guint32
9548 clutter_actor_get_gid (ClutterActor *self)
9549 {
9550   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9551
9552   return self->priv->id;
9553 }
9554
9555 /**
9556  * clutter_actor_set_depth:
9557  * @self: a #ClutterActor
9558  * @depth: Z co-ord
9559  *
9560  * Sets the Z coordinate of @self to @depth.
9561  *
9562  * The unit used by @depth is dependant on the perspective setup. See
9563  * also clutter_stage_set_perspective().
9564  */
9565 void
9566 clutter_actor_set_depth (ClutterActor *self,
9567                          gfloat        depth)
9568 {
9569   ClutterActorPrivate *priv;
9570
9571   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9572
9573   priv = self->priv;
9574
9575   if (priv->z != depth)
9576     {
9577       /* Sets Z value - XXX 2.0: should we invert? */
9578       priv->z = depth;
9579
9580       priv->transform_valid = FALSE;
9581
9582       /* FIXME - remove this crap; sadly, there are still containers
9583        * in Clutter that depend on this utter brain damage
9584        */
9585       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9586
9587       clutter_actor_queue_redraw (self);
9588
9589       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9590     }
9591 }
9592
9593 /**
9594  * clutter_actor_get_depth:
9595  * @self: a #ClutterActor
9596  *
9597  * Retrieves the depth of @self.
9598  *
9599  * Return value: the depth of the actor
9600  */
9601 gfloat
9602 clutter_actor_get_depth (ClutterActor *self)
9603 {
9604   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
9605
9606   return self->priv->z;
9607 }
9608
9609 /**
9610  * clutter_actor_set_rotation:
9611  * @self: a #ClutterActor
9612  * @axis: the axis of rotation
9613  * @angle: the angle of rotation
9614  * @x: X coordinate of the rotation center
9615  * @y: Y coordinate of the rotation center
9616  * @z: Z coordinate of the rotation center
9617  *
9618  * Sets the rotation angle of @self around the given axis.
9619  *
9620  * The rotation center coordinates used depend on the value of @axis:
9621  * <itemizedlist>
9622  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
9623  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
9624  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
9625  * </itemizedlist>
9626  *
9627  * The rotation coordinates are relative to the anchor point of the
9628  * actor, set using clutter_actor_set_anchor_point(). If no anchor
9629  * point is set, the upper left corner is assumed as the origin.
9630  *
9631  * Since: 0.8
9632  */
9633 void
9634 clutter_actor_set_rotation (ClutterActor      *self,
9635                             ClutterRotateAxis  axis,
9636                             gdouble            angle,
9637                             gfloat             x,
9638                             gfloat             y,
9639                             gfloat             z)
9640 {
9641   ClutterVertex v;
9642
9643   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9644
9645   v.x = x;
9646   v.y = y;
9647   v.z = z;
9648
9649   g_object_freeze_notify (G_OBJECT (self));
9650
9651   clutter_actor_set_rotation_angle_internal (self, axis, angle);
9652   clutter_actor_set_rotation_center_internal (self, axis, &v);
9653
9654   g_object_thaw_notify (G_OBJECT (self));
9655 }
9656
9657 /**
9658  * clutter_actor_set_z_rotation_from_gravity:
9659  * @self: a #ClutterActor
9660  * @angle: the angle of rotation
9661  * @gravity: the center point of the rotation
9662  *
9663  * Sets the rotation angle of @self around the Z axis using the center
9664  * point specified as a compass point. For example to rotate such that
9665  * the center of the actor remains static you can use
9666  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
9667  * will move accordingly.
9668  *
9669  * Since: 1.0
9670  */
9671 void
9672 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
9673                                            gdouble         angle,
9674                                            ClutterGravity  gravity)
9675 {
9676   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9677
9678   if (gravity == CLUTTER_GRAVITY_NONE)
9679     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
9680   else
9681     {
9682       GObject *obj = G_OBJECT (self);
9683       ClutterTransformInfo *info;
9684
9685       info = _clutter_actor_get_transform_info (self);
9686
9687       g_object_freeze_notify (obj);
9688
9689       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
9690
9691       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
9692       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
9693       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
9694
9695       g_object_thaw_notify (obj);
9696     }
9697 }
9698
9699 /**
9700  * clutter_actor_get_rotation:
9701  * @self: a #ClutterActor
9702  * @axis: the axis of rotation
9703  * @x: (out): return value for the X coordinate of the center of rotation
9704  * @y: (out): return value for the Y coordinate of the center of rotation
9705  * @z: (out): return value for the Z coordinate of the center of rotation
9706  *
9707  * Retrieves the angle and center of rotation on the given axis,
9708  * set using clutter_actor_set_rotation().
9709  *
9710  * Return value: the angle of rotation
9711  *
9712  * Since: 0.8
9713  */
9714 gdouble
9715 clutter_actor_get_rotation (ClutterActor      *self,
9716                             ClutterRotateAxis  axis,
9717                             gfloat            *x,
9718                             gfloat            *y,
9719                             gfloat            *z)
9720 {
9721   const ClutterTransformInfo *info;
9722   const AnchorCoord *anchor_coord;
9723   gdouble retval = 0;
9724
9725   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9726
9727   info = _clutter_actor_get_transform_info_or_defaults (self);
9728
9729   switch (axis)
9730     {
9731     case CLUTTER_X_AXIS:
9732       anchor_coord = &info->rx_center;
9733       retval = info->rx_angle;
9734       break;
9735
9736     case CLUTTER_Y_AXIS:
9737       anchor_coord = &info->ry_center;
9738       retval = info->ry_angle;
9739       break;
9740
9741     case CLUTTER_Z_AXIS:
9742       anchor_coord = &info->rz_center;
9743       retval = info->rz_angle;
9744       break;
9745
9746     default:
9747       anchor_coord = NULL;
9748       retval = 0.0;
9749       break;
9750     }
9751
9752   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
9753
9754   return retval;
9755 }
9756
9757 /**
9758  * clutter_actor_get_z_rotation_gravity:
9759  * @self: A #ClutterActor
9760  *
9761  * Retrieves the center for the rotation around the Z axis as a
9762  * compass direction. If the center was specified in pixels or units
9763  * this will return %CLUTTER_GRAVITY_NONE.
9764  *
9765  * Return value: the Z rotation center
9766  *
9767  * Since: 1.0
9768  */
9769 ClutterGravity
9770 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
9771 {
9772   const ClutterTransformInfo *info;
9773
9774   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9775
9776   info = _clutter_actor_get_transform_info_or_defaults (self);
9777
9778   return clutter_anchor_coord_get_gravity (&info->rz_center);
9779 }
9780
9781 /**
9782  * clutter_actor_set_clip:
9783  * @self: A #ClutterActor
9784  * @xoff: X offset of the clip rectangle
9785  * @yoff: Y offset of the clip rectangle
9786  * @width: Width of the clip rectangle
9787  * @height: Height of the clip rectangle
9788  *
9789  * Sets clip area for @self. The clip area is always computed from the
9790  * upper left corner of the actor, even if the anchor point is set
9791  * otherwise.
9792  *
9793  * Since: 0.6
9794  */
9795 void
9796 clutter_actor_set_clip (ClutterActor *self,
9797                         gfloat        xoff,
9798                         gfloat        yoff,
9799                         gfloat        width,
9800                         gfloat        height)
9801 {
9802   ClutterActorPrivate *priv;
9803
9804   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9805
9806   priv = self->priv;
9807
9808   if (priv->has_clip &&
9809       priv->clip.x == xoff &&
9810       priv->clip.y == yoff &&
9811       priv->clip.width == width &&
9812       priv->clip.height == height)
9813     return;
9814
9815   priv->clip.x = xoff;
9816   priv->clip.y = yoff;
9817   priv->clip.width = width;
9818   priv->clip.height = height;
9819
9820   priv->has_clip = TRUE;
9821
9822   clutter_actor_queue_redraw (self);
9823
9824   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9825   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
9826 }
9827
9828 /**
9829  * clutter_actor_remove_clip:
9830  * @self: A #ClutterActor
9831  *
9832  * Removes clip area from @self.
9833  */
9834 void
9835 clutter_actor_remove_clip (ClutterActor *self)
9836 {
9837   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9838
9839   if (!self->priv->has_clip)
9840     return;
9841
9842   self->priv->has_clip = FALSE;
9843
9844   clutter_actor_queue_redraw (self);
9845
9846   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9847 }
9848
9849 /**
9850  * clutter_actor_has_clip:
9851  * @self: a #ClutterActor
9852  *
9853  * Determines whether the actor has a clip area set or not.
9854  *
9855  * Return value: %TRUE if the actor has a clip area set.
9856  *
9857  * Since: 0.1.1
9858  */
9859 gboolean
9860 clutter_actor_has_clip (ClutterActor *self)
9861 {
9862   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9863
9864   return self->priv->has_clip;
9865 }
9866
9867 /**
9868  * clutter_actor_get_clip:
9869  * @self: a #ClutterActor
9870  * @xoff: (out) (allow-none): return location for the X offset of
9871  *   the clip rectangle, or %NULL
9872  * @yoff: (out) (allow-none): return location for the Y offset of
9873  *   the clip rectangle, or %NULL
9874  * @width: (out) (allow-none): return location for the width of
9875  *   the clip rectangle, or %NULL
9876  * @height: (out) (allow-none): return location for the height of
9877  *   the clip rectangle, or %NULL
9878  *
9879  * Gets the clip area for @self, if any is set
9880  *
9881  * Since: 0.6
9882  */
9883 void
9884 clutter_actor_get_clip (ClutterActor *self,
9885                         gfloat       *xoff,
9886                         gfloat       *yoff,
9887                         gfloat       *width,
9888                         gfloat       *height)
9889 {
9890   ClutterActorPrivate *priv;
9891
9892   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9893
9894   priv = self->priv;
9895
9896   if (!priv->has_clip)
9897     return;
9898
9899   if (xoff != NULL)
9900     *xoff = priv->clip.x;
9901
9902   if (yoff != NULL)
9903     *yoff = priv->clip.y;
9904
9905   if (width != NULL)
9906     *width = priv->clip.width;
9907
9908   if (height != NULL)
9909     *height = priv->clip.height;
9910 }
9911
9912 /**
9913  * clutter_actor_get_children:
9914  * @self: a #ClutterActor
9915  *
9916  * Retrieves the list of children of @self.
9917  *
9918  * Return value: (transfer container) (element-type ClutterActor): A newly
9919  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
9920  *   done.
9921  *
9922  * Since: 1.10
9923  */
9924 GList *
9925 clutter_actor_get_children (ClutterActor *self)
9926 {
9927   ClutterActor *iter;
9928   GList *res;
9929
9930   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9931
9932   /* we walk the list backward so that we can use prepend(),
9933    * which is O(1)
9934    */
9935   for (iter = self->priv->last_child, res = NULL;
9936        iter != NULL;
9937        iter = iter->priv->prev_sibling)
9938     {
9939       res = g_list_prepend (res, iter);
9940     }
9941
9942   return res;
9943 }
9944
9945 /*< private >
9946  * insert_child_at_depth:
9947  * @self: a #ClutterActor
9948  * @child: a #ClutterActor
9949  *
9950  * Inserts @child inside the list of children held by @self, using
9951  * the depth as the insertion criteria.
9952  *
9953  * This sadly makes the insertion not O(1), but we can keep the
9954  * list sorted so that the painters algorithm we use for painting
9955  * the children will work correctly.
9956  */
9957 static void
9958 insert_child_at_depth (ClutterActor *self,
9959                        ClutterActor *child,
9960                        gpointer      dummy G_GNUC_UNUSED)
9961 {
9962   ClutterActor *iter;
9963
9964   child->priv->parent = self;
9965
9966   /* special-case the first child */
9967   if (self->priv->n_children == 0)
9968     {
9969       self->priv->first_child = child;
9970       self->priv->last_child = child;
9971
9972       child->priv->next_sibling = NULL;
9973       child->priv->prev_sibling = NULL;
9974
9975       return;
9976     }
9977
9978   /* Find the right place to insert the child so that it will still be
9979      sorted and the child will be after all of the actors at the same
9980      dept */
9981   for (iter = self->priv->first_child;
9982        iter != NULL;
9983        iter = iter->priv->next_sibling)
9984     {
9985       if (iter->priv->z > child->priv->z)
9986         break;
9987     }
9988
9989   if (iter != NULL)
9990     {
9991       ClutterActor *tmp = iter->priv->prev_sibling;
9992
9993       if (tmp != NULL)
9994         tmp->priv->next_sibling = child;
9995
9996       /* Insert the node before the found one */
9997       child->priv->prev_sibling = iter->priv->prev_sibling;
9998       child->priv->next_sibling = iter;
9999       iter->priv->prev_sibling = child;
10000     }
10001   else
10002     {
10003       ClutterActor *tmp = self->priv->last_child;
10004
10005       if (tmp != NULL)
10006         tmp->priv->next_sibling = child;
10007
10008       /* insert the node at the end of the list */
10009       child->priv->prev_sibling = self->priv->last_child;
10010       child->priv->next_sibling = NULL;
10011     }
10012
10013   if (child->priv->prev_sibling == NULL)
10014     self->priv->first_child = child;
10015
10016   if (child->priv->next_sibling == NULL)
10017     self->priv->last_child = child;
10018 }
10019
10020 static void
10021 insert_child_at_index (ClutterActor *self,
10022                        ClutterActor *child,
10023                        gpointer      data_)
10024 {
10025   gint index_ = GPOINTER_TO_INT (data_);
10026
10027   child->priv->parent = self;
10028
10029   if (index_ == 0)
10030     {
10031       ClutterActor *tmp = self->priv->first_child;
10032
10033       if (tmp != NULL)
10034         tmp->priv->prev_sibling = child;
10035
10036       child->priv->prev_sibling = NULL;
10037       child->priv->next_sibling = tmp;
10038     }
10039   else if (index_ < 0 || index_ >= self->priv->n_children)
10040     {
10041       ClutterActor *tmp = self->priv->last_child;
10042
10043       if (tmp != NULL)
10044         tmp->priv->next_sibling = child;
10045
10046       child->priv->prev_sibling = tmp;
10047       child->priv->next_sibling = NULL;
10048     }
10049   else
10050     {
10051       ClutterActor *iter;
10052       int i;
10053
10054       for (iter = self->priv->first_child, i = 0;
10055            iter != NULL;
10056            iter = iter->priv->next_sibling, i += 1)
10057         {
10058           if (index_ == i)
10059             {
10060               ClutterActor *tmp = iter->priv->prev_sibling;
10061
10062               child->priv->prev_sibling = tmp;
10063               child->priv->next_sibling = iter;
10064
10065               iter->priv->prev_sibling = child;
10066
10067               if (tmp != NULL)
10068                 tmp->priv->next_sibling = child;
10069
10070               break;
10071             }
10072         }
10073     }
10074
10075   if (child->priv->prev_sibling == NULL)
10076     self->priv->first_child = child;
10077
10078   if (child->priv->next_sibling == NULL)
10079     self->priv->last_child = child;
10080 }
10081
10082 static void
10083 insert_child_above (ClutterActor *self,
10084                     ClutterActor *child,
10085                     gpointer      data)
10086 {
10087   ClutterActor *sibling = data;
10088
10089   child->priv->parent = self;
10090
10091   if (sibling == NULL)
10092     sibling = self->priv->last_child;
10093
10094   child->priv->prev_sibling = sibling;
10095
10096   if (sibling != NULL)
10097     {
10098       ClutterActor *tmp = sibling->priv->next_sibling;
10099
10100       child->priv->next_sibling = tmp;
10101
10102       if (tmp != NULL)
10103         tmp->priv->prev_sibling = child;
10104
10105       sibling->priv->next_sibling = child;
10106     }
10107   else
10108     child->priv->next_sibling = NULL;
10109
10110   if (child->priv->prev_sibling == NULL)
10111     self->priv->first_child = child;
10112
10113   if (child->priv->next_sibling == NULL)
10114     self->priv->last_child = child;
10115 }
10116
10117 static void
10118 insert_child_below (ClutterActor *self,
10119                     ClutterActor *child,
10120                     gpointer      data)
10121 {
10122   ClutterActor *sibling = data;
10123
10124   child->priv->parent = self;
10125
10126   if (sibling == NULL)
10127     sibling = self->priv->first_child;
10128
10129   child->priv->next_sibling = sibling;
10130
10131   if (sibling != NULL)
10132     {
10133       ClutterActor *tmp = sibling->priv->prev_sibling;
10134
10135       child->priv->prev_sibling = tmp;
10136
10137       if (tmp != NULL)
10138         tmp->priv->next_sibling = child;
10139
10140       sibling->priv->prev_sibling = child;
10141     }
10142   else
10143     child->priv->prev_sibling = NULL;
10144
10145   if (child->priv->prev_sibling == NULL)
10146     self->priv->first_child = child;
10147
10148   if (child->priv->next_sibling == NULL)
10149     self->priv->last_child = child;
10150 }
10151
10152 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10153                                            ClutterActor *child,
10154                                            gpointer      data);
10155
10156 typedef enum {
10157   ADD_CHILD_CREATE_META       = 1 << 0,
10158   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10159   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10160   ADD_CHILD_CHECK_STATE       = 1 << 3,
10161   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10162
10163   /* default flags for public API */
10164   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10165                                ADD_CHILD_EMIT_PARENT_SET |
10166                                ADD_CHILD_EMIT_ACTOR_ADDED |
10167                                ADD_CHILD_CHECK_STATE |
10168                                ADD_CHILD_NOTIFY_FIRST_LAST,
10169
10170   /* flags for legacy/deprecated API */
10171   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10172                                ADD_CHILD_CHECK_STATE |
10173                                ADD_CHILD_NOTIFY_FIRST_LAST
10174 } ClutterActorAddChildFlags;
10175
10176 /*< private >
10177  * clutter_actor_add_child_internal:
10178  * @self: a #ClutterActor
10179  * @child: a #ClutterActor
10180  * @flags: control flags for actions
10181  * @add_func: delegate function
10182  * @data: (closure): data to pass to @add_func
10183  *
10184  * Adds @child to the list of children of @self.
10185  *
10186  * The actual insertion inside the list is delegated to @add_func: this
10187  * function will just set up the state, perform basic checks, and emit
10188  * signals.
10189  *
10190  * The @flags argument is used to perform additional operations.
10191  */
10192 static inline void
10193 clutter_actor_add_child_internal (ClutterActor              *self,
10194                                   ClutterActor              *child,
10195                                   ClutterActorAddChildFlags  flags,
10196                                   ClutterActorAddChildFunc   add_func,
10197                                   gpointer                   data)
10198 {
10199   ClutterTextDirection text_dir;
10200   gboolean create_meta;
10201   gboolean emit_parent_set, emit_actor_added;
10202   gboolean check_state;
10203   gboolean notify_first_last;
10204   ClutterActor *old_first_child, *old_last_child;
10205
10206   if (child->priv->parent != NULL)
10207     {
10208       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10209                  "use clutter_actor_remove_child() first.",
10210                  _clutter_actor_get_debug_name (child),
10211                  _clutter_actor_get_debug_name (child->priv->parent));
10212       return;
10213     }
10214
10215   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10216     {
10217       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10218                  "a child of another actor.",
10219                  _clutter_actor_get_debug_name (child));
10220       return;
10221     }
10222
10223 #if 0
10224   /* XXX - this check disallows calling methods that change the stacking
10225    * order within the destruction sequence, by triggering a critical
10226    * warning first, and leaving the actor in an undefined state, which
10227    * then ends up being caught by an assertion.
10228    *
10229    * the reproducible sequence is:
10230    *
10231    *   - actor gets destroyed;
10232    *   - another actor, linked to the first, will try to change the
10233    *     stacking order of the first actor;
10234    *   - changing the stacking order is a composite operation composed
10235    *     by the following steps:
10236    *     1. ref() the child;
10237    *     2. remove_child_internal(), which removes the reference;
10238    *     3. add_child_internal(), which adds a reference;
10239    *   - the state of the actor is not changed between (2) and (3), as
10240    *     it could be an expensive recomputation;
10241    *   - if (3) bails out, then the actor is in an undefined state, but
10242    *     still alive;
10243    *   - the destruction sequence terminates, but the actor is unparented
10244    *     while its state indicates being parented instead.
10245    *   - assertion failure.
10246    *
10247    * the obvious fix would be to decompose each set_child_*_sibling()
10248    * method into proper remove_child()/add_child(), with state validation;
10249    * this may cause excessive work, though, and trigger a cascade of other
10250    * bugs in code that assumes that a change in the stacking order is an
10251    * atomic operation.
10252    *
10253    * another potential fix is to just remove this check here, and let
10254    * code doing stacking order changes inside the destruction sequence
10255    * of an actor continue doing the work.
10256    *
10257    * the third fix is to silently bail out early from every
10258    * set_child_*_sibling() and set_child_at_index() method, and avoid
10259    * doing work.
10260    *
10261    * I have a preference for the second solution, since it involves the
10262    * least amount of work, and the least amount of code duplication.
10263    *
10264    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10265    */
10266   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10267     {
10268       g_warning ("The actor '%s' is currently being destroyed, and "
10269                  "cannot be added as a child of another actor.",
10270                  _clutter_actor_get_debug_name (child));
10271       return;
10272     }
10273 #endif
10274
10275   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10276   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10277   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10278   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10279   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10280
10281   old_first_child = self->priv->first_child;
10282   old_last_child = self->priv->last_child;
10283
10284   g_object_freeze_notify (G_OBJECT (self));
10285
10286   if (create_meta)
10287     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10288
10289   g_object_ref_sink (child);
10290   child->priv->parent = NULL;
10291   child->priv->next_sibling = NULL;
10292   child->priv->prev_sibling = NULL;
10293
10294   /* delegate the actual insertion */
10295   add_func (self, child, data);
10296
10297   g_assert (child->priv->parent == self);
10298
10299   self->priv->n_children += 1;
10300
10301   self->priv->age += 1;
10302
10303   /* if push_internal() has been called then we automatically set
10304    * the flag on the actor
10305    */
10306   if (self->priv->internal_child)
10307     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10308
10309   /* clutter_actor_reparent() will emit ::parent-set for us */
10310   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10311     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10312
10313   if (check_state)
10314     {
10315       /* If parent is mapped or realized, we need to also be mapped or
10316        * realized once we're inside the parent.
10317        */
10318       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10319
10320       /* propagate the parent's text direction to the child */
10321       text_dir = clutter_actor_get_text_direction (self);
10322       clutter_actor_set_text_direction (child, text_dir);
10323     }
10324
10325   if (child->priv->show_on_set_parent)
10326     clutter_actor_show (child);
10327
10328   if (CLUTTER_ACTOR_IS_MAPPED (child))
10329     clutter_actor_queue_redraw (child);
10330
10331   /* maintain the invariant that if an actor needs layout,
10332    * its parents do as well
10333    */
10334   if (child->priv->needs_width_request ||
10335       child->priv->needs_height_request ||
10336       child->priv->needs_allocation)
10337     {
10338       /* we work around the short-circuiting we do
10339        * in clutter_actor_queue_relayout() since we
10340        * want to force a relayout
10341        */
10342       child->priv->needs_width_request = TRUE;
10343       child->priv->needs_height_request = TRUE;
10344       child->priv->needs_allocation = TRUE;
10345
10346       clutter_actor_queue_relayout (child->priv->parent);
10347     }
10348
10349   if (emit_actor_added)
10350     g_signal_emit_by_name (self, "actor-added", child);
10351
10352   if (notify_first_last)
10353     {
10354       if (old_first_child != self->priv->first_child)
10355         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10356
10357       if (old_last_child != self->priv->last_child)
10358         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10359     }
10360
10361   g_object_thaw_notify (G_OBJECT (self));
10362 }
10363
10364 /**
10365  * clutter_actor_add_child:
10366  * @self: a #ClutterActor
10367  * @child: a #ClutterActor
10368  *
10369  * Adds @child to the children of @self.
10370  *
10371  * This function will acquire a reference on @child that will only
10372  * be released when calling clutter_actor_remove_child().
10373  *
10374  * This function will take into consideration the #ClutterActor:depth
10375  * of @child, and will keep the list of children sorted.
10376  *
10377  * This function will emit the #ClutterContainer::actor-added signal
10378  * on @self.
10379  *
10380  * Since: 1.10
10381  */
10382 void
10383 clutter_actor_add_child (ClutterActor *self,
10384                          ClutterActor *child)
10385 {
10386   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10387   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10388   g_return_if_fail (self != child);
10389   g_return_if_fail (child->priv->parent == NULL);
10390
10391   clutter_actor_add_child_internal (self, child,
10392                                     ADD_CHILD_DEFAULT_FLAGS,
10393                                     insert_child_at_depth,
10394                                     NULL);
10395 }
10396
10397 /**
10398  * clutter_actor_insert_child_at_index:
10399  * @self: a #ClutterActor
10400  * @child: a #ClutterActor
10401  * @index_: the index
10402  *
10403  * Inserts @child into the list of children of @self, using the
10404  * given @index_. If @index_ is greater than the number of children
10405  * in @self, or is less than 0, then the new child is added at the end.
10406  *
10407  * This function will acquire a reference on @child that will only
10408  * be released when calling clutter_actor_remove_child().
10409  *
10410  * This function will not take into consideration the #ClutterActor:depth
10411  * of @child.
10412  *
10413  * This function will emit the #ClutterContainer::actor-added signal
10414  * on @self.
10415  *
10416  * Since: 1.10
10417  */
10418 void
10419 clutter_actor_insert_child_at_index (ClutterActor *self,
10420                                      ClutterActor *child,
10421                                      gint          index_)
10422 {
10423   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10424   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10425   g_return_if_fail (self != child);
10426   g_return_if_fail (child->priv->parent == NULL);
10427
10428   clutter_actor_add_child_internal (self, child,
10429                                     ADD_CHILD_DEFAULT_FLAGS,
10430                                     insert_child_at_index,
10431                                     GINT_TO_POINTER (index_));
10432 }
10433
10434 /**
10435  * clutter_actor_insert_child_above:
10436  * @self: a #ClutterActor
10437  * @child: a #ClutterActor
10438  * @sibling: (allow-none): a child of @self, or %NULL
10439  *
10440  * Inserts @child into the list of children of @self, above another
10441  * child of @self or, if @sibling is %NULL, above all the children
10442  * of @self.
10443  *
10444  * This function will acquire a reference on @child that will only
10445  * be released when calling clutter_actor_remove_child().
10446  *
10447  * This function will not take into consideration the #ClutterActor:depth
10448  * of @child.
10449  *
10450  * This function will emit the #ClutterContainer::actor-added signal
10451  * on @self.
10452  *
10453  * Since: 1.10
10454  */
10455 void
10456 clutter_actor_insert_child_above (ClutterActor *self,
10457                                   ClutterActor *child,
10458                                   ClutterActor *sibling)
10459 {
10460   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10461   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10462   g_return_if_fail (self != child);
10463   g_return_if_fail (child != sibling);
10464   g_return_if_fail (child->priv->parent == NULL);
10465   g_return_if_fail (sibling == NULL ||
10466                     (CLUTTER_IS_ACTOR (sibling) &&
10467                      sibling->priv->parent == self));
10468
10469   clutter_actor_add_child_internal (self, child,
10470                                     ADD_CHILD_DEFAULT_FLAGS,
10471                                     insert_child_above,
10472                                     sibling);
10473 }
10474
10475 /**
10476  * clutter_actor_insert_child_below:
10477  * @self: a #ClutterActor
10478  * @child: a #ClutterActor
10479  * @sibling: (allow-none): a child of @self, or %NULL
10480  *
10481  * Inserts @child into the list of children of @self, below another
10482  * child of @self or, if @sibling is %NULL, below all the children
10483  * of @self.
10484  *
10485  * This function will acquire a reference on @child that will only
10486  * be released when calling clutter_actor_remove_child().
10487  *
10488  * This function will not take into consideration the #ClutterActor:depth
10489  * of @child.
10490  *
10491  * This function will emit the #ClutterContainer::actor-added signal
10492  * on @self.
10493  *
10494  * Since: 1.10
10495  */
10496 void
10497 clutter_actor_insert_child_below (ClutterActor *self,
10498                                   ClutterActor *child,
10499                                   ClutterActor *sibling)
10500 {
10501   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10502   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10503   g_return_if_fail (self != child);
10504   g_return_if_fail (child != sibling);
10505   g_return_if_fail (child->priv->parent == NULL);
10506   g_return_if_fail (sibling == NULL ||
10507                     (CLUTTER_IS_ACTOR (sibling) &&
10508                      sibling->priv->parent == self));
10509
10510   clutter_actor_add_child_internal (self, child,
10511                                     ADD_CHILD_DEFAULT_FLAGS,
10512                                     insert_child_below,
10513                                     sibling);
10514 }
10515
10516 /**
10517  * clutter_actor_set_parent:
10518  * @self: A #ClutterActor
10519  * @parent: A new #ClutterActor parent
10520  *
10521  * Sets the parent of @self to @parent.
10522  *
10523  * This function will result in @parent acquiring a reference on @self,
10524  * eventually by sinking its floating reference first. The reference
10525  * will be released by clutter_actor_unparent().
10526  *
10527  * This function should only be called by legacy #ClutterActor<!-- -->s
10528  * implementing the #ClutterContainer interface.
10529  *
10530  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10531  */
10532 void
10533 clutter_actor_set_parent (ClutterActor *self,
10534                           ClutterActor *parent)
10535 {
10536   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10537   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10538   g_return_if_fail (self != parent);
10539   g_return_if_fail (self->priv->parent == NULL);
10540
10541   /* as this function will be called inside ClutterContainer::add
10542    * implementations or when building up a composite actor, we have
10543    * to preserve the old behaviour, and not create child meta or
10544    * emit the ::actor-added signal, to avoid recursion or double
10545    * emissions
10546    */
10547   clutter_actor_add_child_internal (parent, self,
10548                                     ADD_CHILD_LEGACY_FLAGS,
10549                                     insert_child_at_depth,
10550                                     NULL);
10551 }
10552
10553 /**
10554  * clutter_actor_get_parent:
10555  * @self: A #ClutterActor
10556  *
10557  * Retrieves the parent of @self.
10558  *
10559  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10560  *  if no parent is set
10561  */
10562 ClutterActor *
10563 clutter_actor_get_parent (ClutterActor *self)
10564 {
10565   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10566
10567   return self->priv->parent;
10568 }
10569
10570 /**
10571  * clutter_actor_get_paint_visibility:
10572  * @self: A #ClutterActor
10573  *
10574  * Retrieves the 'paint' visibility of an actor recursively checking for non
10575  * visible parents.
10576  *
10577  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10578  *
10579  * Return Value: %TRUE if the actor is visibile and will be painted.
10580  *
10581  * Since: 0.8.4
10582  */
10583 gboolean
10584 clutter_actor_get_paint_visibility (ClutterActor *actor)
10585 {
10586   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10587
10588   return CLUTTER_ACTOR_IS_MAPPED (actor);
10589 }
10590
10591 /**
10592  * clutter_actor_remove_child:
10593  * @self: a #ClutterActor
10594  * @child: a #ClutterActor
10595  *
10596  * Removes @child from the children of @self.
10597  *
10598  * This function will release the reference added by
10599  * clutter_actor_add_child(), so if you want to keep using @child
10600  * you will have to acquire a referenced on it before calling this
10601  * function.
10602  *
10603  * This function will emit the #ClutterContainer::actor-removed
10604  * signal on @self.
10605  *
10606  * Since: 1.10
10607  */
10608 void
10609 clutter_actor_remove_child (ClutterActor *self,
10610                             ClutterActor *child)
10611 {
10612   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10613   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10614   g_return_if_fail (self != child);
10615   g_return_if_fail (child->priv->parent != NULL);
10616   g_return_if_fail (child->priv->parent == self);
10617
10618   clutter_actor_remove_child_internal (self, child,
10619                                        REMOVE_CHILD_DEFAULT_FLAGS);
10620 }
10621
10622 /**
10623  * clutter_actor_remove_all_children:
10624  * @self: a #ClutterActor
10625  *
10626  * Removes all children of @self.
10627  *
10628  * This function releases the reference added by inserting a child actor
10629  * in the list of children of @self.
10630  *
10631  * If the reference count of a child drops to zero, the child will be
10632  * destroyed. If you want to ensure the destruction of all the children
10633  * of @self, use clutter_actor_destroy_all_children().
10634  *
10635  * Since: 1.10
10636  */
10637 void
10638 clutter_actor_remove_all_children (ClutterActor *self)
10639 {
10640   ClutterActorIter iter;
10641
10642   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10643
10644   if (self->priv->n_children == 0)
10645     return;
10646
10647   g_object_freeze_notify (G_OBJECT (self));
10648
10649   clutter_actor_iter_init (&iter, self);
10650   while (clutter_actor_iter_next (&iter, NULL))
10651     clutter_actor_iter_remove (&iter);
10652
10653   g_object_thaw_notify (G_OBJECT (self));
10654
10655   /* sanity check */
10656   g_assert (self->priv->first_child == NULL);
10657   g_assert (self->priv->last_child == NULL);
10658   g_assert (self->priv->n_children == 0);
10659 }
10660
10661 /**
10662  * clutter_actor_destroy_all_children:
10663  * @self: a #ClutterActor
10664  *
10665  * Destroys all children of @self.
10666  *
10667  * This function releases the reference added by inserting a child
10668  * actor in the list of children of @self, and ensures that the
10669  * #ClutterActor::destroy signal is emitted on each child of the
10670  * actor.
10671  *
10672  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
10673  * when its reference count drops to 0; the default handler of the
10674  * #ClutterActor::destroy signal will destroy all the children of an
10675  * actor. This function ensures that all children are destroyed, instead
10676  * of just removed from @self, unlike clutter_actor_remove_all_children()
10677  * which will merely release the reference and remove each child.
10678  *
10679  * Unless you acquired an additional reference on each child of @self
10680  * prior to calling clutter_actor_remove_all_children() and want to reuse
10681  * the actors, you should use clutter_actor_destroy_all_children() in
10682  * order to make sure that children are destroyed and signal handlers
10683  * are disconnected even in cases where circular references prevent this
10684  * from automatically happening through reference counting alone.
10685  *
10686  * Since: 1.10
10687  */
10688 void
10689 clutter_actor_destroy_all_children (ClutterActor *self)
10690 {
10691   ClutterActorIter iter;
10692
10693   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10694
10695   if (self->priv->n_children == 0)
10696     return;
10697
10698   g_object_freeze_notify (G_OBJECT (self));
10699
10700   clutter_actor_iter_init (&iter, self);
10701   while (clutter_actor_iter_next (&iter, NULL))
10702     clutter_actor_iter_destroy (&iter);
10703
10704   g_object_thaw_notify (G_OBJECT (self));
10705
10706   /* sanity check */
10707   g_assert (self->priv->first_child == NULL);
10708   g_assert (self->priv->last_child == NULL);
10709   g_assert (self->priv->n_children == 0);
10710 }
10711
10712 typedef struct _InsertBetweenData {
10713   ClutterActor *prev_sibling;
10714   ClutterActor *next_sibling;
10715 } InsertBetweenData;
10716
10717 static void
10718 insert_child_between (ClutterActor *self,
10719                       ClutterActor *child,
10720                       gpointer      data_)
10721 {
10722   InsertBetweenData *data = data_;
10723   ClutterActor *prev_sibling = data->prev_sibling;
10724   ClutterActor *next_sibling = data->next_sibling;
10725
10726   child->priv->parent = self;
10727   child->priv->prev_sibling = prev_sibling;
10728   child->priv->next_sibling = next_sibling;
10729
10730   if (prev_sibling != NULL)
10731     prev_sibling->priv->next_sibling = child;
10732
10733   if (next_sibling != NULL)
10734     next_sibling->priv->prev_sibling = child;
10735
10736   if (child->priv->prev_sibling == NULL)
10737     self->priv->first_child = child;
10738
10739   if (child->priv->next_sibling == NULL)
10740     self->priv->last_child = child;
10741 }
10742
10743 /**
10744  * clutter_actor_replace_child:
10745  * @self: a #ClutterActor
10746  * @old_child: the child of @self to replace
10747  * @new_child: the #ClutterActor to replace @old_child
10748  *
10749  * Replaces @old_child with @new_child in the list of children of @self.
10750  *
10751  * Since: 1.10
10752  */
10753 void
10754 clutter_actor_replace_child (ClutterActor *self,
10755                              ClutterActor *old_child,
10756                              ClutterActor *new_child)
10757 {
10758   ClutterActor *prev_sibling, *next_sibling;
10759   InsertBetweenData clos;
10760
10761   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10762   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
10763   g_return_if_fail (old_child->priv->parent == self);
10764   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
10765   g_return_if_fail (old_child != new_child);
10766   g_return_if_fail (new_child != self);
10767   g_return_if_fail (new_child->priv->parent == NULL);
10768
10769   prev_sibling = old_child->priv->prev_sibling;
10770   next_sibling = old_child->priv->next_sibling;
10771   clutter_actor_remove_child_internal (self, old_child,
10772                                        REMOVE_CHILD_DEFAULT_FLAGS);
10773
10774   clos.prev_sibling = prev_sibling;
10775   clos.next_sibling = next_sibling;
10776   clutter_actor_add_child_internal (self, new_child,
10777                                     ADD_CHILD_DEFAULT_FLAGS,
10778                                     insert_child_between,
10779                                     &clos);
10780 }
10781
10782 /**
10783  * clutter_actor_unparent:
10784  * @self: a #ClutterActor
10785  *
10786  * Removes the parent of @self.
10787  *
10788  * This will cause the parent of @self to release the reference
10789  * acquired when calling clutter_actor_set_parent(), so if you
10790  * want to keep @self you will have to acquire a reference of
10791  * your own, through g_object_ref().
10792  *
10793  * This function should only be called by legacy #ClutterActor<!-- -->s
10794  * implementing the #ClutterContainer interface.
10795  *
10796  * Since: 0.1.1
10797  *
10798  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
10799  */
10800 void
10801 clutter_actor_unparent (ClutterActor *self)
10802 {
10803   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10804
10805   if (self->priv->parent == NULL)
10806     return;
10807
10808   clutter_actor_remove_child_internal (self->priv->parent, self,
10809                                        REMOVE_CHILD_LEGACY_FLAGS);
10810 }
10811
10812 /**
10813  * clutter_actor_reparent:
10814  * @self: a #ClutterActor
10815  * @new_parent: the new #ClutterActor parent
10816  *
10817  * Resets the parent actor of @self.
10818  *
10819  * This function is logically equivalent to calling clutter_actor_unparent()
10820  * and clutter_actor_set_parent(), but more efficiently implemented, as it
10821  * ensures the child is not finalized when unparented, and emits the
10822  * #ClutterActor::parent-set signal only once.
10823  *
10824  * In reality, calling this function is less useful than it sounds, as some
10825  * application code may rely on changes in the intermediate state between
10826  * removal and addition of the actor from its old parent to the @new_parent.
10827  * Thus, it is strongly encouraged to avoid using this function in application
10828  * code.
10829  *
10830  * Since: 0.2
10831  *
10832  * Deprecated: 1.10: Use clutter_actor_remove_child() and
10833  *   clutter_actor_add_child() instead; remember to take a reference on
10834  *   the actor being removed before calling clutter_actor_remove_child()
10835  *   to avoid the reference count dropping to zero and the actor being
10836  *   destroyed.
10837  */
10838 void
10839 clutter_actor_reparent (ClutterActor *self,
10840                         ClutterActor *new_parent)
10841 {
10842   ClutterActorPrivate *priv;
10843
10844   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10845   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
10846   g_return_if_fail (self != new_parent);
10847
10848   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10849     {
10850       g_warning ("Cannot set a parent on a toplevel actor");
10851       return;
10852     }
10853
10854   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
10855     {
10856       g_warning ("Cannot set a parent currently being destroyed");
10857       return;
10858     }
10859
10860   priv = self->priv;
10861
10862   if (priv->parent != new_parent)
10863     {
10864       ClutterActor *old_parent;
10865
10866       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10867
10868       old_parent = priv->parent;
10869
10870       g_object_ref (self);
10871
10872       if (old_parent != NULL)
10873         {
10874          /* go through the Container implementation if this is a regular
10875           * child and not an internal one
10876           */
10877          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10878            {
10879              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
10880
10881              /* this will have to call unparent() */
10882              clutter_container_remove_actor (parent, self);
10883            }
10884          else
10885            clutter_actor_remove_child_internal (old_parent, self,
10886                                                 REMOVE_CHILD_LEGACY_FLAGS);
10887         }
10888
10889       /* Note, will call set_parent() */
10890       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10891         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
10892       else
10893         clutter_actor_add_child_internal (new_parent, self,
10894                                           ADD_CHILD_LEGACY_FLAGS,
10895                                           insert_child_at_depth,
10896                                           NULL);
10897
10898       /* we emit the ::parent-set signal once */
10899       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
10900
10901       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10902
10903       /* the IN_REPARENT flag suspends state updates */
10904       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
10905
10906       g_object_unref (self);
10907    }
10908 }
10909
10910 /**
10911  * clutter_actor_contains:
10912  * @self: A #ClutterActor
10913  * @descendant: A #ClutterActor, possibly contained in @self
10914  *
10915  * Determines if @descendant is contained inside @self (either as an
10916  * immediate child, or as a deeper descendant). If @self and
10917  * @descendant point to the same actor then it will also return %TRUE.
10918  *
10919  * Return value: whether @descendent is contained within @self
10920  *
10921  * Since: 1.4
10922  */
10923 gboolean
10924 clutter_actor_contains (ClutterActor *self,
10925                         ClutterActor *descendant)
10926 {
10927   ClutterActor *actor;
10928
10929   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10930   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
10931
10932   for (actor = descendant; actor; actor = actor->priv->parent)
10933     if (actor == self)
10934       return TRUE;
10935
10936   return FALSE;
10937 }
10938
10939 /**
10940  * clutter_actor_set_child_above_sibling:
10941  * @self: a #ClutterActor
10942  * @child: a #ClutterActor child of @self
10943  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10944  *
10945  * Sets @child to be above @sibling in the list of children of @self.
10946  *
10947  * If @sibling is %NULL, @child will be the new last child of @self.
10948  *
10949  * This function is logically equivalent to removing @child and using
10950  * clutter_actor_insert_child_above(), but it will not emit signals
10951  * or change state on @child.
10952  *
10953  * Since: 1.10
10954  */
10955 void
10956 clutter_actor_set_child_above_sibling (ClutterActor *self,
10957                                        ClutterActor *child,
10958                                        ClutterActor *sibling)
10959 {
10960   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10961   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10962   g_return_if_fail (child->priv->parent == self);
10963   g_return_if_fail (child != sibling);
10964   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10965
10966   if (sibling != NULL)
10967     g_return_if_fail (sibling->priv->parent == self);
10968
10969   /* we don't want to change the state of child, or emit signals, or
10970    * regenerate ChildMeta instances here, but we still want to follow
10971    * the correct sequence of steps encoded in remove_child() and
10972    * add_child(), so that correctness is ensured, and we only go
10973    * through one known code path.
10974    */
10975   g_object_ref (child);
10976   clutter_actor_remove_child_internal (self, child, 0);
10977   clutter_actor_add_child_internal (self, child,
10978                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10979                                     insert_child_above,
10980                                     sibling);
10981
10982   clutter_actor_queue_relayout (self);
10983 }
10984
10985 /**
10986  * clutter_actor_set_child_below_sibling:
10987  * @self: a #ClutterActor
10988  * @child: a #ClutterActor child of @self
10989  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10990  *
10991  * Sets @child to be below @sibling in the list of children of @self.
10992  *
10993  * If @sibling is %NULL, @child will be the new first child of @self.
10994  *
10995  * This function is logically equivalent to removing @self and using
10996  * clutter_actor_insert_child_below(), but it will not emit signals
10997  * or change state on @child.
10998  *
10999  * Since: 1.10
11000  */
11001 void
11002 clutter_actor_set_child_below_sibling (ClutterActor *self,
11003                                        ClutterActor *child,
11004                                        ClutterActor *sibling)
11005 {
11006   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11007   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11008   g_return_if_fail (child->priv->parent == self);
11009   g_return_if_fail (child != sibling);
11010   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11011
11012   if (sibling != NULL)
11013     g_return_if_fail (sibling->priv->parent == self);
11014
11015   /* see the comment in set_child_above_sibling() */
11016   g_object_ref (child);
11017   clutter_actor_remove_child_internal (self, child, 0);
11018   clutter_actor_add_child_internal (self, child,
11019                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11020                                     insert_child_below,
11021                                     sibling);
11022
11023   clutter_actor_queue_relayout (self);
11024 }
11025
11026 /**
11027  * clutter_actor_set_child_at_index:
11028  * @self: a #ClutterActor
11029  * @child: a #ClutterActor child of @self
11030  * @index_: the new index for @child
11031  *
11032  * Changes the index of @child in the list of children of @self.
11033  *
11034  * This function is logically equivalent to removing @child and
11035  * calling clutter_actor_insert_child_at_index(), but it will not
11036  * emit signals or change state on @child.
11037  *
11038  * Since: 1.10
11039  */
11040 void
11041 clutter_actor_set_child_at_index (ClutterActor *self,
11042                                   ClutterActor *child,
11043                                   gint          index_)
11044 {
11045   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11046   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11047   g_return_if_fail (child->priv->parent == self);
11048   g_return_if_fail (index_ <= self->priv->n_children);
11049
11050   g_object_ref (child);
11051   clutter_actor_remove_child_internal (self, child, 0);
11052   clutter_actor_add_child_internal (self, child,
11053                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11054                                     insert_child_at_index,
11055                                     GINT_TO_POINTER (index_));
11056
11057   clutter_actor_queue_relayout (self);
11058 }
11059
11060 /**
11061  * clutter_actor_raise:
11062  * @self: A #ClutterActor
11063  * @below: (allow-none): A #ClutterActor to raise above.
11064  *
11065  * Puts @self above @below.
11066  *
11067  * Both actors must have the same parent, and the parent must implement
11068  * the #ClutterContainer interface
11069  *
11070  * This function calls clutter_container_raise_child() internally.
11071  *
11072  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11073  */
11074 void
11075 clutter_actor_raise (ClutterActor *self,
11076                      ClutterActor *below)
11077 {
11078   ClutterActor *parent;
11079
11080   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11081
11082   parent = clutter_actor_get_parent (self);
11083   if (parent == NULL)
11084     {
11085       g_warning ("%s: Actor '%s' is not inside a container",
11086                  G_STRFUNC,
11087                  _clutter_actor_get_debug_name (self));
11088       return;
11089     }
11090
11091   if (below != NULL)
11092     {
11093       if (parent != clutter_actor_get_parent (below))
11094         {
11095           g_warning ("%s Actor '%s' is not in the same container as "
11096                      "actor '%s'",
11097                      G_STRFUNC,
11098                      _clutter_actor_get_debug_name (self),
11099                      _clutter_actor_get_debug_name (below));
11100           return;
11101         }
11102     }
11103
11104   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11105 }
11106
11107 /**
11108  * clutter_actor_lower:
11109  * @self: A #ClutterActor
11110  * @above: (allow-none): A #ClutterActor to lower below
11111  *
11112  * Puts @self below @above.
11113  *
11114  * Both actors must have the same parent, and the parent must implement
11115  * the #ClutterContainer interface.
11116  *
11117  * This function calls clutter_container_lower_child() internally.
11118  *
11119  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11120  */
11121 void
11122 clutter_actor_lower (ClutterActor *self,
11123                      ClutterActor *above)
11124 {
11125   ClutterActor *parent;
11126
11127   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11128
11129   parent = clutter_actor_get_parent (self);
11130   if (parent == NULL)
11131     {
11132       g_warning ("%s: Actor of type %s is not inside a container",
11133                  G_STRFUNC,
11134                  _clutter_actor_get_debug_name (self));
11135       return;
11136     }
11137
11138   if (above)
11139     {
11140       if (parent != clutter_actor_get_parent (above))
11141         {
11142           g_warning ("%s: Actor '%s' is not in the same container as "
11143                      "actor '%s'",
11144                      G_STRFUNC,
11145                      _clutter_actor_get_debug_name (self),
11146                      _clutter_actor_get_debug_name (above));
11147           return;
11148         }
11149     }
11150
11151   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11152 }
11153
11154 /**
11155  * clutter_actor_raise_top:
11156  * @self: A #ClutterActor
11157  *
11158  * Raises @self to the top.
11159  *
11160  * This function calls clutter_actor_raise() internally.
11161  *
11162  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11163  *   a %NULL sibling, instead.
11164  */
11165 void
11166 clutter_actor_raise_top (ClutterActor *self)
11167 {
11168   clutter_actor_raise (self, NULL);
11169 }
11170
11171 /**
11172  * clutter_actor_lower_bottom:
11173  * @self: A #ClutterActor
11174  *
11175  * Lowers @self to the bottom.
11176  *
11177  * This function calls clutter_actor_lower() internally.
11178  *
11179  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11180  *   a %NULL sibling, instead.
11181  */
11182 void
11183 clutter_actor_lower_bottom (ClutterActor *self)
11184 {
11185   clutter_actor_lower (self, NULL);
11186 }
11187
11188 /*
11189  * Event handling
11190  */
11191
11192 /**
11193  * clutter_actor_event:
11194  * @actor: a #ClutterActor
11195  * @event: a #ClutterEvent
11196  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11197  *
11198  * This function is used to emit an event on the main stage.
11199  * You should rarely need to use this function, except for
11200  * synthetising events.
11201  *
11202  * Return value: the return value from the signal emission: %TRUE
11203  *   if the actor handled the event, or %FALSE if the event was
11204  *   not handled
11205  *
11206  * Since: 0.6
11207  */
11208 gboolean
11209 clutter_actor_event (ClutterActor *actor,
11210                      ClutterEvent *event,
11211                      gboolean      capture)
11212 {
11213   gboolean retval = FALSE;
11214   gint signal_num = -1;
11215
11216   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11217   g_return_val_if_fail (event != NULL, FALSE);
11218
11219   g_object_ref (actor);
11220
11221   if (capture)
11222     {
11223       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11224                      event,
11225                      &retval);
11226       goto out;
11227     }
11228
11229   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11230
11231   if (!retval)
11232     {
11233       switch (event->type)
11234         {
11235         case CLUTTER_NOTHING:
11236           break;
11237         case CLUTTER_BUTTON_PRESS:
11238           signal_num = BUTTON_PRESS_EVENT;
11239           break;
11240         case CLUTTER_BUTTON_RELEASE:
11241           signal_num = BUTTON_RELEASE_EVENT;
11242           break;
11243         case CLUTTER_SCROLL:
11244           signal_num = SCROLL_EVENT;
11245           break;
11246         case CLUTTER_KEY_PRESS:
11247           signal_num = KEY_PRESS_EVENT;
11248           break;
11249         case CLUTTER_KEY_RELEASE:
11250           signal_num = KEY_RELEASE_EVENT;
11251           break;
11252         case CLUTTER_MOTION:
11253           signal_num = MOTION_EVENT;
11254           break;
11255         case CLUTTER_ENTER:
11256           signal_num = ENTER_EVENT;
11257           break;
11258         case CLUTTER_LEAVE:
11259           signal_num = LEAVE_EVENT;
11260           break;
11261         case CLUTTER_DELETE:
11262         case CLUTTER_DESTROY_NOTIFY:
11263         case CLUTTER_CLIENT_MESSAGE:
11264         default:
11265           signal_num = -1;
11266           break;
11267         }
11268
11269       if (signal_num != -1)
11270         g_signal_emit (actor, actor_signals[signal_num], 0,
11271                        event, &retval);
11272     }
11273
11274 out:
11275   g_object_unref (actor);
11276
11277   return retval;
11278 }
11279
11280 /**
11281  * clutter_actor_set_reactive:
11282  * @actor: a #ClutterActor
11283  * @reactive: whether the actor should be reactive to events
11284  *
11285  * Sets @actor as reactive. Reactive actors will receive events.
11286  *
11287  * Since: 0.6
11288  */
11289 void
11290 clutter_actor_set_reactive (ClutterActor *actor,
11291                             gboolean      reactive)
11292 {
11293   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11294
11295   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11296     return;
11297
11298   if (reactive)
11299     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11300   else
11301     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11302
11303   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11304 }
11305
11306 /**
11307  * clutter_actor_get_reactive:
11308  * @actor: a #ClutterActor
11309  *
11310  * Checks whether @actor is marked as reactive.
11311  *
11312  * Return value: %TRUE if the actor is reactive
11313  *
11314  * Since: 0.6
11315  */
11316 gboolean
11317 clutter_actor_get_reactive (ClutterActor *actor)
11318 {
11319   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11320
11321   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11322 }
11323
11324 /**
11325  * clutter_actor_get_anchor_point:
11326  * @self: a #ClutterActor
11327  * @anchor_x: (out): return location for the X coordinate of the anchor point
11328  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11329  *
11330  * Gets the current anchor point of the @actor in pixels.
11331  *
11332  * Since: 0.6
11333  */
11334 void
11335 clutter_actor_get_anchor_point (ClutterActor *self,
11336                                 gfloat       *anchor_x,
11337                                 gfloat       *anchor_y)
11338 {
11339   const ClutterTransformInfo *info;
11340
11341   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11342
11343   info = _clutter_actor_get_transform_info_or_defaults (self);
11344   clutter_anchor_coord_get_units (self, &info->anchor,
11345                                   anchor_x,
11346                                   anchor_y,
11347                                   NULL);
11348 }
11349
11350 /**
11351  * clutter_actor_set_anchor_point:
11352  * @self: a #ClutterActor
11353  * @anchor_x: X coordinate of the anchor point
11354  * @anchor_y: Y coordinate of the anchor point
11355  *
11356  * Sets an anchor point for @self. The anchor point is a point in the
11357  * coordinate space of an actor to which the actor position within its
11358  * parent is relative; the default is (0, 0), i.e. the top-left corner
11359  * of the actor.
11360  *
11361  * Since: 0.6
11362  */
11363 void
11364 clutter_actor_set_anchor_point (ClutterActor *self,
11365                                 gfloat        anchor_x,
11366                                 gfloat        anchor_y)
11367 {
11368   ClutterTransformInfo *info;
11369   ClutterActorPrivate *priv;
11370   gboolean changed = FALSE;
11371   gfloat old_anchor_x, old_anchor_y;
11372   GObject *obj;
11373
11374   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11375
11376   obj = G_OBJECT (self);
11377   priv = self->priv;
11378   info = _clutter_actor_get_transform_info (self);
11379
11380   g_object_freeze_notify (obj);
11381
11382   clutter_anchor_coord_get_units (self, &info->anchor,
11383                                   &old_anchor_x,
11384                                   &old_anchor_y,
11385                                   NULL);
11386
11387   if (info->anchor.is_fractional)
11388     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11389
11390   if (old_anchor_x != anchor_x)
11391     {
11392       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11393       changed = TRUE;
11394     }
11395
11396   if (old_anchor_y != anchor_y)
11397     {
11398       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11399       changed = TRUE;
11400     }
11401
11402   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11403
11404   if (changed)
11405     {
11406       priv->transform_valid = FALSE;
11407       clutter_actor_queue_redraw (self);
11408     }
11409
11410   g_object_thaw_notify (obj);
11411 }
11412
11413 /**
11414  * clutter_actor_get_anchor_point_gravity:
11415  * @self: a #ClutterActor
11416  *
11417  * Retrieves the anchor position expressed as a #ClutterGravity. If
11418  * the anchor point was specified using pixels or units this will
11419  * return %CLUTTER_GRAVITY_NONE.
11420  *
11421  * Return value: the #ClutterGravity used by the anchor point
11422  *
11423  * Since: 1.0
11424  */
11425 ClutterGravity
11426 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11427 {
11428   const ClutterTransformInfo *info;
11429
11430   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11431
11432   info = _clutter_actor_get_transform_info_or_defaults (self);
11433
11434   return clutter_anchor_coord_get_gravity (&info->anchor);
11435 }
11436
11437 /**
11438  * clutter_actor_move_anchor_point:
11439  * @self: a #ClutterActor
11440  * @anchor_x: X coordinate of the anchor point
11441  * @anchor_y: Y coordinate of the anchor point
11442  *
11443  * Sets an anchor point for the actor, and adjusts the actor postion so that
11444  * the relative position of the actor toward its parent remains the same.
11445  *
11446  * Since: 0.6
11447  */
11448 void
11449 clutter_actor_move_anchor_point (ClutterActor *self,
11450                                  gfloat        anchor_x,
11451                                  gfloat        anchor_y)
11452 {
11453   gfloat old_anchor_x, old_anchor_y;
11454   const ClutterTransformInfo *info;
11455
11456   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11457
11458   info = _clutter_actor_get_transform_info (self);
11459   clutter_anchor_coord_get_units (self, &info->anchor,
11460                                   &old_anchor_x,
11461                                   &old_anchor_y,
11462                                   NULL);
11463
11464   g_object_freeze_notify (G_OBJECT (self));
11465
11466   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11467
11468   if (self->priv->position_set)
11469     clutter_actor_move_by (self,
11470                            anchor_x - old_anchor_x,
11471                            anchor_y - old_anchor_y);
11472
11473   g_object_thaw_notify (G_OBJECT (self));
11474 }
11475
11476 /**
11477  * clutter_actor_move_anchor_point_from_gravity:
11478  * @self: a #ClutterActor
11479  * @gravity: #ClutterGravity.
11480  *
11481  * Sets an anchor point on the actor based on the given gravity, adjusting the
11482  * actor postion so that its relative position within its parent remains
11483  * unchanged.
11484  *
11485  * Since version 1.0 the anchor point will be stored as a gravity so
11486  * that if the actor changes size then the anchor point will move. For
11487  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11488  * and later double the size of the actor, the anchor point will move
11489  * to the bottom right.
11490  *
11491  * Since: 0.6
11492  */
11493 void
11494 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11495                                               ClutterGravity  gravity)
11496 {
11497   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11498   const ClutterTransformInfo *info;
11499   ClutterActorPrivate *priv;
11500
11501   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11502
11503   priv = self->priv;
11504   info = _clutter_actor_get_transform_info (self);
11505
11506   g_object_freeze_notify (G_OBJECT (self));
11507
11508   clutter_anchor_coord_get_units (self, &info->anchor,
11509                                   &old_anchor_x,
11510                                   &old_anchor_y,
11511                                   NULL);
11512   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11513   clutter_anchor_coord_get_units (self, &info->anchor,
11514                                   &new_anchor_x,
11515                                   &new_anchor_y,
11516                                   NULL);
11517
11518   if (priv->position_set)
11519     clutter_actor_move_by (self,
11520                            new_anchor_x - old_anchor_x,
11521                            new_anchor_y - old_anchor_y);
11522
11523   g_object_thaw_notify (G_OBJECT (self));
11524 }
11525
11526 /**
11527  * clutter_actor_set_anchor_point_from_gravity:
11528  * @self: a #ClutterActor
11529  * @gravity: #ClutterGravity.
11530  *
11531  * Sets an anchor point on the actor, based on the given gravity (this is a
11532  * convenience function wrapping clutter_actor_set_anchor_point()).
11533  *
11534  * Since version 1.0 the anchor point will be stored as a gravity so
11535  * that if the actor changes size then the anchor point will move. For
11536  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11537  * and later double the size of the actor, the anchor point will move
11538  * to the bottom right.
11539  *
11540  * Since: 0.6
11541  */
11542 void
11543 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11544                                              ClutterGravity  gravity)
11545 {
11546   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11547
11548   if (gravity == CLUTTER_GRAVITY_NONE)
11549     clutter_actor_set_anchor_point (self, 0, 0);
11550   else
11551     {
11552       GObject *obj = G_OBJECT (self);
11553       ClutterTransformInfo *info;
11554
11555       g_object_freeze_notify (obj);
11556
11557       info = _clutter_actor_get_transform_info (self);
11558       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11559
11560       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11561       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11562       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11563
11564       self->priv->transform_valid = FALSE;
11565
11566       clutter_actor_queue_redraw (self);
11567
11568       g_object_thaw_notify (obj);
11569     }
11570 }
11571
11572 static void
11573 clutter_container_iface_init (ClutterContainerIface *iface)
11574 {
11575   /* we don't override anything, as ClutterContainer already has a default
11576    * implementation that we can use, and which calls into our own API.
11577    */
11578 }
11579
11580 typedef enum
11581 {
11582   PARSE_X,
11583   PARSE_Y,
11584   PARSE_WIDTH,
11585   PARSE_HEIGHT,
11586   PARSE_ANCHOR_X,
11587   PARSE_ANCHOR_Y
11588 } ParseDimension;
11589
11590 static gfloat
11591 parse_units (ClutterActor   *self,
11592              ParseDimension  dimension,
11593              JsonNode       *node)
11594 {
11595   GValue value = { 0, };
11596   gfloat retval = 0;
11597
11598   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11599     return 0;
11600
11601   json_node_get_value (node, &value);
11602
11603   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11604     {
11605       retval = (gfloat) g_value_get_int64 (&value);
11606     }
11607   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
11608     {
11609       retval = g_value_get_double (&value);
11610     }
11611   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
11612     {
11613       ClutterUnits units;
11614       gboolean res;
11615
11616       res = clutter_units_from_string (&units, g_value_get_string (&value));
11617       if (res)
11618         retval = clutter_units_to_pixels (&units);
11619       else
11620         {
11621           g_warning ("Invalid value '%s': integers, strings or floating point "
11622                      "values can be used for the x, y, width and height "
11623                      "properties. Valid modifiers for strings are 'px', 'mm', "
11624                      "'pt' and 'em'.",
11625                      g_value_get_string (&value));
11626           retval = 0;
11627         }
11628     }
11629   else
11630     {
11631       g_warning ("Invalid value of type '%s': integers, strings of floating "
11632                  "point values can be used for the x, y, width, height "
11633                  "anchor-x and anchor-y properties.",
11634                  g_type_name (G_VALUE_TYPE (&value)));
11635     }
11636
11637   g_value_unset (&value);
11638
11639   return retval;
11640 }
11641
11642 typedef struct {
11643   ClutterRotateAxis axis;
11644
11645   gdouble angle;
11646
11647   gfloat center_x;
11648   gfloat center_y;
11649   gfloat center_z;
11650 } RotationInfo;
11651
11652 static inline gboolean
11653 parse_rotation_array (ClutterActor *actor,
11654                       JsonArray    *array,
11655                       RotationInfo *info)
11656 {
11657   JsonNode *element;
11658
11659   if (json_array_get_length (array) != 2)
11660     return FALSE;
11661
11662   /* angle */
11663   element = json_array_get_element (array, 0);
11664   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
11665     info->angle = json_node_get_double (element);
11666   else
11667     return FALSE;
11668
11669   /* center */
11670   element = json_array_get_element (array, 1);
11671   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
11672     {
11673       JsonArray *center = json_node_get_array (element);
11674
11675       if (json_array_get_length (center) != 2)
11676         return FALSE;
11677
11678       switch (info->axis)
11679         {
11680         case CLUTTER_X_AXIS:
11681           info->center_y = parse_units (actor, PARSE_Y,
11682                                         json_array_get_element (center, 0));
11683           info->center_z = parse_units (actor, PARSE_Y,
11684                                         json_array_get_element (center, 1));
11685           return TRUE;
11686
11687         case CLUTTER_Y_AXIS:
11688           info->center_x = parse_units (actor, PARSE_X,
11689                                         json_array_get_element (center, 0));
11690           info->center_z = parse_units (actor, PARSE_X,
11691                                         json_array_get_element (center, 1));
11692           return TRUE;
11693
11694         case CLUTTER_Z_AXIS:
11695           info->center_x = parse_units (actor, PARSE_X,
11696                                         json_array_get_element (center, 0));
11697           info->center_y = parse_units (actor, PARSE_Y,
11698                                         json_array_get_element (center, 1));
11699           return TRUE;
11700         }
11701     }
11702
11703   return FALSE;
11704 }
11705
11706 static gboolean
11707 parse_rotation (ClutterActor *actor,
11708                 JsonNode     *node,
11709                 RotationInfo *info)
11710 {
11711   JsonArray *array;
11712   guint len, i;
11713   gboolean retval = FALSE;
11714
11715   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
11716     {
11717       g_warning ("Invalid node of type '%s' found, expecting an array",
11718                  json_node_type_name (node));
11719       return FALSE;
11720     }
11721
11722   array = json_node_get_array (node);
11723   len = json_array_get_length (array);
11724
11725   for (i = 0; i < len; i++)
11726     {
11727       JsonNode *element = json_array_get_element (array, i);
11728       JsonObject *object;
11729       JsonNode *member;
11730
11731       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
11732         {
11733           g_warning ("Invalid node of type '%s' found, expecting an object",
11734                      json_node_type_name (element));
11735           return FALSE;
11736         }
11737
11738       object = json_node_get_object (element);
11739
11740       if (json_object_has_member (object, "x-axis"))
11741         {
11742           member = json_object_get_member (object, "x-axis");
11743
11744           info->axis = CLUTTER_X_AXIS;
11745
11746           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11747             {
11748               info->angle = json_node_get_double (member);
11749               retval = TRUE;
11750             }
11751           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11752             retval = parse_rotation_array (actor,
11753                                            json_node_get_array (member),
11754                                            info);
11755           else
11756             retval = FALSE;
11757         }
11758       else if (json_object_has_member (object, "y-axis"))
11759         {
11760           member = json_object_get_member (object, "y-axis");
11761
11762           info->axis = CLUTTER_Y_AXIS;
11763
11764           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11765             {
11766               info->angle = json_node_get_double (member);
11767               retval = TRUE;
11768             }
11769           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11770             retval = parse_rotation_array (actor,
11771                                            json_node_get_array (member),
11772                                            info);
11773           else
11774             retval = FALSE;
11775         }
11776       else if (json_object_has_member (object, "z-axis"))
11777         {
11778           member = json_object_get_member (object, "z-axis");
11779
11780           info->axis = CLUTTER_Z_AXIS;
11781
11782           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11783             {
11784               info->angle = json_node_get_double (member);
11785               retval = TRUE;
11786             }
11787           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11788             retval = parse_rotation_array (actor,
11789                                            json_node_get_array (member),
11790                                            info);
11791           else
11792             retval = FALSE;
11793         }
11794     }
11795
11796   return retval;
11797 }
11798
11799 static GSList *
11800 parse_actor_metas (ClutterScript *script,
11801                    ClutterActor  *actor,
11802                    JsonNode      *node)
11803 {
11804   GList *elements, *l;
11805   GSList *retval = NULL;
11806
11807   if (!JSON_NODE_HOLDS_ARRAY (node))
11808     return NULL;
11809
11810   elements = json_array_get_elements (json_node_get_array (node));
11811
11812   for (l = elements; l != NULL; l = l->next)
11813     {
11814       JsonNode *element = l->data;
11815       const gchar *id_ = _clutter_script_get_id_from_node (element);
11816       GObject *meta;
11817
11818       if (id_ == NULL || *id_ == '\0')
11819         continue;
11820
11821       meta = clutter_script_get_object (script, id_);
11822       if (meta == NULL)
11823         continue;
11824
11825       retval = g_slist_prepend (retval, meta);
11826     }
11827
11828   g_list_free (elements);
11829
11830   return g_slist_reverse (retval);
11831 }
11832
11833 static GSList *
11834 parse_behaviours (ClutterScript *script,
11835                   ClutterActor  *actor,
11836                   JsonNode      *node)
11837 {
11838   GList *elements, *l;
11839   GSList *retval = NULL;
11840
11841   if (!JSON_NODE_HOLDS_ARRAY (node))
11842     return NULL;
11843
11844   elements = json_array_get_elements (json_node_get_array (node));
11845
11846   for (l = elements; l != NULL; l = l->next)
11847     {
11848       JsonNode *element = l->data;
11849       const gchar *id_ = _clutter_script_get_id_from_node (element);
11850       GObject *behaviour;
11851
11852       if (id_ == NULL || *id_ == '\0')
11853         continue;
11854
11855       behaviour = clutter_script_get_object (script, id_);
11856       if (behaviour == NULL)
11857         continue;
11858
11859       retval = g_slist_prepend (retval, behaviour);
11860     }
11861
11862   g_list_free (elements);
11863
11864   return g_slist_reverse (retval);
11865 }
11866
11867 static gboolean
11868 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
11869                                  ClutterScript     *script,
11870                                  GValue            *value,
11871                                  const gchar       *name,
11872                                  JsonNode          *node)
11873 {
11874   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11875   gboolean retval = FALSE;
11876
11877   if ((name[0] == 'x' && name[1] == '\0') ||
11878       (name[0] == 'y' && name[1] == '\0') ||
11879       (strcmp (name, "width") == 0) ||
11880       (strcmp (name, "height") == 0) ||
11881       (strcmp (name, "anchor_x") == 0) ||
11882       (strcmp (name, "anchor_y") == 0))
11883     {
11884       ParseDimension dimension;
11885       gfloat units;
11886
11887       if (name[0] == 'x')
11888         dimension = PARSE_X;
11889       else if (name[0] == 'y')
11890         dimension = PARSE_Y;
11891       else if (name[0] == 'w')
11892         dimension = PARSE_WIDTH;
11893       else if (name[0] == 'h')
11894         dimension = PARSE_HEIGHT;
11895       else if (name[0] == 'a' && name[7] == 'x')
11896         dimension = PARSE_ANCHOR_X;
11897       else if (name[0] == 'a' && name[7] == 'y')
11898         dimension = PARSE_ANCHOR_Y;
11899       else
11900         return FALSE;
11901
11902       units = parse_units (actor, dimension, node);
11903
11904       /* convert back to pixels: all properties are pixel-based */
11905       g_value_init (value, G_TYPE_FLOAT);
11906       g_value_set_float (value, units);
11907
11908       retval = TRUE;
11909     }
11910   else if (strcmp (name, "rotation") == 0)
11911     {
11912       RotationInfo *info;
11913
11914       info = g_slice_new0 (RotationInfo);
11915       retval = parse_rotation (actor, node, info);
11916
11917       if (retval)
11918         {
11919           g_value_init (value, G_TYPE_POINTER);
11920           g_value_set_pointer (value, info);
11921         }
11922       else
11923         g_slice_free (RotationInfo, info);
11924     }
11925   else if (strcmp (name, "behaviours") == 0)
11926     {
11927       GSList *l;
11928
11929 #ifdef CLUTTER_ENABLE_DEBUG
11930       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
11931         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
11932                                      "and it should not be used in newly "
11933                                      "written ClutterScript definitions.");
11934 #endif
11935
11936       l = parse_behaviours (script, actor, node);
11937
11938       g_value_init (value, G_TYPE_POINTER);
11939       g_value_set_pointer (value, l);
11940
11941       retval = TRUE;
11942     }
11943   else if (strcmp (name, "actions") == 0 ||
11944            strcmp (name, "constraints") == 0 ||
11945            strcmp (name, "effects") == 0)
11946     {
11947       GSList *l;
11948
11949       l = parse_actor_metas (script, actor, node);
11950
11951       g_value_init (value, G_TYPE_POINTER);
11952       g_value_set_pointer (value, l);
11953
11954       retval = TRUE;
11955     }
11956
11957   return retval;
11958 }
11959
11960 static void
11961 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
11962                                    ClutterScript     *script,
11963                                    const gchar       *name,
11964                                    const GValue      *value)
11965 {
11966   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11967
11968 #ifdef CLUTTER_ENABLE_DEBUG
11969   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
11970     {
11971       gchar *tmp = g_strdup_value_contents (value);
11972
11973       CLUTTER_NOTE (SCRIPT,
11974                     "in ClutterActor::set_custom_property('%s') = %s",
11975                     name,
11976                     tmp);
11977
11978       g_free (tmp);
11979     }
11980 #endif /* CLUTTER_ENABLE_DEBUG */
11981
11982   if (strcmp (name, "rotation") == 0)
11983     {
11984       RotationInfo *info;
11985
11986       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11987         return;
11988
11989       info = g_value_get_pointer (value);
11990
11991       clutter_actor_set_rotation (actor,
11992                                   info->axis, info->angle,
11993                                   info->center_x,
11994                                   info->center_y,
11995                                   info->center_z);
11996
11997       g_slice_free (RotationInfo, info);
11998
11999       return;
12000     }
12001
12002   if (strcmp (name, "behaviours") == 0)
12003     {
12004       GSList *behaviours, *l;
12005
12006       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12007         return;
12008
12009       behaviours = g_value_get_pointer (value);
12010       for (l = behaviours; l != NULL; l = l->next)
12011         {
12012           ClutterBehaviour *behaviour = l->data;
12013
12014           clutter_behaviour_apply (behaviour, actor);
12015         }
12016
12017       g_slist_free (behaviours);
12018
12019       return;
12020     }
12021
12022   if (strcmp (name, "actions") == 0 ||
12023       strcmp (name, "constraints") == 0 ||
12024       strcmp (name, "effects") == 0)
12025     {
12026       GSList *metas, *l;
12027
12028       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12029         return;
12030
12031       metas = g_value_get_pointer (value);
12032       for (l = metas; l != NULL; l = l->next)
12033         {
12034           if (name[0] == 'a')
12035             clutter_actor_add_action (actor, l->data);
12036
12037           if (name[0] == 'c')
12038             clutter_actor_add_constraint (actor, l->data);
12039
12040           if (name[0] == 'e')
12041             clutter_actor_add_effect (actor, l->data);
12042         }
12043
12044       g_slist_free (metas);
12045
12046       return;
12047     }
12048
12049   g_object_set_property (G_OBJECT (scriptable), name, value);
12050 }
12051
12052 static void
12053 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12054 {
12055   iface->parse_custom_node = clutter_actor_parse_custom_node;
12056   iface->set_custom_property = clutter_actor_set_custom_property;
12057 }
12058
12059 static ClutterActorMeta *
12060 get_meta_from_animation_property (ClutterActor  *actor,
12061                                   const gchar   *name,
12062                                   gchar        **name_p)
12063 {
12064   ClutterActorPrivate *priv = actor->priv;
12065   ClutterActorMeta *meta = NULL;
12066   gchar **tokens;
12067
12068   /* if this is not a special property, fall through */
12069   if (name[0] != '@')
12070     return NULL;
12071
12072   /* detect the properties named using the following spec:
12073    *
12074    *   @<section>.<meta-name>.<property-name>
12075    *
12076    * where <section> can be one of the following:
12077    *
12078    *   - actions
12079    *   - constraints
12080    *   - effects
12081    *
12082    * and <meta-name> is the name set on a specific ActorMeta
12083    */
12084
12085   tokens = g_strsplit (name + 1, ".", -1);
12086   if (tokens == NULL || g_strv_length (tokens) != 3)
12087     {
12088       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12089                     name + 1);
12090       g_strfreev (tokens);
12091       return NULL;
12092     }
12093
12094   if (strcmp (tokens[0], "actions") == 0)
12095     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12096
12097   if (strcmp (tokens[0], "constraints") == 0)
12098     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12099
12100   if (strcmp (tokens[0], "effects") == 0)
12101     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12102
12103   if (name_p != NULL)
12104     *name_p = g_strdup (tokens[2]);
12105
12106   CLUTTER_NOTE (ANIMATION,
12107                 "Looking for property '%s' of object '%s' in section '%s'",
12108                 tokens[2],
12109                 tokens[1],
12110                 tokens[0]);
12111
12112   g_strfreev (tokens);
12113
12114   return meta;
12115 }
12116
12117 static GParamSpec *
12118 clutter_actor_find_property (ClutterAnimatable *animatable,
12119                              const gchar       *property_name)
12120 {
12121   ClutterActorMeta *meta = NULL;
12122   GObjectClass *klass = NULL;
12123   GParamSpec *pspec = NULL;
12124   gchar *p_name = NULL;
12125
12126   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12127                                            property_name,
12128                                            &p_name);
12129
12130   if (meta != NULL)
12131     {
12132       klass = G_OBJECT_GET_CLASS (meta);
12133
12134       pspec = g_object_class_find_property (klass, p_name);
12135     }
12136   else
12137     {
12138       klass = G_OBJECT_GET_CLASS (animatable);
12139
12140       pspec = g_object_class_find_property (klass, property_name);
12141     }
12142
12143   g_free (p_name);
12144
12145   return pspec;
12146 }
12147
12148 static void
12149 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12150                                  const gchar       *property_name,
12151                                  GValue            *initial)
12152 {
12153   ClutterActorMeta *meta = NULL;
12154   gchar *p_name = NULL;
12155
12156   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12157                                            property_name,
12158                                            &p_name);
12159
12160   if (meta != NULL)
12161     g_object_get_property (G_OBJECT (meta), p_name, initial);
12162   else
12163     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12164
12165   g_free (p_name);
12166 }
12167
12168 static void
12169 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12170                                const gchar       *property_name,
12171                                const GValue      *final)
12172 {
12173   ClutterActorMeta *meta = NULL;
12174   gchar *p_name = NULL;
12175
12176   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12177                                            property_name,
12178                                            &p_name);
12179   if (meta != NULL)
12180     g_object_set_property (G_OBJECT (meta), p_name, final);
12181   else
12182     g_object_set_property (G_OBJECT (animatable), property_name, final);
12183
12184   g_free (p_name);
12185 }
12186
12187 static void
12188 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12189 {
12190   iface->find_property = clutter_actor_find_property;
12191   iface->get_initial_state = clutter_actor_get_initial_state;
12192   iface->set_final_state = clutter_actor_set_final_state;
12193 }
12194
12195 /**
12196  * clutter_actor_transform_stage_point:
12197  * @self: A #ClutterActor
12198  * @x: (in): x screen coordinate of the point to unproject
12199  * @y: (in): y screen coordinate of the point to unproject
12200  * @x_out: (out): return location for the unprojected x coordinance
12201  * @y_out: (out): return location for the unprojected y coordinance
12202  *
12203  * This function translates screen coordinates (@x, @y) to
12204  * coordinates relative to the actor. For example, it can be used to translate
12205  * screen events from global screen coordinates into actor-local coordinates.
12206  *
12207  * The conversion can fail, notably if the transform stack results in the
12208  * actor being projected on the screen as a mere line.
12209  *
12210  * The conversion should not be expected to be pixel-perfect due to the
12211  * nature of the operation. In general the error grows when the skewing
12212  * of the actor rectangle on screen increases.
12213  *
12214  * <note><para>This function can be computationally intensive.</para></note>
12215  *
12216  * <note><para>This function only works when the allocation is up-to-date,
12217  * i.e. inside of paint().</para></note>
12218  *
12219  * Return value: %TRUE if conversion was successful.
12220  *
12221  * Since: 0.6
12222  */
12223 gboolean
12224 clutter_actor_transform_stage_point (ClutterActor *self,
12225                                      gfloat        x,
12226                                      gfloat        y,
12227                                      gfloat       *x_out,
12228                                      gfloat       *y_out)
12229 {
12230   ClutterVertex v[4];
12231   float ST[3][3];
12232   float RQ[3][3];
12233   int du, dv, xi, yi;
12234   float px, py;
12235   float xf, yf, wf, det;
12236   ClutterActorPrivate *priv;
12237
12238   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12239
12240   priv = self->priv;
12241
12242   /* This implementation is based on the quad -> quad projection algorithm
12243    * described by Paul Heckbert in:
12244    *
12245    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12246    *
12247    * and the sample implementation at:
12248    *
12249    *   http://www.cs.cmu.edu/~ph/src/texfund/
12250    *
12251    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12252    * quad to rectangle only, which significantly simplifies things; the
12253    * function calls have been unrolled, and most of the math is done in fixed
12254    * point.
12255    */
12256
12257   clutter_actor_get_abs_allocation_vertices (self, v);
12258
12259   /* Keeping these as ints simplifies the multiplication (no significant
12260    * loss of precision here).
12261    */
12262   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12263   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12264
12265   if (!du || !dv)
12266     return FALSE;
12267
12268 #define UX2FP(x)        (x)
12269 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12270
12271   /* First, find mapping from unit uv square to xy quadrilateral; this
12272    * equivalent to the pmap_square_quad() functions in the sample
12273    * implementation, which we can simplify, since our target is always
12274    * a rectangle.
12275    */
12276   px = v[0].x - v[1].x + v[3].x - v[2].x;
12277   py = v[0].y - v[1].y + v[3].y - v[2].y;
12278
12279   if (!px && !py)
12280     {
12281       /* affine transform */
12282       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12283       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12284       RQ[2][0] = UX2FP (v[0].x);
12285       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12286       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12287       RQ[2][1] = UX2FP (v[0].y);
12288       RQ[0][2] = 0;
12289       RQ[1][2] = 0;
12290       RQ[2][2] = 1.0;
12291     }
12292   else
12293     {
12294       /* projective transform */
12295       double dx1, dx2, dy1, dy2, del;
12296
12297       dx1 = UX2FP (v[1].x - v[3].x);
12298       dx2 = UX2FP (v[2].x - v[3].x);
12299       dy1 = UX2FP (v[1].y - v[3].y);
12300       dy2 = UX2FP (v[2].y - v[3].y);
12301
12302       del = DET2FP (dx1, dx2, dy1, dy2);
12303       if (!del)
12304         return FALSE;
12305
12306       /*
12307        * The division here needs to be done in floating point for
12308        * precisions reasons.
12309        */
12310       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12311       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12312       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12313       RQ[2][2] = 1.0;
12314       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12315       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12316       RQ[2][0] = UX2FP (v[0].x);
12317       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12318       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12319       RQ[2][1] = UX2FP (v[0].y);
12320     }
12321
12322   /*
12323    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12324    * square. Since our rectangle is based at 0,0 we only need to scale.
12325    */
12326   RQ[0][0] /= du;
12327   RQ[1][0] /= dv;
12328   RQ[0][1] /= du;
12329   RQ[1][1] /= dv;
12330   RQ[0][2] /= du;
12331   RQ[1][2] /= dv;
12332
12333   /*
12334    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12335    * inverse of that.
12336    */
12337   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12338   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12339   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12340   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12341   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12342   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12343   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12344   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12345   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12346
12347   /*
12348    * Check the resulting matrix is OK.
12349    */
12350   det = (RQ[0][0] * ST[0][0])
12351       + (RQ[0][1] * ST[0][1])
12352       + (RQ[0][2] * ST[0][2]);
12353   if (!det)
12354     return FALSE;
12355
12356   /*
12357    * Now transform our point with the ST matrix; the notional w
12358    * coordinate is 1, hence the last part is simply added.
12359    */
12360   xi = (int) x;
12361   yi = (int) y;
12362
12363   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12364   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12365   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12366
12367   if (x_out)
12368     *x_out = xf / wf;
12369
12370   if (y_out)
12371     *y_out = yf / wf;
12372
12373 #undef UX2FP
12374 #undef DET2FP
12375
12376   return TRUE;
12377 }
12378
12379 /*
12380  * ClutterGeometry
12381  */
12382
12383 static ClutterGeometry*
12384 clutter_geometry_copy (const ClutterGeometry *geometry)
12385 {
12386   return g_slice_dup (ClutterGeometry, geometry);
12387 }
12388
12389 static void
12390 clutter_geometry_free (ClutterGeometry *geometry)
12391 {
12392   if (G_LIKELY (geometry != NULL))
12393     g_slice_free (ClutterGeometry, geometry);
12394 }
12395
12396 /**
12397  * clutter_geometry_union:
12398  * @geometry_a: a #ClutterGeometry
12399  * @geometry_b: another #ClutterGeometry
12400  * @result: (out): location to store the result
12401  *
12402  * Find the union of two rectangles represented as #ClutterGeometry.
12403  *
12404  * Since: 1.4
12405  */
12406 void
12407 clutter_geometry_union (const ClutterGeometry *geometry_a,
12408                         const ClutterGeometry *geometry_b,
12409                         ClutterGeometry       *result)
12410 {
12411   /* We don't try to handle rectangles that can't be represented
12412    * as a signed integer box */
12413   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12414   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12415   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12416                   geometry_b->x + (gint)geometry_b->width);
12417   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12418                   geometry_b->y + (gint)geometry_b->height);
12419   result->x = x_1;
12420   result->y = y_1;
12421   result->width = x_2 - x_1;
12422   result->height = y_2 - y_1;
12423 }
12424
12425 /**
12426  * clutter_geometry_intersects:
12427  * @geometry0: The first geometry to test
12428  * @geometry1: The second geometry to test
12429  *
12430  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12431  * they do else %FALSE.
12432  *
12433  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12434  * %FALSE.
12435  *
12436  * Since: 1.4
12437  */
12438 gboolean
12439 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12440                              const ClutterGeometry *geometry1)
12441 {
12442   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12443       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12444       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12445       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12446     return FALSE;
12447   else
12448     return TRUE;
12449 }
12450
12451 static gboolean
12452 clutter_geometry_progress (const GValue *a,
12453                            const GValue *b,
12454                            gdouble       progress,
12455                            GValue       *retval)
12456 {
12457   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12458   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12459   ClutterGeometry res = { 0, };
12460   gint a_width = a_geom->width;
12461   gint b_width = b_geom->width;
12462   gint a_height = a_geom->height;
12463   gint b_height = b_geom->height;
12464
12465   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12466   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12467
12468   res.width = a_width + (b_width - a_width) * progress;
12469   res.height = a_height + (b_height - a_height) * progress;
12470
12471   g_value_set_boxed (retval, &res);
12472
12473   return TRUE;
12474 }
12475
12476 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12477                                clutter_geometry_copy,
12478                                clutter_geometry_free,
12479                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12480
12481 /*
12482  * ClutterVertices
12483  */
12484
12485 /**
12486  * clutter_vertex_new:
12487  * @x: X coordinate
12488  * @y: Y coordinate
12489  * @z: Z coordinate
12490  *
12491  * Creates a new #ClutterVertex for the point in 3D space
12492  * identified by the 3 coordinates @x, @y, @z
12493  *
12494  * Return value: the newly allocate #ClutterVertex. Use
12495  *   clutter_vertex_free() to free the resources
12496  *
12497  * Since: 1.0
12498  */
12499 ClutterVertex *
12500 clutter_vertex_new (gfloat x,
12501                     gfloat y,
12502                     gfloat z)
12503 {
12504   ClutterVertex *vertex;
12505
12506   vertex = g_slice_new (ClutterVertex);
12507   vertex->x = x;
12508   vertex->y = y;
12509   vertex->z = z;
12510
12511   return vertex;
12512 }
12513
12514 /**
12515  * clutter_vertex_copy:
12516  * @vertex: a #ClutterVertex
12517  *
12518  * Copies @vertex
12519  *
12520  * Return value: a newly allocated copy of #ClutterVertex. Use
12521  *   clutter_vertex_free() to free the allocated resources
12522  *
12523  * Since: 1.0
12524  */
12525 ClutterVertex *
12526 clutter_vertex_copy (const ClutterVertex *vertex)
12527 {
12528   if (G_LIKELY (vertex != NULL))
12529     return g_slice_dup (ClutterVertex, vertex);
12530
12531   return NULL;
12532 }
12533
12534 /**
12535  * clutter_vertex_free:
12536  * @vertex: a #ClutterVertex
12537  *
12538  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
12539  *
12540  * Since: 1.0
12541  */
12542 void
12543 clutter_vertex_free (ClutterVertex *vertex)
12544 {
12545   if (G_UNLIKELY (vertex != NULL))
12546     g_slice_free (ClutterVertex, vertex);
12547 }
12548
12549 /**
12550  * clutter_vertex_equal:
12551  * @vertex_a: a #ClutterVertex
12552  * @vertex_b: a #ClutterVertex
12553  *
12554  * Compares @vertex_a and @vertex_b for equality
12555  *
12556  * Return value: %TRUE if the passed #ClutterVertex are equal
12557  *
12558  * Since: 1.0
12559  */
12560 gboolean
12561 clutter_vertex_equal (const ClutterVertex *vertex_a,
12562                       const ClutterVertex *vertex_b)
12563 {
12564   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
12565
12566   if (vertex_a == vertex_b)
12567     return TRUE;
12568
12569   return vertex_a->x == vertex_b->x &&
12570          vertex_a->y == vertex_b->y &&
12571          vertex_a->z == vertex_b->z;
12572 }
12573
12574 static gboolean
12575 clutter_vertex_progress (const GValue *a,
12576                          const GValue *b,
12577                          gdouble       progress,
12578                          GValue       *retval)
12579 {
12580   const ClutterVertex *av = g_value_get_boxed (a);
12581   const ClutterVertex *bv = g_value_get_boxed (b);
12582   ClutterVertex res = { 0, };
12583
12584   res.x = av->x + (bv->x - av->x) * progress;
12585   res.y = av->y + (bv->y - av->y) * progress;
12586   res.z = av->z + (bv->z - av->z) * progress;
12587
12588   g_value_set_boxed (retval, &res);
12589
12590   return TRUE;
12591 }
12592
12593 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
12594                                clutter_vertex_copy,
12595                                clutter_vertex_free,
12596                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
12597
12598 /**
12599  * clutter_actor_is_rotated:
12600  * @self: a #ClutterActor
12601  *
12602  * Checks whether any rotation is applied to the actor.
12603  *
12604  * Return value: %TRUE if the actor is rotated.
12605  *
12606  * Since: 0.6
12607  */
12608 gboolean
12609 clutter_actor_is_rotated (ClutterActor *self)
12610 {
12611   const ClutterTransformInfo *info;
12612
12613   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12614
12615   info = _clutter_actor_get_transform_info_or_defaults (self);
12616
12617   if (info->rx_angle || info->ry_angle || info->rz_angle)
12618     return TRUE;
12619
12620   return FALSE;
12621 }
12622
12623 /**
12624  * clutter_actor_is_scaled:
12625  * @self: a #ClutterActor
12626  *
12627  * Checks whether the actor is scaled in either dimension.
12628  *
12629  * Return value: %TRUE if the actor is scaled.
12630  *
12631  * Since: 0.6
12632  */
12633 gboolean
12634 clutter_actor_is_scaled (ClutterActor *self)
12635 {
12636   const ClutterTransformInfo *info;
12637
12638   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12639
12640   info = _clutter_actor_get_transform_info_or_defaults (self);
12641
12642   if (info->scale_x != 1.0 || info->scale_y != 1.0)
12643     return TRUE;
12644
12645   return FALSE;
12646 }
12647
12648 ClutterActor *
12649 _clutter_actor_get_stage_internal (ClutterActor *actor)
12650 {
12651   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
12652     actor = actor->priv->parent;
12653
12654   return actor;
12655 }
12656
12657 /**
12658  * clutter_actor_get_stage:
12659  * @actor: a #ClutterActor
12660  *
12661  * Retrieves the #ClutterStage where @actor is contained.
12662  *
12663  * Return value: (transfer none) (type Clutter.Stage): the stage
12664  *   containing the actor, or %NULL
12665  *
12666  * Since: 0.8
12667  */
12668 ClutterActor *
12669 clutter_actor_get_stage (ClutterActor *actor)
12670 {
12671   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
12672
12673   return _clutter_actor_get_stage_internal (actor);
12674 }
12675
12676 /**
12677  * clutter_actor_allocate_available_size:
12678  * @self: a #ClutterActor
12679  * @x: the actor's X coordinate
12680  * @y: the actor's Y coordinate
12681  * @available_width: the maximum available width, or -1 to use the
12682  *   actor's natural width
12683  * @available_height: the maximum available height, or -1 to use the
12684  *   actor's natural height
12685  * @flags: flags controlling the allocation
12686  *
12687  * Allocates @self taking into account the #ClutterActor<!-- -->'s
12688  * preferred size, but limiting it to the maximum available width
12689  * and height provided.
12690  *
12691  * This function will do the right thing when dealing with the
12692  * actor's request mode.
12693  *
12694  * The implementation of this function is equivalent to:
12695  *
12696  * |[
12697  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12698  *     {
12699  *       clutter_actor_get_preferred_width (self, available_height,
12700  *                                          &amp;min_width,
12701  *                                          &amp;natural_width);
12702  *       width = CLAMP (natural_width, min_width, available_width);
12703  *
12704  *       clutter_actor_get_preferred_height (self, width,
12705  *                                           &amp;min_height,
12706  *                                           &amp;natural_height);
12707  *       height = CLAMP (natural_height, min_height, available_height);
12708  *     }
12709  *   else
12710  *     {
12711  *       clutter_actor_get_preferred_height (self, available_width,
12712  *                                           &amp;min_height,
12713  *                                           &amp;natural_height);
12714  *       height = CLAMP (natural_height, min_height, available_height);
12715  *
12716  *       clutter_actor_get_preferred_width (self, height,
12717  *                                          &amp;min_width,
12718  *                                          &amp;natural_width);
12719  *       width = CLAMP (natural_width, min_width, available_width);
12720  *     }
12721  *
12722  *   box.x1 = x; box.y1 = y;
12723  *   box.x2 = box.x1 + available_width;
12724  *   box.y2 = box.y1 + available_height;
12725  *   clutter_actor_allocate (self, &amp;box, flags);
12726  * ]|
12727  *
12728  * This function can be used by fluid layout managers to allocate
12729  * an actor's preferred size without making it bigger than the area
12730  * available for the container.
12731  *
12732  * Since: 1.0
12733  */
12734 void
12735 clutter_actor_allocate_available_size (ClutterActor           *self,
12736                                        gfloat                  x,
12737                                        gfloat                  y,
12738                                        gfloat                  available_width,
12739                                        gfloat                  available_height,
12740                                        ClutterAllocationFlags  flags)
12741 {
12742   ClutterActorPrivate *priv;
12743   gfloat width, height;
12744   gfloat min_width, min_height;
12745   gfloat natural_width, natural_height;
12746   ClutterActorBox box;
12747
12748   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12749
12750   priv = self->priv;
12751
12752   width = height = 0.0;
12753
12754   switch (priv->request_mode)
12755     {
12756     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
12757       clutter_actor_get_preferred_width (self, available_height,
12758                                          &min_width,
12759                                          &natural_width);
12760       width  = CLAMP (natural_width, min_width, available_width);
12761
12762       clutter_actor_get_preferred_height (self, width,
12763                                           &min_height,
12764                                           &natural_height);
12765       height = CLAMP (natural_height, min_height, available_height);
12766       break;
12767
12768     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
12769       clutter_actor_get_preferred_height (self, available_width,
12770                                           &min_height,
12771                                           &natural_height);
12772       height = CLAMP (natural_height, min_height, available_height);
12773
12774       clutter_actor_get_preferred_width (self, height,
12775                                          &min_width,
12776                                          &natural_width);
12777       width  = CLAMP (natural_width, min_width, available_width);
12778       break;
12779     }
12780
12781
12782   box.x1 = x;
12783   box.y1 = y;
12784   box.x2 = box.x1 + width;
12785   box.y2 = box.y1 + height;
12786   clutter_actor_allocate (self, &box, flags);
12787 }
12788
12789 /**
12790  * clutter_actor_allocate_preferred_size:
12791  * @self: a #ClutterActor
12792  * @flags: flags controlling the allocation
12793  *
12794  * Allocates the natural size of @self.
12795  *
12796  * This function is a utility call for #ClutterActor implementations
12797  * that allocates the actor's preferred natural size. It can be used
12798  * by fixed layout managers (like #ClutterGroup or so called
12799  * 'composite actors') inside the ClutterActor::allocate
12800  * implementation to give each child exactly how much space it
12801  * requires.
12802  *
12803  * This function is not meant to be used by applications. It is also
12804  * not meant to be used outside the implementation of the
12805  * ClutterActor::allocate virtual function.
12806  *
12807  * Since: 0.8
12808  */
12809 void
12810 clutter_actor_allocate_preferred_size (ClutterActor           *self,
12811                                        ClutterAllocationFlags  flags)
12812 {
12813   gfloat actor_x, actor_y;
12814   gfloat natural_width, natural_height;
12815   ClutterActorBox actor_box;
12816
12817   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12818
12819   actor_x = clutter_actor_get_x (self);
12820   actor_y = clutter_actor_get_y (self);
12821
12822   clutter_actor_get_preferred_size (self,
12823                                     NULL, NULL,
12824                                     &natural_width,
12825                                     &natural_height);
12826
12827   actor_box.x1 = actor_x;
12828   actor_box.y1 = actor_y;
12829   actor_box.x2 = actor_box.x1 + natural_width;
12830   actor_box.y2 = actor_box.y1 + natural_height;
12831
12832   clutter_actor_allocate (self, &actor_box, flags);
12833 }
12834
12835 /**
12836  * clutter_actor_allocate_align_fill:
12837  * @self: a #ClutterActor
12838  * @box: a #ClutterActorBox, containing the available width and height
12839  * @x_align: the horizontal alignment, between 0 and 1
12840  * @y_align: the vertical alignment, between 0 and 1
12841  * @x_fill: whether the actor should fill horizontally
12842  * @y_fill: whether the actor should fill vertically
12843  * @flags: allocation flags to be passed to clutter_actor_allocate()
12844  *
12845  * Allocates @self by taking into consideration the available allocation
12846  * area; an alignment factor on either axis; and whether the actor should
12847  * fill the allocation on either axis.
12848  *
12849  * The @box should contain the available allocation width and height;
12850  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
12851  * allocation will be offset by their value.
12852  *
12853  * This function takes into consideration the geometry request specified by
12854  * the #ClutterActor:request-mode property, and the text direction.
12855  *
12856  * This function is useful for fluid layout managers, like #ClutterBinLayout
12857  * or #ClutterTableLayout
12858  *
12859  * Since: 1.4
12860  */
12861 void
12862 clutter_actor_allocate_align_fill (ClutterActor           *self,
12863                                    const ClutterActorBox  *box,
12864                                    gdouble                 x_align,
12865                                    gdouble                 y_align,
12866                                    gboolean                x_fill,
12867                                    gboolean                y_fill,
12868                                    ClutterAllocationFlags  flags)
12869 {
12870   ClutterActorPrivate *priv;
12871   ClutterActorBox allocation = { 0, };
12872   gfloat x_offset, y_offset;
12873   gfloat available_width, available_height;
12874   gfloat child_width, child_height;
12875
12876   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12877   g_return_if_fail (box != NULL);
12878   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
12879   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
12880
12881   priv = self->priv;
12882
12883   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
12884   clutter_actor_box_get_size (box, &available_width, &available_height);
12885
12886   if (available_width < 0)
12887     available_width = 0;
12888
12889   if (available_height < 0)
12890     available_height = 0;
12891
12892   if (x_fill)
12893     {
12894       allocation.x1 = x_offset;
12895       allocation.x2 = allocation.x1 + available_width;
12896     }
12897
12898   if (y_fill)
12899     {
12900       allocation.y1 = y_offset;
12901       allocation.y2 = allocation.y1 + available_height;
12902     }
12903
12904   /* if we are filling horizontally and vertically then we're done */
12905   if (x_fill && y_fill)
12906     goto out;
12907
12908   child_width = child_height = 0.0f;
12909
12910   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12911     {
12912       gfloat min_width, natural_width;
12913       gfloat min_height, natural_height;
12914
12915       clutter_actor_get_preferred_width (self, available_height,
12916                                          &min_width,
12917                                          &natural_width);
12918
12919       child_width = CLAMP (natural_width, min_width, available_width);
12920
12921       if (!y_fill)
12922         {
12923           clutter_actor_get_preferred_height (self, child_width,
12924                                               &min_height,
12925                                               &natural_height);
12926
12927           child_height = CLAMP (natural_height, min_height, available_height);
12928         }
12929     }
12930   else
12931     {
12932       gfloat min_width, natural_width;
12933       gfloat min_height, natural_height;
12934
12935       clutter_actor_get_preferred_height (self, available_width,
12936                                           &min_height,
12937                                           &natural_height);
12938
12939       child_height = CLAMP (natural_height, min_height, available_height);
12940
12941       if (!x_fill)
12942         {
12943           clutter_actor_get_preferred_width (self, child_height,
12944                                              &min_width,
12945                                              &natural_width);
12946
12947           child_width = CLAMP (natural_width, min_width, available_width);
12948         }
12949     }
12950
12951   /* invert the horizontal alignment for RTL languages */
12952   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
12953     x_align = 1.0 - x_align;
12954
12955   if (!x_fill)
12956     {
12957       allocation.x1 = x_offset
12958                     + ((available_width - child_width) * x_align);
12959       allocation.x2 = allocation.x1 + child_width;
12960     }
12961
12962   if (!y_fill)
12963     {
12964       allocation.y1 = y_offset
12965                     + ((available_height - child_height) * y_align);
12966       allocation.y2 = allocation.y1 + child_height;
12967     }
12968
12969 out:
12970   clutter_actor_box_clamp_to_pixel (&allocation);
12971   clutter_actor_allocate (self, &allocation, flags);
12972 }
12973
12974 /**
12975  * clutter_actor_grab_key_focus:
12976  * @self: a #ClutterActor
12977  *
12978  * Sets the key focus of the #ClutterStage including @self
12979  * to this #ClutterActor.
12980  *
12981  * Since: 1.0
12982  */
12983 void
12984 clutter_actor_grab_key_focus (ClutterActor *self)
12985 {
12986   ClutterActor *stage;
12987
12988   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12989
12990   stage = _clutter_actor_get_stage_internal (self);
12991   if (stage != NULL)
12992     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
12993 }
12994
12995 /**
12996  * clutter_actor_get_pango_context:
12997  * @self: a #ClutterActor
12998  *
12999  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13000  * is already configured using the appropriate font map, resolution
13001  * and font options.
13002  *
13003  * Unlike clutter_actor_create_pango_context(), this context is owend
13004  * by the #ClutterActor and it will be updated each time the options
13005  * stored by the #ClutterBackend change.
13006  *
13007  * You can use the returned #PangoContext to create a #PangoLayout
13008  * and render text using cogl_pango_render_layout() to reuse the
13009  * glyphs cache also used by Clutter.
13010  *
13011  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13012  *   The returned #PangoContext is owned by the actor and should not be
13013  *   unreferenced by the application code
13014  *
13015  * Since: 1.0
13016  */
13017 PangoContext *
13018 clutter_actor_get_pango_context (ClutterActor *self)
13019 {
13020   ClutterActorPrivate *priv;
13021
13022   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13023
13024   priv = self->priv;
13025
13026   if (priv->pango_context != NULL)
13027     return priv->pango_context;
13028
13029   priv->pango_context = _clutter_context_get_pango_context ();
13030   g_object_ref (priv->pango_context);
13031
13032   return priv->pango_context;
13033 }
13034
13035 /**
13036  * clutter_actor_create_pango_context:
13037  * @self: a #ClutterActor
13038  *
13039  * Creates a #PangoContext for the given actor. The #PangoContext
13040  * is already configured using the appropriate font map, resolution
13041  * and font options.
13042  *
13043  * See also clutter_actor_get_pango_context().
13044  *
13045  * Return value: (transfer full): the newly created #PangoContext.
13046  *   Use g_object_unref() on the returned value to deallocate its
13047  *   resources
13048  *
13049  * Since: 1.0
13050  */
13051 PangoContext *
13052 clutter_actor_create_pango_context (ClutterActor *self)
13053 {
13054   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13055
13056   return _clutter_context_create_pango_context ();
13057 }
13058
13059 /**
13060  * clutter_actor_create_pango_layout:
13061  * @self: a #ClutterActor
13062  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13063  *
13064  * Creates a new #PangoLayout from the same #PangoContext used
13065  * by the #ClutterActor. The #PangoLayout is already configured
13066  * with the font map, resolution and font options, and the
13067  * given @text.
13068  *
13069  * If you want to keep around a #PangoLayout created by this
13070  * function you will have to connect to the #ClutterBackend::font-changed
13071  * and #ClutterBackend::resolution-changed signals, and call
13072  * pango_layout_context_changed() in response to them.
13073  *
13074  * Return value: (transfer full): the newly created #PangoLayout.
13075  *   Use g_object_unref() when done
13076  *
13077  * Since: 1.0
13078  */
13079 PangoLayout *
13080 clutter_actor_create_pango_layout (ClutterActor *self,
13081                                    const gchar  *text)
13082 {
13083   PangoContext *context;
13084   PangoLayout *layout;
13085
13086   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13087
13088   context = clutter_actor_get_pango_context (self);
13089   layout = pango_layout_new (context);
13090
13091   if (text)
13092     pango_layout_set_text (layout, text, -1);
13093
13094   return layout;
13095 }
13096
13097 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13098  * ClutterOffscreenEffect.
13099  */
13100 void
13101 _clutter_actor_set_opacity_override (ClutterActor *self,
13102                                      gint          opacity)
13103 {
13104   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13105
13106   self->priv->opacity_override = opacity;
13107 }
13108
13109 gint
13110 _clutter_actor_get_opacity_override (ClutterActor *self)
13111 {
13112   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13113
13114   return self->priv->opacity_override;
13115 }
13116
13117 /* Allows you to disable applying the actors model view transform during
13118  * a paint. Used by ClutterClone. */
13119 void
13120 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13121                                                 gboolean      enable)
13122 {
13123   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13124
13125   self->priv->enable_model_view_transform = enable;
13126 }
13127
13128 void
13129 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13130                                           gboolean      enable)
13131 {
13132   ClutterActorPrivate *priv;
13133
13134   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13135
13136   priv = self->priv;
13137
13138   priv->enable_paint_unmapped = enable;
13139
13140   if (priv->enable_paint_unmapped)
13141     {
13142       /* Make sure that the parents of the widget are realized first;
13143        * otherwise checks in clutter_actor_update_map_state() will
13144        * fail.
13145        */
13146       clutter_actor_realize (self);
13147
13148       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13149     }
13150   else
13151     {
13152       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13153     }
13154 }
13155
13156 static void
13157 clutter_anchor_coord_get_units (ClutterActor      *self,
13158                                 const AnchorCoord *coord,
13159                                 gfloat            *x,
13160                                 gfloat            *y,
13161                                 gfloat            *z)
13162 {
13163   if (coord->is_fractional)
13164     {
13165       gfloat actor_width, actor_height;
13166
13167       clutter_actor_get_size (self, &actor_width, &actor_height);
13168
13169       if (x)
13170         *x = actor_width * coord->v.fraction.x;
13171
13172       if (y)
13173         *y = actor_height * coord->v.fraction.y;
13174
13175       if (z)
13176         *z = 0;
13177     }
13178   else
13179     {
13180       if (x)
13181         *x = coord->v.units.x;
13182
13183       if (y)
13184         *y = coord->v.units.y;
13185
13186       if (z)
13187         *z = coord->v.units.z;
13188     }
13189 }
13190
13191 static void
13192 clutter_anchor_coord_set_units (AnchorCoord *coord,
13193                                 gfloat       x,
13194                                 gfloat       y,
13195                                 gfloat       z)
13196 {
13197   coord->is_fractional = FALSE;
13198   coord->v.units.x = x;
13199   coord->v.units.y = y;
13200   coord->v.units.z = z;
13201 }
13202
13203 static ClutterGravity
13204 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13205 {
13206   if (coord->is_fractional)
13207     {
13208       if (coord->v.fraction.x == 0.0)
13209         {
13210           if (coord->v.fraction.y == 0.0)
13211             return CLUTTER_GRAVITY_NORTH_WEST;
13212           else if (coord->v.fraction.y == 0.5)
13213             return CLUTTER_GRAVITY_WEST;
13214           else if (coord->v.fraction.y == 1.0)
13215             return CLUTTER_GRAVITY_SOUTH_WEST;
13216           else
13217             return CLUTTER_GRAVITY_NONE;
13218         }
13219       else if (coord->v.fraction.x == 0.5)
13220         {
13221           if (coord->v.fraction.y == 0.0)
13222             return CLUTTER_GRAVITY_NORTH;
13223           else if (coord->v.fraction.y == 0.5)
13224             return CLUTTER_GRAVITY_CENTER;
13225           else if (coord->v.fraction.y == 1.0)
13226             return CLUTTER_GRAVITY_SOUTH;
13227           else
13228             return CLUTTER_GRAVITY_NONE;
13229         }
13230       else if (coord->v.fraction.x == 1.0)
13231         {
13232           if (coord->v.fraction.y == 0.0)
13233             return CLUTTER_GRAVITY_NORTH_EAST;
13234           else if (coord->v.fraction.y == 0.5)
13235             return CLUTTER_GRAVITY_EAST;
13236           else if (coord->v.fraction.y == 1.0)
13237             return CLUTTER_GRAVITY_SOUTH_EAST;
13238           else
13239             return CLUTTER_GRAVITY_NONE;
13240         }
13241       else
13242         return CLUTTER_GRAVITY_NONE;
13243     }
13244   else
13245     return CLUTTER_GRAVITY_NONE;
13246 }
13247
13248 static void
13249 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13250                                   ClutterGravity  gravity)
13251 {
13252   switch (gravity)
13253     {
13254     case CLUTTER_GRAVITY_NORTH:
13255       coord->v.fraction.x = 0.5;
13256       coord->v.fraction.y = 0.0;
13257       break;
13258
13259     case CLUTTER_GRAVITY_NORTH_EAST:
13260       coord->v.fraction.x = 1.0;
13261       coord->v.fraction.y = 0.0;
13262       break;
13263
13264     case CLUTTER_GRAVITY_EAST:
13265       coord->v.fraction.x = 1.0;
13266       coord->v.fraction.y = 0.5;
13267       break;
13268
13269     case CLUTTER_GRAVITY_SOUTH_EAST:
13270       coord->v.fraction.x = 1.0;
13271       coord->v.fraction.y = 1.0;
13272       break;
13273
13274     case CLUTTER_GRAVITY_SOUTH:
13275       coord->v.fraction.x = 0.5;
13276       coord->v.fraction.y = 1.0;
13277       break;
13278
13279     case CLUTTER_GRAVITY_SOUTH_WEST:
13280       coord->v.fraction.x = 0.0;
13281       coord->v.fraction.y = 1.0;
13282       break;
13283
13284     case CLUTTER_GRAVITY_WEST:
13285       coord->v.fraction.x = 0.0;
13286       coord->v.fraction.y = 0.5;
13287       break;
13288
13289     case CLUTTER_GRAVITY_NORTH_WEST:
13290       coord->v.fraction.x = 0.0;
13291       coord->v.fraction.y = 0.0;
13292       break;
13293
13294     case CLUTTER_GRAVITY_CENTER:
13295       coord->v.fraction.x = 0.5;
13296       coord->v.fraction.y = 0.5;
13297       break;
13298
13299     default:
13300       coord->v.fraction.x = 0.0;
13301       coord->v.fraction.y = 0.0;
13302       break;
13303     }
13304
13305   coord->is_fractional = TRUE;
13306 }
13307
13308 static gboolean
13309 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13310 {
13311   if (coord->is_fractional)
13312     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13313   else
13314     return (coord->v.units.x == 0.0
13315             && coord->v.units.y == 0.0
13316             && coord->v.units.z == 0.0);
13317 }
13318
13319 /**
13320  * clutter_actor_get_flags:
13321  * @self: a #ClutterActor
13322  *
13323  * Retrieves the flags set on @self
13324  *
13325  * Return value: a bitwise or of #ClutterActorFlags or 0
13326  *
13327  * Since: 1.0
13328  */
13329 ClutterActorFlags
13330 clutter_actor_get_flags (ClutterActor *self)
13331 {
13332   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13333
13334   return self->flags;
13335 }
13336
13337 /**
13338  * clutter_actor_set_flags:
13339  * @self: a #ClutterActor
13340  * @flags: the flags to set
13341  *
13342  * Sets @flags on @self
13343  *
13344  * This function will emit notifications for the changed properties
13345  *
13346  * Since: 1.0
13347  */
13348 void
13349 clutter_actor_set_flags (ClutterActor      *self,
13350                          ClutterActorFlags  flags)
13351 {
13352   ClutterActorFlags old_flags;
13353   GObject *obj;
13354   gboolean was_reactive_set, reactive_set;
13355   gboolean was_realized_set, realized_set;
13356   gboolean was_mapped_set, mapped_set;
13357   gboolean was_visible_set, visible_set;
13358
13359   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13360
13361   if (self->flags == flags)
13362     return;
13363
13364   obj = G_OBJECT (self);
13365   g_object_ref (obj);
13366   g_object_freeze_notify (obj);
13367
13368   old_flags = self->flags;
13369
13370   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13371   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13372   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13373   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13374
13375   self->flags |= flags;
13376
13377   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13378   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13379   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13380   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13381
13382   if (reactive_set != was_reactive_set)
13383     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13384
13385   if (realized_set != was_realized_set)
13386     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13387
13388   if (mapped_set != was_mapped_set)
13389     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13390
13391   if (visible_set != was_visible_set)
13392     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13393
13394   g_object_thaw_notify (obj);
13395   g_object_unref (obj);
13396 }
13397
13398 /**
13399  * clutter_actor_unset_flags:
13400  * @self: a #ClutterActor
13401  * @flags: the flags to unset
13402  *
13403  * Unsets @flags on @self
13404  *
13405  * This function will emit notifications for the changed properties
13406  *
13407  * Since: 1.0
13408  */
13409 void
13410 clutter_actor_unset_flags (ClutterActor      *self,
13411                            ClutterActorFlags  flags)
13412 {
13413   ClutterActorFlags old_flags;
13414   GObject *obj;
13415   gboolean was_reactive_set, reactive_set;
13416   gboolean was_realized_set, realized_set;
13417   gboolean was_mapped_set, mapped_set;
13418   gboolean was_visible_set, visible_set;
13419
13420   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13421
13422   obj = G_OBJECT (self);
13423   g_object_freeze_notify (obj);
13424
13425   old_flags = self->flags;
13426
13427   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13428   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13429   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13430   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13431
13432   self->flags &= ~flags;
13433
13434   if (self->flags == old_flags)
13435     return;
13436
13437   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13438   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13439   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13440   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13441
13442   if (reactive_set != was_reactive_set)
13443     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13444
13445   if (realized_set != was_realized_set)
13446     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13447
13448   if (mapped_set != was_mapped_set)
13449     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13450
13451   if (visible_set != was_visible_set)
13452     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13453
13454   g_object_thaw_notify (obj);
13455 }
13456
13457 /**
13458  * clutter_actor_get_transformation_matrix:
13459  * @self: a #ClutterActor
13460  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13461  *
13462  * Retrieves the transformations applied to @self relative to its
13463  * parent.
13464  *
13465  * Since: 1.0
13466  */
13467 void
13468 clutter_actor_get_transformation_matrix (ClutterActor *self,
13469                                          CoglMatrix   *matrix)
13470 {
13471   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13472
13473   cogl_matrix_init_identity (matrix);
13474
13475   _clutter_actor_apply_modelview_transform (self, matrix);
13476 }
13477
13478 void
13479 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13480                                    gboolean      is_in_clone_paint)
13481 {
13482   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13483   self->priv->in_clone_paint = is_in_clone_paint;
13484 }
13485
13486 /**
13487  * clutter_actor_is_in_clone_paint:
13488  * @self: a #ClutterActor
13489  *
13490  * Checks whether @self is being currently painted by a #ClutterClone
13491  *
13492  * This function is useful only inside the ::paint virtual function
13493  * implementations or within handlers for the #ClutterActor::paint
13494  * signal
13495  *
13496  * This function should not be used by applications
13497  *
13498  * Return value: %TRUE if the #ClutterActor is currently being painted
13499  *   by a #ClutterClone, and %FALSE otherwise
13500  *
13501  * Since: 1.0
13502  */
13503 gboolean
13504 clutter_actor_is_in_clone_paint (ClutterActor *self)
13505 {
13506   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13507
13508   return self->priv->in_clone_paint;
13509 }
13510
13511 static gboolean
13512 set_direction_recursive (ClutterActor *actor,
13513                          gpointer      user_data)
13514 {
13515   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
13516
13517   clutter_actor_set_text_direction (actor, text_dir);
13518
13519   return TRUE;
13520 }
13521
13522 /**
13523  * clutter_actor_set_text_direction:
13524  * @self: a #ClutterActor
13525  * @text_dir: the text direction for @self
13526  *
13527  * Sets the #ClutterTextDirection for an actor
13528  *
13529  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
13530  *
13531  * If @self implements #ClutterContainer then this function will recurse
13532  * inside all the children of @self (including the internal ones).
13533  *
13534  * Composite actors not implementing #ClutterContainer, or actors requiring
13535  * special handling when the text direction changes, should connect to
13536  * the #GObject::notify signal for the #ClutterActor:text-direction property
13537  *
13538  * Since: 1.2
13539  */
13540 void
13541 clutter_actor_set_text_direction (ClutterActor         *self,
13542                                   ClutterTextDirection  text_dir)
13543 {
13544   ClutterActorPrivate *priv;
13545
13546   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13547   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
13548
13549   priv = self->priv;
13550
13551   if (priv->text_direction != text_dir)
13552     {
13553       priv->text_direction = text_dir;
13554
13555       /* we need to emit the notify::text-direction first, so that
13556        * the sub-classes can catch that and do specific handling of
13557        * the text direction; see clutter_text_direction_changed_cb()
13558        * inside clutter-text.c
13559        */
13560       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
13561
13562       _clutter_actor_foreach_child (self, set_direction_recursive,
13563                                     GINT_TO_POINTER (text_dir));
13564
13565       clutter_actor_queue_relayout (self);
13566     }
13567 }
13568
13569 void
13570 _clutter_actor_set_has_pointer (ClutterActor *self,
13571                                 gboolean      has_pointer)
13572 {
13573   ClutterActorPrivate *priv = self->priv;
13574
13575   if (priv->has_pointer != has_pointer)
13576     {
13577       priv->has_pointer = has_pointer;
13578
13579       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
13580     }
13581 }
13582
13583 /**
13584  * clutter_actor_get_text_direction:
13585  * @self: a #ClutterActor
13586  *
13587  * Retrieves the value set using clutter_actor_set_text_direction()
13588  *
13589  * If no text direction has been previously set, the default text
13590  * direction, as returned by clutter_get_default_text_direction(), will
13591  * be returned instead
13592  *
13593  * Return value: the #ClutterTextDirection for the actor
13594  *
13595  * Since: 1.2
13596  */
13597 ClutterTextDirection
13598 clutter_actor_get_text_direction (ClutterActor *self)
13599 {
13600   ClutterActorPrivate *priv;
13601
13602   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
13603                         CLUTTER_TEXT_DIRECTION_LTR);
13604
13605   priv = self->priv;
13606
13607   /* if no direction has been set yet use the default */
13608   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
13609     priv->text_direction = clutter_get_default_text_direction ();
13610
13611   return priv->text_direction;
13612 }
13613
13614 /**
13615  * clutter_actor_push_internal:
13616  * @self: a #ClutterActor
13617  *
13618  * Should be used by actors implementing the #ClutterContainer and with
13619  * internal children added through clutter_actor_set_parent(), for instance:
13620  *
13621  * |[
13622  *   static void
13623  *   my_actor_init (MyActor *self)
13624  *   {
13625  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
13626  *
13627  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
13628  *
13629  *     /&ast; calling clutter_actor_set_parent() now will result in
13630  *      &ast; the internal flag being set on a child of MyActor
13631  *      &ast;/
13632  *
13633  *     /&ast; internal child - a background texture &ast;/
13634  *     self->priv->background_tex = clutter_texture_new ();
13635  *     clutter_actor_set_parent (self->priv->background_tex,
13636  *                               CLUTTER_ACTOR (self));
13637  *
13638  *     /&ast; internal child - a label &ast;/
13639  *     self->priv->label = clutter_text_new ();
13640  *     clutter_actor_set_parent (self->priv->label,
13641  *                               CLUTTER_ACTOR (self));
13642  *
13643  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
13644  *
13645  *     /&ast; calling clutter_actor_set_parent() now will not result in
13646  *      &ast; the internal flag being set on a child of MyActor
13647  *      &ast;/
13648  *   }
13649  * ]|
13650  *
13651  * This function will be used by Clutter to toggle an "internal child"
13652  * flag whenever clutter_actor_set_parent() is called; internal children
13653  * are handled differently by Clutter, specifically when destroying their
13654  * parent.
13655  *
13656  * Call clutter_actor_pop_internal() when you finished adding internal
13657  * children.
13658  *
13659  * Nested calls to clutter_actor_push_internal() are allowed, but each
13660  * one must by followed by a clutter_actor_pop_internal() call.
13661  *
13662  * Since: 1.2
13663  *
13664  * Deprecated: 1.10: All children of an actor are accessible through
13665  *   the #ClutterActor API, and #ClutterActor implements the
13666  *   #ClutterContainer interface, so this function is only useful
13667  *   for legacy containers overriding the default implementation.
13668  */
13669 void
13670 clutter_actor_push_internal (ClutterActor *self)
13671 {
13672   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13673
13674   self->priv->internal_child += 1;
13675 }
13676
13677 /**
13678  * clutter_actor_pop_internal:
13679  * @self: a #ClutterActor
13680  *
13681  * Disables the effects of clutter_actor_push_internal().
13682  *
13683  * Since: 1.2
13684  *
13685  * Deprecated: 1.10: All children of an actor are accessible through
13686  *   the #ClutterActor API. This function is only useful for legacy
13687  *   containers overriding the default implementation of the
13688  *   #ClutterContainer interface.
13689  */
13690 void
13691 clutter_actor_pop_internal (ClutterActor *self)
13692 {
13693   ClutterActorPrivate *priv;
13694
13695   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13696
13697   priv = self->priv;
13698
13699   if (priv->internal_child == 0)
13700     {
13701       g_warning ("Mismatched %s: you need to call "
13702                  "clutter_actor_push_composite() at least once before "
13703                  "calling this function", G_STRFUNC);
13704       return;
13705     }
13706
13707   priv->internal_child -= 1;
13708 }
13709
13710 /**
13711  * clutter_actor_has_pointer:
13712  * @self: a #ClutterActor
13713  *
13714  * Checks whether an actor contains the pointer of a
13715  * #ClutterInputDevice
13716  *
13717  * Return value: %TRUE if the actor contains the pointer, and
13718  *   %FALSE otherwise
13719  *
13720  * Since: 1.2
13721  */
13722 gboolean
13723 clutter_actor_has_pointer (ClutterActor *self)
13724 {
13725   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13726
13727   return self->priv->has_pointer;
13728 }
13729
13730 /* XXX: This is a workaround for not being able to break the ABI of
13731  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
13732  * clutter_actor_queue_clipped_redraw() for details.
13733  */
13734 ClutterPaintVolume *
13735 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
13736 {
13737   return g_object_get_data (G_OBJECT (self),
13738                             "-clutter-actor-queue-redraw-clip");
13739 }
13740
13741 void
13742 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
13743                                       ClutterPaintVolume *clip)
13744 {
13745   g_object_set_data (G_OBJECT (self),
13746                      "-clutter-actor-queue-redraw-clip",
13747                      clip);
13748 }
13749
13750 /**
13751  * clutter_actor_has_allocation:
13752  * @self: a #ClutterActor
13753  *
13754  * Checks if the actor has an up-to-date allocation assigned to
13755  * it. This means that the actor should have an allocation: it's
13756  * visible and has a parent. It also means that there is no
13757  * outstanding relayout request in progress for the actor or its
13758  * children (There might be other outstanding layout requests in
13759  * progress that will cause the actor to get a new allocation
13760  * when the stage is laid out, however).
13761  *
13762  * If this function returns %FALSE, then the actor will normally
13763  * be allocated before it is next drawn on the screen.
13764  *
13765  * Return value: %TRUE if the actor has an up-to-date allocation
13766  *
13767  * Since: 1.4
13768  */
13769 gboolean
13770 clutter_actor_has_allocation (ClutterActor *self)
13771 {
13772   ClutterActorPrivate *priv;
13773
13774   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13775
13776   priv = self->priv;
13777
13778   return priv->parent != NULL &&
13779          CLUTTER_ACTOR_IS_VISIBLE (self) &&
13780          !priv->needs_allocation;
13781 }
13782
13783 /**
13784  * clutter_actor_add_action:
13785  * @self: a #ClutterActor
13786  * @action: a #ClutterAction
13787  *
13788  * Adds @action to the list of actions applied to @self
13789  *
13790  * A #ClutterAction can only belong to one actor at a time
13791  *
13792  * The #ClutterActor will hold a reference on @action until either
13793  * clutter_actor_remove_action() or clutter_actor_clear_actions()
13794  * is called
13795  *
13796  * Since: 1.4
13797  */
13798 void
13799 clutter_actor_add_action (ClutterActor  *self,
13800                           ClutterAction *action)
13801 {
13802   ClutterActorPrivate *priv;
13803
13804   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13805   g_return_if_fail (CLUTTER_IS_ACTION (action));
13806
13807   priv = self->priv;
13808
13809   if (priv->actions == NULL)
13810     {
13811       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13812       priv->actions->actor = self;
13813     }
13814
13815   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
13816
13817   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13818 }
13819
13820 /**
13821  * clutter_actor_add_action_with_name:
13822  * @self: a #ClutterActor
13823  * @name: the name to set on the action
13824  * @action: a #ClutterAction
13825  *
13826  * A convenience function for setting the name of a #ClutterAction
13827  * while adding it to the list of actions applied to @self
13828  *
13829  * This function is the logical equivalent of:
13830  *
13831  * |[
13832  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13833  *   clutter_actor_add_action (self, action);
13834  * ]|
13835  *
13836  * Since: 1.4
13837  */
13838 void
13839 clutter_actor_add_action_with_name (ClutterActor  *self,
13840                                     const gchar   *name,
13841                                     ClutterAction *action)
13842 {
13843   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13844   g_return_if_fail (name != NULL);
13845   g_return_if_fail (CLUTTER_IS_ACTION (action));
13846
13847   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13848   clutter_actor_add_action (self, action);
13849 }
13850
13851 /**
13852  * clutter_actor_remove_action:
13853  * @self: a #ClutterActor
13854  * @action: a #ClutterAction
13855  *
13856  * Removes @action from the list of actions applied to @self
13857  *
13858  * The reference held by @self on the #ClutterAction will be released
13859  *
13860  * Since: 1.4
13861  */
13862 void
13863 clutter_actor_remove_action (ClutterActor  *self,
13864                              ClutterAction *action)
13865 {
13866   ClutterActorPrivate *priv;
13867
13868   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13869   g_return_if_fail (CLUTTER_IS_ACTION (action));
13870
13871   priv = self->priv;
13872
13873   if (priv->actions == NULL)
13874     return;
13875
13876   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
13877
13878   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13879 }
13880
13881 /**
13882  * clutter_actor_remove_action_by_name:
13883  * @self: a #ClutterActor
13884  * @name: the name of the action to remove
13885  *
13886  * Removes the #ClutterAction with the given name from the list
13887  * of actions applied to @self
13888  *
13889  * Since: 1.4
13890  */
13891 void
13892 clutter_actor_remove_action_by_name (ClutterActor *self,
13893                                      const gchar  *name)
13894 {
13895   ClutterActorPrivate *priv;
13896   ClutterActorMeta *meta;
13897
13898   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13899   g_return_if_fail (name != NULL);
13900
13901   priv = self->priv;
13902
13903   if (priv->actions == NULL)
13904     return;
13905
13906   meta = _clutter_meta_group_get_meta (priv->actions, name);
13907   if (meta == NULL)
13908     return;
13909
13910   _clutter_meta_group_remove_meta (priv->actions, meta);
13911
13912   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13913 }
13914
13915 /**
13916  * clutter_actor_get_actions:
13917  * @self: a #ClutterActor
13918  *
13919  * Retrieves the list of actions applied to @self
13920  *
13921  * Return value: (transfer container) (element-type Clutter.Action): a copy
13922  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
13923  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13924  *   allocated by the returned #GList
13925  *
13926  * Since: 1.4
13927  */
13928 GList *
13929 clutter_actor_get_actions (ClutterActor *self)
13930 {
13931   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13932
13933   if (self->priv->actions == NULL)
13934     return NULL;
13935
13936   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
13937 }
13938
13939 /**
13940  * clutter_actor_get_action:
13941  * @self: a #ClutterActor
13942  * @name: the name of the action to retrieve
13943  *
13944  * Retrieves the #ClutterAction with the given name in the list
13945  * of actions applied to @self
13946  *
13947  * Return value: (transfer none): a #ClutterAction for the given
13948  *   name, or %NULL. The returned #ClutterAction is owned by the
13949  *   actor and it should not be unreferenced directly
13950  *
13951  * Since: 1.4
13952  */
13953 ClutterAction *
13954 clutter_actor_get_action (ClutterActor *self,
13955                           const gchar  *name)
13956 {
13957   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13958   g_return_val_if_fail (name != NULL, NULL);
13959
13960   if (self->priv->actions == NULL)
13961     return NULL;
13962
13963   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
13964 }
13965
13966 /**
13967  * clutter_actor_clear_actions:
13968  * @self: a #ClutterActor
13969  *
13970  * Clears the list of actions applied to @self
13971  *
13972  * Since: 1.4
13973  */
13974 void
13975 clutter_actor_clear_actions (ClutterActor *self)
13976 {
13977   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13978
13979   if (self->priv->actions == NULL)
13980     return;
13981
13982   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
13983 }
13984
13985 /**
13986  * clutter_actor_add_constraint:
13987  * @self: a #ClutterActor
13988  * @constraint: a #ClutterConstraint
13989  *
13990  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
13991  * to @self
13992  *
13993  * The #ClutterActor will hold a reference on the @constraint until
13994  * either clutter_actor_remove_constraint() or
13995  * clutter_actor_clear_constraints() is called.
13996  *
13997  * Since: 1.4
13998  */
13999 void
14000 clutter_actor_add_constraint (ClutterActor      *self,
14001                               ClutterConstraint *constraint)
14002 {
14003   ClutterActorPrivate *priv;
14004
14005   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14006   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14007
14008   priv = self->priv;
14009
14010   if (priv->constraints == NULL)
14011     {
14012       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14013       priv->constraints->actor = self;
14014     }
14015
14016   _clutter_meta_group_add_meta (priv->constraints,
14017                                 CLUTTER_ACTOR_META (constraint));
14018   clutter_actor_queue_relayout (self);
14019
14020   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14021 }
14022
14023 /**
14024  * clutter_actor_add_constraint_with_name:
14025  * @self: a #ClutterActor
14026  * @name: the name to set on the constraint
14027  * @constraint: a #ClutterConstraint
14028  *
14029  * A convenience function for setting the name of a #ClutterConstraint
14030  * while adding it to the list of constraints applied to @self
14031  *
14032  * This function is the logical equivalent of:
14033  *
14034  * |[
14035  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14036  *   clutter_actor_add_constraint (self, constraint);
14037  * ]|
14038  *
14039  * Since: 1.4
14040  */
14041 void
14042 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14043                                         const gchar       *name,
14044                                         ClutterConstraint *constraint)
14045 {
14046   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14047   g_return_if_fail (name != NULL);
14048   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14049
14050   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14051   clutter_actor_add_constraint (self, constraint);
14052 }
14053
14054 /**
14055  * clutter_actor_remove_constraint:
14056  * @self: a #ClutterActor
14057  * @constraint: a #ClutterConstraint
14058  *
14059  * Removes @constraint from the list of constraints applied to @self
14060  *
14061  * The reference held by @self on the #ClutterConstraint will be released
14062  *
14063  * Since: 1.4
14064  */
14065 void
14066 clutter_actor_remove_constraint (ClutterActor      *self,
14067                                  ClutterConstraint *constraint)
14068 {
14069   ClutterActorPrivate *priv;
14070
14071   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14072   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14073
14074   priv = self->priv;
14075
14076   if (priv->constraints == NULL)
14077     return;
14078
14079   _clutter_meta_group_remove_meta (priv->constraints,
14080                                    CLUTTER_ACTOR_META (constraint));
14081   clutter_actor_queue_relayout (self);
14082
14083   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14084 }
14085
14086 /**
14087  * clutter_actor_remove_constraint_by_name:
14088  * @self: a #ClutterActor
14089  * @name: the name of the constraint to remove
14090  *
14091  * Removes the #ClutterConstraint with the given name from the list
14092  * of constraints applied to @self
14093  *
14094  * Since: 1.4
14095  */
14096 void
14097 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14098                                          const gchar  *name)
14099 {
14100   ClutterActorPrivate *priv;
14101   ClutterActorMeta *meta;
14102
14103   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14104   g_return_if_fail (name != NULL);
14105
14106   priv = self->priv;
14107
14108   if (priv->constraints == NULL)
14109     return;
14110
14111   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14112   if (meta == NULL)
14113     return;
14114
14115   _clutter_meta_group_remove_meta (priv->constraints, meta);
14116   clutter_actor_queue_relayout (self);
14117 }
14118
14119 /**
14120  * clutter_actor_get_constraints:
14121  * @self: a #ClutterActor
14122  *
14123  * Retrieves the list of constraints applied to @self
14124  *
14125  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14126  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14127  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14128  *   allocated by the returned #GList
14129  *
14130  * Since: 1.4
14131  */
14132 GList *
14133 clutter_actor_get_constraints (ClutterActor *self)
14134 {
14135   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14136
14137   if (self->priv->constraints == NULL)
14138     return NULL;
14139
14140   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14141 }
14142
14143 /**
14144  * clutter_actor_get_constraint:
14145  * @self: a #ClutterActor
14146  * @name: the name of the constraint to retrieve
14147  *
14148  * Retrieves the #ClutterConstraint with the given name in the list
14149  * of constraints applied to @self
14150  *
14151  * Return value: (transfer none): a #ClutterConstraint for the given
14152  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14153  *   actor and it should not be unreferenced directly
14154  *
14155  * Since: 1.4
14156  */
14157 ClutterConstraint *
14158 clutter_actor_get_constraint (ClutterActor *self,
14159                               const gchar  *name)
14160 {
14161   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14162   g_return_val_if_fail (name != NULL, NULL);
14163
14164   if (self->priv->constraints == NULL)
14165     return NULL;
14166
14167   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14168 }
14169
14170 /**
14171  * clutter_actor_clear_constraints:
14172  * @self: a #ClutterActor
14173  *
14174  * Clears the list of constraints applied to @self
14175  *
14176  * Since: 1.4
14177  */
14178 void
14179 clutter_actor_clear_constraints (ClutterActor *self)
14180 {
14181   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14182
14183   if (self->priv->constraints == NULL)
14184     return;
14185
14186   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14187
14188   clutter_actor_queue_relayout (self);
14189 }
14190
14191 /**
14192  * clutter_actor_set_clip_to_allocation:
14193  * @self: a #ClutterActor
14194  * @clip_set: %TRUE to apply a clip tracking the allocation
14195  *
14196  * Sets whether @self should be clipped to the same size as its
14197  * allocation
14198  *
14199  * Since: 1.4
14200  */
14201 void
14202 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14203                                       gboolean      clip_set)
14204 {
14205   ClutterActorPrivate *priv;
14206
14207   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14208
14209   clip_set = !!clip_set;
14210
14211   priv = self->priv;
14212
14213   if (priv->clip_to_allocation != clip_set)
14214     {
14215       priv->clip_to_allocation = clip_set;
14216
14217       clutter_actor_queue_redraw (self);
14218
14219       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14220     }
14221 }
14222
14223 /**
14224  * clutter_actor_get_clip_to_allocation:
14225  * @self: a #ClutterActor
14226  *
14227  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14228  *
14229  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14230  *
14231  * Since: 1.4
14232  */
14233 gboolean
14234 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14235 {
14236   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14237
14238   return self->priv->clip_to_allocation;
14239 }
14240
14241 /**
14242  * clutter_actor_add_effect:
14243  * @self: a #ClutterActor
14244  * @effect: a #ClutterEffect
14245  *
14246  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14247  *
14248  * The #ClutterActor will hold a reference on the @effect until either
14249  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14250  * called.
14251  *
14252  * Since: 1.4
14253  */
14254 void
14255 clutter_actor_add_effect (ClutterActor  *self,
14256                           ClutterEffect *effect)
14257 {
14258   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14259   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14260
14261   _clutter_actor_add_effect_internal (self, effect);
14262
14263   clutter_actor_queue_redraw (self);
14264
14265   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14266 }
14267
14268 /**
14269  * clutter_actor_add_effect_with_name:
14270  * @self: a #ClutterActor
14271  * @name: the name to set on the effect
14272  * @effect: a #ClutterEffect
14273  *
14274  * A convenience function for setting the name of a #ClutterEffect
14275  * while adding it to the list of effectss applied to @self
14276  *
14277  * This function is the logical equivalent of:
14278  *
14279  * |[
14280  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14281  *   clutter_actor_add_effect (self, effect);
14282  * ]|
14283  *
14284  * Since: 1.4
14285  */
14286 void
14287 clutter_actor_add_effect_with_name (ClutterActor  *self,
14288                                     const gchar   *name,
14289                                     ClutterEffect *effect)
14290 {
14291   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14292   g_return_if_fail (name != NULL);
14293   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14294
14295   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14296   clutter_actor_add_effect (self, effect);
14297 }
14298
14299 /**
14300  * clutter_actor_remove_effect:
14301  * @self: a #ClutterActor
14302  * @effect: a #ClutterEffect
14303  *
14304  * Removes @effect from the list of effects applied to @self
14305  *
14306  * The reference held by @self on the #ClutterEffect will be released
14307  *
14308  * Since: 1.4
14309  */
14310 void
14311 clutter_actor_remove_effect (ClutterActor  *self,
14312                              ClutterEffect *effect)
14313 {
14314   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14315   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14316
14317   _clutter_actor_remove_effect_internal (self, effect);
14318
14319   clutter_actor_queue_redraw (self);
14320
14321   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14322 }
14323
14324 /**
14325  * clutter_actor_remove_effect_by_name:
14326  * @self: a #ClutterActor
14327  * @name: the name of the effect to remove
14328  *
14329  * Removes the #ClutterEffect with the given name from the list
14330  * of effects applied to @self
14331  *
14332  * Since: 1.4
14333  */
14334 void
14335 clutter_actor_remove_effect_by_name (ClutterActor *self,
14336                                      const gchar  *name)
14337 {
14338   ClutterActorPrivate *priv;
14339   ClutterActorMeta *meta;
14340
14341   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14342   g_return_if_fail (name != NULL);
14343
14344   priv = self->priv;
14345
14346   if (priv->effects == NULL)
14347     return;
14348
14349   meta = _clutter_meta_group_get_meta (priv->effects, name);
14350   if (meta == NULL)
14351     return;
14352
14353   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14354 }
14355
14356 /**
14357  * clutter_actor_get_effects:
14358  * @self: a #ClutterActor
14359  *
14360  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14361  *
14362  * Return value: (transfer container) (element-type Clutter.Effect): a list
14363  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14364  *   list are owned by Clutter and they should not be freed. You should
14365  *   free the returned list using g_list_free() when done
14366  *
14367  * Since: 1.4
14368  */
14369 GList *
14370 clutter_actor_get_effects (ClutterActor *self)
14371 {
14372   ClutterActorPrivate *priv;
14373
14374   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14375
14376   priv = self->priv;
14377
14378   if (priv->effects == NULL)
14379     return NULL;
14380
14381   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14382 }
14383
14384 /**
14385  * clutter_actor_get_effect:
14386  * @self: a #ClutterActor
14387  * @name: the name of the effect to retrieve
14388  *
14389  * Retrieves the #ClutterEffect with the given name in the list
14390  * of effects applied to @self
14391  *
14392  * Return value: (transfer none): a #ClutterEffect for the given
14393  *   name, or %NULL. The returned #ClutterEffect is owned by the
14394  *   actor and it should not be unreferenced directly
14395  *
14396  * Since: 1.4
14397  */
14398 ClutterEffect *
14399 clutter_actor_get_effect (ClutterActor *self,
14400                           const gchar  *name)
14401 {
14402   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14403   g_return_val_if_fail (name != NULL, NULL);
14404
14405   if (self->priv->effects == NULL)
14406     return NULL;
14407
14408   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14409 }
14410
14411 /**
14412  * clutter_actor_clear_effects:
14413  * @self: a #ClutterActor
14414  *
14415  * Clears the list of effects applied to @self
14416  *
14417  * Since: 1.4
14418  */
14419 void
14420 clutter_actor_clear_effects (ClutterActor *self)
14421 {
14422   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14423
14424   if (self->priv->effects == NULL)
14425     return;
14426
14427   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14428
14429   clutter_actor_queue_redraw (self);
14430 }
14431
14432 /**
14433  * clutter_actor_has_key_focus:
14434  * @self: a #ClutterActor
14435  *
14436  * Checks whether @self is the #ClutterActor that has key focus
14437  *
14438  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14439  *
14440  * Since: 1.4
14441  */
14442 gboolean
14443 clutter_actor_has_key_focus (ClutterActor *self)
14444 {
14445   ClutterActor *stage;
14446
14447   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14448
14449   stage = _clutter_actor_get_stage_internal (self);
14450   if (stage == NULL)
14451     return FALSE;
14452
14453   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14454 }
14455
14456 static gboolean
14457 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14458                                       ClutterPaintVolume *pv)
14459 {
14460   ClutterActorPrivate *priv = self->priv;
14461
14462   /* Actors are only expected to report a valid paint volume
14463    * while they have a valid allocation. */
14464   if (G_UNLIKELY (priv->needs_allocation))
14465     {
14466       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14467                     "Actor needs allocation",
14468                     _clutter_actor_get_debug_name (self));
14469       return FALSE;
14470     }
14471
14472   /* Check if there are any handlers connected to the paint
14473    * signal. If there are then all bets are off for what the paint
14474    * volume for this actor might possibly be!
14475    *
14476    * XXX: It's expected that this is going to end up being quite a
14477    * costly check to have to do here, but we haven't come up with
14478    * another solution that can reliably catch paint signal handlers at
14479    * the right time to either avoid artefacts due to invalid stage
14480    * clipping or due to incorrect culling.
14481    *
14482    * Previously we checked in clutter_actor_paint(), but at that time
14483    * we may already be using a stage clip that could be derived from
14484    * an invalid paint-volume. We used to try and handle that by
14485    * queuing a follow up, unclipped, redraw but still the previous
14486    * checking wasn't enough to catch invalid volumes involved in
14487    * culling (considering that containers may derive their volume from
14488    * children that haven't yet been painted)
14489    *
14490    * Longer term, improved solutions could be:
14491    * - Disallow painting in the paint signal, only allow using it
14492    *   for tracking when paints happen. We can add another API that
14493    *   allows monkey patching the paint of arbitrary actors but in a
14494    *   more controlled way and that also supports modifying the
14495    *   paint-volume.
14496    * - If we could be notified somehow when signal handlers are
14497    *   connected we wouldn't have to poll for handlers like this.
14498    */
14499   if (g_signal_has_handler_pending (self,
14500                                     actor_signals[PAINT],
14501                                     0,
14502                                     TRUE))
14503     {
14504       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14505                     "Actor has \"paint\" signal handlers",
14506                     _clutter_actor_get_debug_name (self));
14507       return FALSE;
14508     }
14509
14510   _clutter_paint_volume_init_static (pv, self);
14511
14512   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
14513     {
14514       clutter_paint_volume_free (pv);
14515       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14516                     "Actor failed to report a volume",
14517                     _clutter_actor_get_debug_name (self));
14518       return FALSE;
14519     }
14520
14521   /* since effects can modify the paint volume, we allow them to actually
14522    * do this by making get_paint_volume() "context sensitive"
14523    */
14524   if (priv->effects != NULL)
14525     {
14526       if (priv->current_effect != NULL)
14527         {
14528           const GList *effects, *l;
14529
14530           /* if we are being called from within the paint sequence of
14531            * an actor, get the paint volume up to the current effect
14532            */
14533           effects = _clutter_meta_group_peek_metas (priv->effects);
14534           for (l = effects;
14535                l != NULL || (l != NULL && l->data != priv->current_effect);
14536                l = l->next)
14537             {
14538               if (!_clutter_effect_get_paint_volume (l->data, pv))
14539                 {
14540                   clutter_paint_volume_free (pv);
14541                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14542                                 "Effect (%s) failed to report a volume",
14543                                 _clutter_actor_get_debug_name (self),
14544                                 _clutter_actor_meta_get_debug_name (l->data));
14545                   return FALSE;
14546                 }
14547             }
14548         }
14549       else
14550         {
14551           const GList *effects, *l;
14552
14553           /* otherwise, get the cumulative volume */
14554           effects = _clutter_meta_group_peek_metas (priv->effects);
14555           for (l = effects; l != NULL; l = l->next)
14556             if (!_clutter_effect_get_paint_volume (l->data, pv))
14557               {
14558                 clutter_paint_volume_free (pv);
14559                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14560                               "Effect (%s) failed to report a volume",
14561                               _clutter_actor_get_debug_name (self),
14562                               _clutter_actor_meta_get_debug_name (l->data));
14563                 return FALSE;
14564               }
14565         }
14566     }
14567
14568   return TRUE;
14569 }
14570
14571 /* The public clutter_actor_get_paint_volume API returns a const
14572  * pointer since we return a pointer directly to the cached
14573  * PaintVolume associated with the actor and don't want the user to
14574  * inadvertently modify it, but for internal uses we sometimes need
14575  * access to the same PaintVolume but need to apply some book-keeping
14576  * modifications to it so we don't want a const pointer.
14577  */
14578 static ClutterPaintVolume *
14579 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
14580 {
14581   ClutterActorPrivate *priv;
14582
14583   priv = self->priv;
14584
14585   if (priv->paint_volume_valid)
14586     clutter_paint_volume_free (&priv->paint_volume);
14587
14588   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
14589     {
14590       priv->paint_volume_valid = TRUE;
14591       return &priv->paint_volume;
14592     }
14593   else
14594     {
14595       priv->paint_volume_valid = FALSE;
14596       return NULL;
14597     }
14598 }
14599
14600 /**
14601  * clutter_actor_get_paint_volume:
14602  * @self: a #ClutterActor
14603  *
14604  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
14605  * when a paint volume can't be determined.
14606  *
14607  * The paint volume is defined as the 3D space occupied by an actor
14608  * when being painted.
14609  *
14610  * This function will call the <function>get_paint_volume()</function>
14611  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
14612  * should not usually care about overriding the default implementation,
14613  * unless they are, for instance: painting outside their allocation, or
14614  * actors with a depth factor (not in terms of #ClutterActor:depth but real
14615  * 3D depth).
14616  *
14617  * <note>2D actors overriding <function>get_paint_volume()</function>
14618  * ensure their volume has a depth of 0. (This will be true so long as
14619  * you don't call clutter_paint_volume_set_depth().)</note>
14620  *
14621  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
14622  *   or %NULL if no volume could be determined. The returned pointer
14623  *   is not guaranteed to be valid across multiple frames; if you want
14624  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
14625  *
14626  * Since: 1.6
14627  */
14628 const ClutterPaintVolume *
14629 clutter_actor_get_paint_volume (ClutterActor *self)
14630 {
14631   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14632
14633   return _clutter_actor_get_paint_volume_mutable (self);
14634 }
14635
14636 /**
14637  * clutter_actor_get_transformed_paint_volume:
14638  * @self: a #ClutterActor
14639  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
14640  *    (or %NULL for the stage)
14641  *
14642  * Retrieves the 3D paint volume of an actor like
14643  * clutter_actor_get_paint_volume() does (Please refer to the
14644  * documentation of clutter_actor_get_paint_volume() for more
14645  * details.) and it additionally transforms the paint volume into the
14646  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
14647  * is passed for @relative_to_ancestor)
14648  *
14649  * This can be used by containers that base their paint volume on
14650  * the volume of their children. Such containers can query the
14651  * transformed paint volume of all of its children and union them
14652  * together using clutter_paint_volume_union().
14653  *
14654  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
14655  *   or %NULL if no volume could be determined. The returned pointer is
14656  *   not guaranteed to be valid across multiple frames; if you wish to
14657  *   keep it, you will have to copy it using clutter_paint_volume_copy().
14658  *
14659  * Since: 1.6
14660  */
14661 const ClutterPaintVolume *
14662 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
14663                                             ClutterActor *relative_to_ancestor)
14664 {
14665   const ClutterPaintVolume *volume;
14666   ClutterActor *stage;
14667   ClutterPaintVolume *transformed_volume;
14668
14669   stage = _clutter_actor_get_stage_internal (self);
14670   if (G_UNLIKELY (stage == NULL))
14671     return NULL;
14672
14673   if (relative_to_ancestor == NULL)
14674     relative_to_ancestor = stage;
14675
14676   volume = clutter_actor_get_paint_volume (self);
14677   if (volume == NULL)
14678     return NULL;
14679
14680   transformed_volume =
14681     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
14682
14683   _clutter_paint_volume_copy_static (volume, transformed_volume);
14684
14685   _clutter_paint_volume_transform_relative (transformed_volume,
14686                                             relative_to_ancestor);
14687
14688   return transformed_volume;
14689 }
14690
14691 /**
14692  * clutter_actor_get_paint_box:
14693  * @self: a #ClutterActor
14694  * @box: (out): return location for a #ClutterActorBox
14695  *
14696  * Retrieves the paint volume of the passed #ClutterActor, and
14697  * transforms it into a 2D bounding box in stage coordinates.
14698  *
14699  * This function is useful to determine the on screen area occupied by
14700  * the actor. The box is only an approximation and may often be
14701  * considerably larger due to the optimizations used to calculate the
14702  * box. The box is never smaller though, so it can reliably be used
14703  * for culling.
14704  *
14705  * There are times when a 2D paint box can't be determined, e.g.
14706  * because the actor isn't yet parented under a stage or because
14707  * the actor is unable to determine a paint volume.
14708  *
14709  * Return value: %TRUE if a 2D paint box could be determined, else
14710  * %FALSE.
14711  *
14712  * Since: 1.6
14713  */
14714 gboolean
14715 clutter_actor_get_paint_box (ClutterActor    *self,
14716                              ClutterActorBox *box)
14717 {
14718   ClutterActor *stage;
14719   ClutterPaintVolume *pv;
14720
14721   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14722   g_return_val_if_fail (box != NULL, FALSE);
14723
14724   stage = _clutter_actor_get_stage_internal (self);
14725   if (G_UNLIKELY (!stage))
14726     return FALSE;
14727
14728   pv = _clutter_actor_get_paint_volume_mutable (self);
14729   if (G_UNLIKELY (!pv))
14730     return FALSE;
14731
14732   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
14733
14734   return TRUE;
14735 }
14736
14737 /**
14738  * clutter_actor_has_overlaps:
14739  * @self: A #ClutterActor
14740  *
14741  * Asks the actor's implementation whether it may contain overlapping
14742  * primitives.
14743  *
14744  * For example; Clutter may use this to determine whether the painting
14745  * should be redirected to an offscreen buffer to correctly implement
14746  * the opacity property.
14747  *
14748  * Custom actors can override the default response by implementing the
14749  * #ClutterActor <function>has_overlaps</function> virtual function. See
14750  * clutter_actor_set_offscreen_redirect() for more information.
14751  *
14752  * Return value: %TRUE if the actor may have overlapping primitives, and
14753  *   %FALSE otherwise
14754  *
14755  * Since: 1.8
14756  */
14757 gboolean
14758 clutter_actor_has_overlaps (ClutterActor *self)
14759 {
14760   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14761
14762   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
14763 }
14764
14765 /**
14766  * clutter_actor_has_effects:
14767  * @self: A #ClutterActor
14768  *
14769  * Returns whether the actor has any effects applied.
14770  *
14771  * Return value: %TRUE if the actor has any effects,
14772  *   %FALSE otherwise
14773  *
14774  * Since: 1.10
14775  */
14776 gboolean
14777 clutter_actor_has_effects (ClutterActor *self)
14778 {
14779   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14780
14781   if (self->priv->effects == NULL)
14782     return FALSE;
14783
14784   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
14785 }
14786
14787 /**
14788  * clutter_actor_has_constraints:
14789  * @self: A #ClutterActor
14790  *
14791  * Returns whether the actor has any constraints applied.
14792  *
14793  * Return value: %TRUE if the actor has any constraints,
14794  *   %FALSE otherwise
14795  *
14796  * Since: 1.10
14797  */
14798 gboolean
14799 clutter_actor_has_constraints (ClutterActor *self)
14800 {
14801   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14802
14803   return self->priv->constraints != NULL;
14804 }
14805
14806 /**
14807  * clutter_actor_has_actions:
14808  * @self: A #ClutterActor
14809  *
14810  * Returns whether the actor has any actions applied.
14811  *
14812  * Return value: %TRUE if the actor has any actions,
14813  *   %FALSE otherwise
14814  *
14815  * Since: 1.10
14816  */
14817 gboolean
14818 clutter_actor_has_actions (ClutterActor *self)
14819 {
14820   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14821
14822   return self->priv->actions != NULL;
14823 }
14824
14825 /**
14826  * clutter_actor_get_n_children:
14827  * @self: a #ClutterActor
14828  *
14829  * Retrieves the number of children of @self.
14830  *
14831  * Return value: the number of children of an actor
14832  *
14833  * Since: 1.10
14834  */
14835 gint
14836 clutter_actor_get_n_children (ClutterActor *self)
14837 {
14838   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14839
14840   return self->priv->n_children;
14841 }
14842
14843 /**
14844  * clutter_actor_get_child_at_index:
14845  * @self: a #ClutterActor
14846  * @index_: the position in the list of children
14847  *
14848  * Retrieves the actor at the given @index_ inside the list of
14849  * children of @self.
14850  *
14851  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
14852  *
14853  * Since: 1.10
14854  */
14855 ClutterActor *
14856 clutter_actor_get_child_at_index (ClutterActor *self,
14857                                   gint          index_)
14858 {
14859   ClutterActor *iter;
14860   int i;
14861
14862   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14863   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
14864
14865   for (iter = self->priv->first_child, i = 0;
14866        iter != NULL && i < index_;
14867        iter = iter->priv->next_sibling, i += 1)
14868     ;
14869
14870   return iter;
14871 }
14872
14873 /*< private >
14874  * _clutter_actor_foreach_child:
14875  * @actor: The actor whos children you want to iterate
14876  * @callback: The function to call for each child
14877  * @user_data: Private data to pass to @callback
14878  *
14879  * Calls a given @callback once for each child of the specified @actor and
14880  * passing the @user_data pointer each time.
14881  *
14882  * Return value: returns %TRUE if all children were iterated, else
14883  *    %FALSE if a callback broke out of iteration early.
14884  */
14885 gboolean
14886 _clutter_actor_foreach_child (ClutterActor           *self,
14887                               ClutterForeachCallback  callback,
14888                               gpointer                user_data)
14889 {
14890   ClutterActorPrivate *priv = self->priv;
14891   ClutterActor *iter;
14892   gboolean cont;
14893
14894   for (cont = TRUE, iter = priv->first_child;
14895        cont && iter != NULL;
14896        iter = iter->priv->next_sibling)
14897     {
14898       cont = callback (iter, user_data);
14899     }
14900
14901   return cont;
14902 }
14903
14904 #if 0
14905 /* For debugging purposes this gives us a simple way to print out
14906  * the scenegraph e.g in gdb using:
14907  * [|
14908  *   _clutter_actor_traverse (stage,
14909  *                            0,
14910  *                            clutter_debug_print_actor_cb,
14911  *                            NULL,
14912  *                            NULL);
14913  * |]
14914  */
14915 static ClutterActorTraverseVisitFlags
14916 clutter_debug_print_actor_cb (ClutterActor *actor,
14917                               int depth,
14918                               void *user_data)
14919 {
14920   g_print ("%*s%s:%p\n",
14921            depth * 2, "",
14922            _clutter_actor_get_debug_name (actor),
14923            actor);
14924
14925   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14926 }
14927 #endif
14928
14929 static void
14930 _clutter_actor_traverse_breadth (ClutterActor           *actor,
14931                                  ClutterTraverseCallback callback,
14932                                  gpointer                user_data)
14933 {
14934   GQueue *queue = g_queue_new ();
14935   ClutterActor dummy;
14936   int current_depth = 0;
14937
14938   g_queue_push_tail (queue, actor);
14939   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
14940
14941   while ((actor = g_queue_pop_head (queue)))
14942     {
14943       ClutterActorTraverseVisitFlags flags;
14944
14945       if (actor == &dummy)
14946         {
14947           current_depth++;
14948           g_queue_push_tail (queue, &dummy);
14949           continue;
14950         }
14951
14952       flags = callback (actor, current_depth, user_data);
14953       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14954         break;
14955       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14956         {
14957           ClutterActor *iter;
14958
14959           for (iter = actor->priv->first_child;
14960                iter != NULL;
14961                iter = iter->priv->next_sibling)
14962             {
14963               g_queue_push_tail (queue, iter);
14964             }
14965         }
14966     }
14967
14968   g_queue_free (queue);
14969 }
14970
14971 static ClutterActorTraverseVisitFlags
14972 _clutter_actor_traverse_depth (ClutterActor           *actor,
14973                                ClutterTraverseCallback before_children_callback,
14974                                ClutterTraverseCallback after_children_callback,
14975                                int                     current_depth,
14976                                gpointer                user_data)
14977 {
14978   ClutterActorTraverseVisitFlags flags;
14979
14980   flags = before_children_callback (actor, current_depth, user_data);
14981   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14982     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14983
14984   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14985     {
14986       ClutterActor *iter;
14987
14988       for (iter = actor->priv->first_child;
14989            iter != NULL;
14990            iter = iter->priv->next_sibling)
14991         {
14992           flags = _clutter_actor_traverse_depth (iter,
14993                                                  before_children_callback,
14994                                                  after_children_callback,
14995                                                  current_depth + 1,
14996                                                  user_data);
14997
14998           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14999             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15000         }
15001     }
15002
15003   if (after_children_callback)
15004     return after_children_callback (actor, current_depth, user_data);
15005   else
15006     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15007 }
15008
15009 /* _clutter_actor_traverse:
15010  * @actor: The actor to start traversing the graph from
15011  * @flags: These flags may affect how the traversal is done
15012  * @before_children_callback: A function to call before visiting the
15013  *   children of the current actor.
15014  * @after_children_callback: A function to call after visiting the
15015  *   children of the current actor. (Ignored if
15016  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15017  * @user_data: The private data to pass to the callbacks
15018  *
15019  * Traverses the scenegraph starting at the specified @actor and
15020  * descending through all its children and its children's children.
15021  * For each actor traversed @before_children_callback and
15022  * @after_children_callback are called with the specified
15023  * @user_data, before and after visiting that actor's children.
15024  *
15025  * The callbacks can return flags that affect the ongoing traversal
15026  * such as by skipping over an actors children or bailing out of
15027  * any further traversing.
15028  */
15029 void
15030 _clutter_actor_traverse (ClutterActor              *actor,
15031                          ClutterActorTraverseFlags  flags,
15032                          ClutterTraverseCallback    before_children_callback,
15033                          ClutterTraverseCallback    after_children_callback,
15034                          gpointer                   user_data)
15035 {
15036   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15037     _clutter_actor_traverse_breadth (actor,
15038                                      before_children_callback,
15039                                      user_data);
15040   else /* DEPTH_FIRST */
15041     _clutter_actor_traverse_depth (actor,
15042                                    before_children_callback,
15043                                    after_children_callback,
15044                                    0, /* start depth */
15045                                    user_data);
15046 }
15047
15048 static void
15049 on_layout_manager_changed (ClutterLayoutManager *manager,
15050                            ClutterActor         *self)
15051 {
15052   clutter_actor_queue_relayout (self);
15053 }
15054
15055 /**
15056  * clutter_actor_set_layout_manager:
15057  * @self: a #ClutterActor
15058  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15059  *
15060  * Sets the #ClutterLayoutManager delegate object that will be used to
15061  * lay out the children of @self.
15062  *
15063  * The #ClutterActor will take a reference on the passed @manager which
15064  * will be released either when the layout manager is removed, or when
15065  * the actor is destroyed.
15066  *
15067  * Since: 1.10
15068  */
15069 void
15070 clutter_actor_set_layout_manager (ClutterActor         *self,
15071                                   ClutterLayoutManager *manager)
15072 {
15073   ClutterActorPrivate *priv;
15074
15075   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15076   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15077
15078   priv = self->priv;
15079
15080   if (priv->layout_manager != NULL)
15081     {
15082       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15083                                             G_CALLBACK (on_layout_manager_changed),
15084                                             self);
15085       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15086       g_object_unref (priv->layout_manager);
15087     }
15088
15089   priv->layout_manager = manager;
15090
15091   if (priv->layout_manager != NULL)
15092     {
15093       g_object_ref_sink (priv->layout_manager);
15094       clutter_layout_manager_set_container (priv->layout_manager,
15095                                             CLUTTER_CONTAINER (self));
15096       g_signal_connect (priv->layout_manager, "layout-changed",
15097                         G_CALLBACK (on_layout_manager_changed),
15098                         self);
15099     }
15100
15101   clutter_actor_queue_relayout (self);
15102
15103   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15104 }
15105
15106 /**
15107  * clutter_actor_get_layout_manager:
15108  * @self: a #ClutterActor
15109  *
15110  * Retrieves the #ClutterLayoutManager used by @self.
15111  *
15112  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15113  *   or %NULL
15114  *
15115  * Since: 1.10
15116  */
15117 ClutterLayoutManager *
15118 clutter_actor_get_layout_manager (ClutterActor *self)
15119 {
15120   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15121
15122   return self->priv->layout_manager;
15123 }
15124
15125 static const ClutterLayoutInfo default_layout_info = {
15126   0.f,                          /* fixed-x */
15127   0.f,                          /* fixed-y */
15128   { 0, 0, 0, 0 },               /* margin */
15129   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15130   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15131   0.f, 0.f,                     /* min_width, natural_width */
15132   0.f, 0.f,                     /* natual_width, natural_height */
15133 };
15134
15135 static void
15136 layout_info_free (gpointer data)
15137 {
15138   if (G_LIKELY (data != NULL))
15139     g_slice_free (ClutterLayoutInfo, data);
15140 }
15141
15142 /*< private >
15143  * _clutter_actor_get_layout_info:
15144  * @self: a #ClutterActor
15145  *
15146  * Retrieves a pointer to the ClutterLayoutInfo structure.
15147  *
15148  * If the actor does not have a ClutterLayoutInfo associated to it, one
15149  * will be created and initialized to the default values.
15150  *
15151  * This function should be used for setters.
15152  *
15153  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15154  * instead.
15155  *
15156  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15157  */
15158 ClutterLayoutInfo *
15159 _clutter_actor_get_layout_info (ClutterActor *self)
15160 {
15161   ClutterLayoutInfo *retval;
15162
15163   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15164   if (retval == NULL)
15165     {
15166       retval = g_slice_new (ClutterLayoutInfo);
15167
15168       *retval = default_layout_info;
15169
15170       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15171                                retval,
15172                                layout_info_free);
15173     }
15174
15175   return retval;
15176 }
15177
15178 /*< private >
15179  * _clutter_actor_get_layout_info_or_defaults:
15180  * @self: a #ClutterActor
15181  *
15182  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15183  *
15184  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15185  * then the default structure will be returned.
15186  *
15187  * This function should only be used for getters.
15188  *
15189  * Return value: a const pointer to the ClutterLayoutInfo structure
15190  */
15191 const ClutterLayoutInfo *
15192 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15193 {
15194   const ClutterLayoutInfo *info;
15195
15196   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15197   if (info == NULL)
15198     return &default_layout_info;
15199
15200   return info;
15201 }
15202
15203 /**
15204  * clutter_actor_set_x_align:
15205  * @self: a #ClutterActor
15206  * @x_align: the horizontal alignment policy
15207  *
15208  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15209  * actor received extra horizontal space.
15210  *
15211  * See also the #ClutterActor:x-align property.
15212  *
15213  * Since: 1.10
15214  */
15215 void
15216 clutter_actor_set_x_align (ClutterActor      *self,
15217                            ClutterActorAlign  x_align)
15218 {
15219   ClutterLayoutInfo *info;
15220
15221   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15222
15223   info = _clutter_actor_get_layout_info (self);
15224
15225   if (info->x_align != x_align)
15226     {
15227       info->x_align = x_align;
15228
15229       clutter_actor_queue_relayout (self);
15230
15231       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15232     }
15233 }
15234
15235 /**
15236  * clutter_actor_get_x_align:
15237  * @self: a #ClutterActor
15238  *
15239  * Retrieves the horizontal alignment policy set using
15240  * clutter_actor_set_x_align().
15241  *
15242  * Return value: the horizontal alignment policy.
15243  *
15244  * Since: 1.10
15245  */
15246 ClutterActorAlign
15247 clutter_actor_get_x_align (ClutterActor *self)
15248 {
15249   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15250
15251   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15252 }
15253
15254 /**
15255  * clutter_actor_set_y_align:
15256  * @self: a #ClutterActor
15257  * @y_align: the vertical alignment policy
15258  *
15259  * Sets the vertical alignment policy of a #ClutterActor, in case the
15260  * actor received extra vertical space.
15261  *
15262  * See also the #ClutterActor:y-align property.
15263  *
15264  * Since: 1.10
15265  */
15266 void
15267 clutter_actor_set_y_align (ClutterActor      *self,
15268                            ClutterActorAlign  y_align)
15269 {
15270   ClutterLayoutInfo *info;
15271
15272   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15273
15274   info = _clutter_actor_get_layout_info (self);
15275
15276   if (info->y_align != y_align)
15277     {
15278       info->y_align = y_align;
15279
15280       clutter_actor_queue_relayout (self);
15281
15282       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15283     }
15284 }
15285
15286 /**
15287  * clutter_actor_get_y_align:
15288  * @self: a #ClutterActor
15289  *
15290  * Retrieves the vertical alignment policy set using
15291  * clutter_actor_set_y_align().
15292  *
15293  * Return value: the vertical alignment policy.
15294  *
15295  * Since: 1.10
15296  */
15297 ClutterActorAlign
15298 clutter_actor_get_y_align (ClutterActor *self)
15299 {
15300   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15301
15302   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15303 }
15304
15305
15306 /**
15307  * clutter_margin_new:
15308  *
15309  * Creates a new #ClutterMargin.
15310  *
15311  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15312  *   clutter_margin_free() to free the resources associated with it when
15313  *   done.
15314  *
15315  * Since: 1.10
15316  */
15317 ClutterMargin *
15318 clutter_margin_new (void)
15319 {
15320   return g_slice_new0 (ClutterMargin);
15321 }
15322
15323 /**
15324  * clutter_margin_copy:
15325  * @margin_: a #ClutterMargin
15326  *
15327  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15328  * the newly created structure.
15329  *
15330  * Return value: (transfer full): a copy of the #ClutterMargin.
15331  *
15332  * Since: 1.10
15333  */
15334 ClutterMargin *
15335 clutter_margin_copy (const ClutterMargin *margin_)
15336 {
15337   if (G_LIKELY (margin_ != NULL))
15338     return g_slice_dup (ClutterMargin, margin_);
15339
15340   return NULL;
15341 }
15342
15343 /**
15344  * clutter_margin_free:
15345  * @margin_: a #ClutterMargin
15346  *
15347  * Frees the resources allocated by clutter_margin_new() and
15348  * clutter_margin_copy().
15349  *
15350  * Since: 1.10
15351  */
15352 void
15353 clutter_margin_free (ClutterMargin *margin_)
15354 {
15355   if (G_LIKELY (margin_ != NULL))
15356     g_slice_free (ClutterMargin, margin_);
15357 }
15358
15359 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15360                      clutter_margin_copy,
15361                      clutter_margin_free)
15362
15363 /**
15364  * clutter_actor_set_margin:
15365  * @self: a #ClutterActor
15366  * @margin: a #ClutterMargin
15367  *
15368  * Sets all the components of the margin of a #ClutterActor.
15369  *
15370  * Since: 1.10
15371  */
15372 void
15373 clutter_actor_set_margin (ClutterActor        *self,
15374                           const ClutterMargin *margin)
15375 {
15376   ClutterLayoutInfo *info;
15377   gboolean changed;
15378   GObject *obj;
15379
15380   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15381   g_return_if_fail (margin != NULL);
15382
15383   obj = G_OBJECT (self);
15384   changed = FALSE;
15385
15386   g_object_freeze_notify (obj);
15387
15388   info = _clutter_actor_get_layout_info (self);
15389
15390   if (info->margin.top != margin->top)
15391     {
15392       info->margin.top = margin->top;
15393       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15394       changed = TRUE;
15395     }
15396
15397   if (info->margin.right != margin->right)
15398     {
15399       info->margin.right = margin->right;
15400       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15401       changed = TRUE;
15402     }
15403
15404   if (info->margin.bottom != margin->bottom)
15405     {
15406       info->margin.bottom = margin->bottom;
15407       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15408       changed = TRUE;
15409     }
15410
15411   if (info->margin.left != margin->left)
15412     {
15413       info->margin.left = margin->left;
15414       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15415       changed = TRUE;
15416     }
15417
15418   if (changed)
15419     clutter_actor_queue_relayout (self);
15420
15421   g_object_thaw_notify (obj);
15422 }
15423
15424 /**
15425  * clutter_actor_get_margin:
15426  * @self: a #ClutterActor
15427  * @margin: (out caller-allocates): return location for a #ClutterMargin
15428  *
15429  * Retrieves all the components of the margin of a #ClutterActor.
15430  *
15431  * Since: 1.10
15432  */
15433 void
15434 clutter_actor_get_margin (ClutterActor  *self,
15435                           ClutterMargin *margin)
15436 {
15437   const ClutterLayoutInfo *info;
15438
15439   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15440   g_return_if_fail (margin != NULL);
15441
15442   info = _clutter_actor_get_layout_info_or_defaults (self);
15443
15444   *margin = info->margin;
15445 }
15446
15447 /**
15448  * clutter_actor_set_margin_top:
15449  * @self: a #ClutterActor
15450  * @margin: the top margin
15451  *
15452  * Sets the margin from the top of a #ClutterActor.
15453  *
15454  * Since: 1.10
15455  */
15456 void
15457 clutter_actor_set_margin_top (ClutterActor *self,
15458                               gfloat        margin)
15459 {
15460   ClutterLayoutInfo *info;
15461
15462   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15463   g_return_if_fail (margin >= 0.f);
15464
15465   info = _clutter_actor_get_layout_info (self);
15466
15467   if (info->margin.top == margin)
15468     return;
15469
15470   info->margin.top = margin;
15471
15472   clutter_actor_queue_relayout (self);
15473
15474   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15475 }
15476
15477 /**
15478  * clutter_actor_get_margin_top:
15479  * @self: a #ClutterActor
15480  *
15481  * Retrieves the top margin of a #ClutterActor.
15482  *
15483  * Return value: the top margin
15484  *
15485  * Since: 1.10
15486  */
15487 gfloat
15488 clutter_actor_get_margin_top (ClutterActor *self)
15489 {
15490   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15491
15492   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15493 }
15494
15495 /**
15496  * clutter_actor_set_margin_bottom:
15497  * @self: a #ClutterActor
15498  * @margin: the bottom margin
15499  *
15500  * Sets the margin from the bottom of a #ClutterActor.
15501  *
15502  * Since: 1.10
15503  */
15504 void
15505 clutter_actor_set_margin_bottom (ClutterActor *self,
15506                                  gfloat        margin)
15507 {
15508   ClutterLayoutInfo *info;
15509
15510   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15511   g_return_if_fail (margin >= 0.f);
15512
15513   info = _clutter_actor_get_layout_info (self);
15514
15515   if (info->margin.bottom == margin)
15516     return;
15517
15518   info->margin.bottom = margin;
15519
15520   clutter_actor_queue_relayout (self);
15521
15522   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
15523 }
15524
15525 /**
15526  * clutter_actor_get_margin_bottom:
15527  * @self: a #ClutterActor
15528  *
15529  * Retrieves the bottom margin of a #ClutterActor.
15530  *
15531  * Return value: the bottom margin
15532  *
15533  * Since: 1.10
15534  */
15535 gfloat
15536 clutter_actor_get_margin_bottom (ClutterActor *self)
15537 {
15538   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15539
15540   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
15541 }
15542
15543 /**
15544  * clutter_actor_set_margin_left:
15545  * @self: a #ClutterActor
15546  * @margin: the left margin
15547  *
15548  * Sets the margin from the left of a #ClutterActor.
15549  *
15550  * Since: 1.10
15551  */
15552 void
15553 clutter_actor_set_margin_left (ClutterActor *self,
15554                                gfloat        margin)
15555 {
15556   ClutterLayoutInfo *info;
15557
15558   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15559   g_return_if_fail (margin >= 0.f);
15560
15561   info = _clutter_actor_get_layout_info (self);
15562
15563   if (info->margin.left == margin)
15564     return;
15565
15566   info->margin.left = margin;
15567
15568   clutter_actor_queue_relayout (self);
15569
15570   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
15571 }
15572
15573 /**
15574  * clutter_actor_get_margin_left:
15575  * @self: a #ClutterActor
15576  *
15577  * Retrieves the left margin of a #ClutterActor.
15578  *
15579  * Return value: the left margin
15580  *
15581  * Since: 1.10
15582  */
15583 gfloat
15584 clutter_actor_get_margin_left (ClutterActor *self)
15585 {
15586   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15587
15588   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
15589 }
15590
15591 /**
15592  * clutter_actor_set_margin_right:
15593  * @self: a #ClutterActor
15594  * @margin: the right margin
15595  *
15596  * Sets the margin from the right of a #ClutterActor.
15597  *
15598  * Since: 1.10
15599  */
15600 void
15601 clutter_actor_set_margin_right (ClutterActor *self,
15602                                 gfloat        margin)
15603 {
15604   ClutterLayoutInfo *info;
15605
15606   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15607   g_return_if_fail (margin >= 0.f);
15608
15609   info = _clutter_actor_get_layout_info (self);
15610
15611   if (info->margin.right == margin)
15612     return;
15613
15614   info->margin.right = margin;
15615
15616   clutter_actor_queue_relayout (self);
15617
15618   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
15619 }
15620
15621 /**
15622  * clutter_actor_get_margin_right:
15623  * @self: a #ClutterActor
15624  *
15625  * Retrieves the right margin of a #ClutterActor.
15626  *
15627  * Return value: the right margin
15628  *
15629  * Since: 1.10
15630  */
15631 gfloat
15632 clutter_actor_get_margin_right (ClutterActor *self)
15633 {
15634   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15635
15636   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
15637 }
15638
15639 /**
15640  * clutter_actor_set_background_color:
15641  * @self: a #ClutterActor
15642  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
15643  *  set color
15644  *
15645  * Sets the background color of a #ClutterActor.
15646  *
15647  * The background color will be used to cover the whole allocation of the
15648  * actor. The default background color of an actor is transparent.
15649  *
15650  * To check whether an actor has a background color, you can use the
15651  * #ClutterActor:background-color-set actor property.
15652  *
15653  * Since: 1.10
15654  */
15655 void
15656 clutter_actor_set_background_color (ClutterActor       *self,
15657                                     const ClutterColor *color)
15658 {
15659   ClutterActorPrivate *priv;
15660
15661   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15662
15663   priv = self->priv;
15664
15665   if (color == NULL)
15666     {
15667       priv->bg_color_set = FALSE;
15668       g_object_notify_by_pspec (G_OBJECT (self),
15669                                 obj_props[PROP_BACKGROUND_COLOR_SET]);
15670       return;
15671     }
15672
15673   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
15674     return;
15675
15676   priv->bg_color = *color;
15677   priv->bg_color_set = TRUE;
15678
15679   clutter_actor_queue_redraw (self);
15680
15681   g_object_notify_by_pspec (G_OBJECT (self),
15682                             obj_props[PROP_BACKGROUND_COLOR_SET]);
15683   g_object_notify_by_pspec (G_OBJECT (self),
15684                             obj_props[PROP_BACKGROUND_COLOR]);
15685 }
15686
15687 /**
15688  * clutter_actor_get_background_color:
15689  * @self: a #ClutterActor
15690  * @color: (out caller-allocates): return location for a #ClutterColor
15691  *
15692  * Retrieves the color set using clutter_actor_set_background_color().
15693  *
15694  * Since: 1.10
15695  */
15696 void
15697 clutter_actor_get_background_color (ClutterActor *self,
15698                                     ClutterColor *color)
15699 {
15700   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15701   g_return_if_fail (color != NULL);
15702
15703   *color = self->priv->bg_color;
15704 }
15705
15706 /**
15707  * clutter_actor_get_previous_sibling:
15708  * @self: a #ClutterActor
15709  *
15710  * Retrieves the sibling of @self that comes before it in the list
15711  * of children of @self's parent.
15712  *
15713  * The returned pointer is only valid until the scene graph changes; it
15714  * is not safe to modify the list of children of @self while iterating
15715  * it.
15716  *
15717  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15718  *
15719  * Since: 1.10
15720  */
15721 ClutterActor *
15722 clutter_actor_get_previous_sibling (ClutterActor *self)
15723 {
15724   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15725
15726   return self->priv->prev_sibling;
15727 }
15728
15729 /**
15730  * clutter_actor_get_next_sibling:
15731  * @self: a #ClutterActor
15732  *
15733  * Retrieves the sibling of @self that comes after it in the list
15734  * of children of @self's parent.
15735  *
15736  * The returned pointer is only valid until the scene graph changes; it
15737  * is not safe to modify the list of children of @self while iterating
15738  * it.
15739  *
15740  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15741  *
15742  * Since: 1.10
15743  */
15744 ClutterActor *
15745 clutter_actor_get_next_sibling (ClutterActor *self)
15746 {
15747   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15748
15749   return self->priv->next_sibling;
15750 }
15751
15752 /**
15753  * clutter_actor_get_first_child:
15754  * @self: a #ClutterActor
15755  *
15756  * Retrieves the first child of @self.
15757  *
15758  * The returned pointer is only valid until the scene graph changes; it
15759  * is not safe to modify the list of children of @self while iterating
15760  * it.
15761  *
15762  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15763  *
15764  * Since: 1.10
15765  */
15766 ClutterActor *
15767 clutter_actor_get_first_child (ClutterActor *self)
15768 {
15769   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15770
15771   return self->priv->first_child;
15772 }
15773
15774 /**
15775  * clutter_actor_get_last_child:
15776  * @self: a #ClutterActor
15777  *
15778  * Retrieves the last child of @self.
15779  *
15780  * The returned pointer is only valid until the scene graph changes; it
15781  * is not safe to modify the list of children of @self while iterating
15782  * it.
15783  *
15784  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15785  *
15786  * Since: 1.10
15787  */
15788 ClutterActor *
15789 clutter_actor_get_last_child (ClutterActor *self)
15790 {
15791   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15792
15793   return self->priv->last_child;
15794 }
15795
15796 /* easy way to have properly named fields instead of the dummy ones
15797  * we use in the public structure
15798  */
15799 typedef struct _RealActorIter
15800 {
15801   ClutterActor *root;           /* dummy1 */
15802   ClutterActor *current;        /* dummy2 */
15803   gpointer padding_1;           /* dummy3 */
15804   gint age;                     /* dummy4 */
15805   gpointer padding_2;           /* dummy5 */
15806 } RealActorIter;
15807
15808 /**
15809  * clutter_actor_iter_init:
15810  * @iter: a #ClutterActorIter
15811  * @root: a #ClutterActor
15812  *
15813  * Initializes a #ClutterActorIter, which can then be used to iterate
15814  * efficiently over a section of the scene graph, and associates it
15815  * with @root.
15816  *
15817  * Modifying the scene graph section that contains @root will invalidate
15818  * the iterator.
15819  *
15820  * |[
15821  *   ClutterActorIter iter;
15822  *   ClutterActor *child;
15823  *
15824  *   clutter_actor_iter_init (&iter, container);
15825  *   while (clutter_actor_iter_next (&iter, &child))
15826  *     {
15827  *       /&ast; do something with child &ast;/
15828  *     }
15829  * ]|
15830  *
15831  * Since: 1.10
15832  */
15833 void
15834 clutter_actor_iter_init (ClutterActorIter *iter,
15835                          ClutterActor     *root)
15836 {
15837   RealActorIter *ri = (RealActorIter *) iter;
15838
15839   g_return_if_fail (iter != NULL);
15840   g_return_if_fail (CLUTTER_IS_ACTOR (root));
15841
15842   ri->root = root;
15843   ri->current = NULL;
15844   ri->age = root->priv->age;
15845 }
15846
15847 /**
15848  * clutter_actor_iter_next:
15849  * @iter: a #ClutterActorIter
15850  * @child: (out): return location for a #ClutterActor
15851  *
15852  * Advances the @iter and retrieves the next child of the root #ClutterActor
15853  * that was used to initialize the #ClutterActorIterator.
15854  *
15855  * If the iterator can advance, this function returns %TRUE and sets the
15856  * @child argument.
15857  *
15858  * If the iterator cannot advance, this function returns %FALSE, and
15859  * the contents of @child are undefined.
15860  *
15861  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15862  *
15863  * Since: 1.10
15864  */
15865 gboolean
15866 clutter_actor_iter_next (ClutterActorIter  *iter,
15867                          ClutterActor     **child)
15868 {
15869   RealActorIter *ri = (RealActorIter *) iter;
15870
15871   g_return_val_if_fail (iter != NULL, FALSE);
15872   g_return_val_if_fail (ri->root != NULL, FALSE);
15873 #ifndef G_DISABLE_ASSERT
15874   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15875 #endif
15876
15877   if (ri->current == NULL)
15878     ri->current = ri->root->priv->first_child;
15879   else
15880     ri->current = ri->current->priv->next_sibling;
15881
15882   if (child != NULL)
15883     *child = ri->current;
15884
15885   return ri->current != NULL;
15886 }
15887
15888 /**
15889  * clutter_actor_iter_prev:
15890  * @iter: a #ClutterActorIter
15891  * @child: (out): return location for a #ClutterActor
15892  *
15893  * Advances the @iter and retrieves the previous child of the root
15894  * #ClutterActor that was used to initialize the #ClutterActorIterator.
15895  *
15896  * If the iterator can advance, this function returns %TRUE and sets the
15897  * @child argument.
15898  *
15899  * If the iterator cannot advance, this function returns %FALSE, and
15900  * the contents of @child are undefined.
15901  *
15902  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15903  *
15904  * Since: 1.10
15905  */
15906 gboolean
15907 clutter_actor_iter_prev (ClutterActorIter  *iter,
15908                          ClutterActor     **child)
15909 {
15910   RealActorIter *ri = (RealActorIter *) iter;
15911
15912   g_return_val_if_fail (iter != NULL, FALSE);
15913   g_return_val_if_fail (ri->root != NULL, FALSE);
15914 #ifndef G_DISABLE_ASSERT
15915   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15916 #endif
15917
15918   if (ri->current == NULL)
15919     ri->current = ri->root->priv->last_child;
15920   else
15921     ri->current = ri->current->priv->prev_sibling;
15922
15923   if (child != NULL)
15924     *child = ri->current;
15925
15926   return ri->current != NULL;
15927 }
15928
15929 /**
15930  * clutter_actor_iter_remove:
15931  * @iter: a #ClutterActorIter
15932  *
15933  * Safely removes the #ClutterActor currently pointer to by the iterator
15934  * from its parent.
15935  *
15936  * This function can only be called after clutter_actor_iter_next() or
15937  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15938  * than once for the same actor.
15939  *
15940  * This function will call clutter_actor_remove_child() internally.
15941  *
15942  * Since: 1.10
15943  */
15944 void
15945 clutter_actor_iter_remove (ClutterActorIter *iter)
15946 {
15947   RealActorIter *ri = (RealActorIter *) iter;
15948   ClutterActor *cur;
15949
15950   g_return_if_fail (iter != NULL);
15951   g_return_if_fail (ri->root != NULL);
15952 #ifndef G_DISABLE_ASSERT
15953   g_return_if_fail (ri->age == ri->root->priv->age);
15954 #endif
15955   g_return_if_fail (ri->current != NULL);
15956
15957   cur = ri->current;
15958
15959   if (cur != NULL)
15960     {
15961       ri->current = cur->priv->prev_sibling;
15962
15963       clutter_actor_remove_child_internal (ri->root, cur,
15964                                            REMOVE_CHILD_DEFAULT_FLAGS);
15965
15966       ri->age += 1;
15967     }
15968 }
15969
15970 /**
15971  * clutter_actor_iter_destroy:
15972  * @iter: a #ClutterActorIter
15973  *
15974  * Safely destroys the #ClutterActor currently pointer to by the iterator
15975  * from its parent.
15976  *
15977  * This function can only be called after clutter_actor_iter_next() or
15978  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15979  * than once for the same actor.
15980  *
15981  * This function will call clutter_actor_destroy() internally.
15982  *
15983  * Since: 1.10
15984  */
15985 void
15986 clutter_actor_iter_destroy (ClutterActorIter *iter)
15987 {
15988   RealActorIter *ri = (RealActorIter *) iter;
15989   ClutterActor *cur;
15990
15991   g_return_if_fail (iter != NULL);
15992   g_return_if_fail (ri->root != NULL);
15993 #ifndef G_DISABLE_ASSERT
15994   g_return_if_fail (ri->age == ri->root->priv->age);
15995 #endif
15996   g_return_if_fail (ri->current != NULL);
15997
15998   cur = ri->current;
15999
16000   if (cur != NULL)
16001     {
16002       ri->current = cur->priv->prev_sibling;
16003
16004       clutter_actor_destroy (cur);
16005
16006       ri->age += 1;
16007     }
16008 }