actor: Ensure static scope to allocation-changed arguments
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: Base abstract class for all visual stage actors.
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-events">
119  *   <title>Handling events on an actor</title>
120  *   <para>A #ClutterActor can receive and handle input device events, for
121  *   instance pointer events and key events, as long as its
122  *   #ClutterActor:reactive property is set to %TRUE.</para>
123  *   <para>Once an actor has been determined to be the source of an event,
124  *   Clutter will traverse the scene graph from the top-level actor towards the
125  *   event source, emitting the #ClutterActor::captured-event signal on each
126  *   ancestor until it reaches the source; this phase is also called
127  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
128  *   stopped, the graph is walked backwards, from the source actor to the
129  *   top-level, and the #ClutterActor::event signal, along with other event
130  *   signals if needed, is emitted; this phase is also called <emphasis>the
131  *   bubble phase</emphasis>. At any point of the signal emission, signal
132  *   handlers can stop the propagation through the scene graph by returning
133  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
134  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
135  * </refsect2>
136  *
137  * <refsect2 id="ClutterActor-subclassing">
138  *   <title>Implementing an actor</title>
139  *   <para>Careful consideration should be given when deciding to implement
140  *   a #ClutterActor sub-class. It is generally recommended to implement a
141  *   sub-class of #ClutterActor only for actors that should be used as leaf
142  *   nodes of a scene graph.</para>
143  *   <para>If your actor should be painted in a custom way, you should
144  *   override the #ClutterActor::paint signal class handler. You can either
145  *   opt to chain up to the parent class implementation or decide to fully
146  *   override the default paint implementation; Clutter will set up the
147  *   transformations and clip regions prior to emitting the #ClutterActor::paint
148  *   signal.</para>
149  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
150  *   #ClutterActorClass.get_preferred_height() virtual functions it is
151  *   possible to change or provide the preferred size of an actor; similarly,
152  *   by overriding the #ClutterActorClass.allocate() virtual function it is
153  *   possible to control the layout of the children of an actor. Make sure to
154  *   always chain up to the parent implementation of the
155  *   #ClutterActorClass.allocate() virtual function.</para>
156  *   <para>In general, it is strongly encouraged to use delegation and
157  *   composition instead of direct subclassing.</para>
158  * </refsect2>
159  *
160  * <refsect2 id="ClutterActor-script">
161  *   <title>ClutterActor custom properties for #ClutterScript</title>
162  *   <para>#ClutterActor defines a custom "rotation" property which
163  *   allows a short-hand description of the rotations to be applied
164  *   to an actor.</para>
165  *   <para>The syntax of the "rotation" property is the following:</para>
166  *   <informalexample>
167  *     <programlisting>
168  * "rotation" : [
169  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
170  * ]
171  *     </programlisting>
172  *   </informalexample>
173  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
174  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
175  *   floating point value representing the rotation angle on the given axis,
176  *   in degrees.</para>
177  *   <para>The <emphasis>center</emphasis> array is optional, and if present
178  *   it must contain the center of rotation as described by two coordinates:
179  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
180  *   "z-axis".</para>
181  *   <para>#ClutterActor will also parse every positional and dimensional
182  *   property defined as a string through clutter_units_from_string(); you
183  *   should read the documentation for the #ClutterUnits parser format for
184  *   the valid units and syntax.</para>
185  * </refsect2>
186  *
187  * <refsect2 id="ClutterActor-animating">
188  *   <title>Custom animatable properties</title>
189  *   <para>#ClutterActor allows accessing properties of #ClutterAction
190  *   and #ClutterConstraint instances associated to an actor instance
191  *   for animation purposes.</para>
192  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
193  *   property it is necessary to set the #ClutterActorMeta:name property on the
194  *   given action or constraint.</para>
195  *   <para>The property can be accessed using the following syntax:</para>
196  *   <informalexample>
197  *     <programlisting>
198  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
199  *     </programlisting>
200  *   </informalexample>
201  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
202  *   <para>The <emphasis>section</emphasis> fragment can be one between
203  *   "actions", "constraints" and "effects".</para>
204  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
205  *   action or constraint, as specified by the #ClutterActorMeta:name
206  *   property.</para>
207  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
208  *   action or constraint property to be animated.</para>
209  *   <para>The example below animates a #ClutterBindConstraint applied to an
210  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
211  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
212  *   its initial state is fully transparent and overlapping the actor to
213  *   which is bound to. </para>
214  *   <informalexample><programlisting>
215  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
216  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
217  * clutter_actor_add_constraint (rect, constraint);
218  *
219  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
220  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
221  * clutter_actor_add_constraint (rect, constraint);
222  *
223  * clutter_actor_set_reactive (rect, TRUE);
224  * clutter_actor_set_opacity (rect, 0);
225  *
226  * g_signal_connect (rect, "button-press-event",
227  *                   G_CALLBACK (on_button_press),
228  *                   NULL);
229  *   </programlisting></informalexample>
230  *   <para>On button press, the rectangle "slides" from behind the actor to
231  *   which is bound to, using the #ClutterBindConstraint:offset property and
232  *   the #ClutterActor:opacity property.</para>
233  *   <informalexample><programlisting>
234  * float new_offset = clutter_actor_get_width (origin) + h_padding;
235  *
236  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
237  *                        "opacity", 255,
238  *                        "@constraints.bind-x.offset", new_offset,
239  *                        NULL);
240  *   </programlisting></informalexample>
241  * </refsect2>
242  */
243
244 /**
245  * CLUTTER_ACTOR_IS_MAPPED:
246  * @a: a #ClutterActor
247  *
248  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
249  *
250  * The mapped state is set when the actor is visible and all its parents up
251  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
252  *
253  * This check can be used to see if an actor is going to be painted, as only
254  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
255  *
256  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
257  * not be checked directly; instead, the recommended usage is to connect a
258  * handler on the #GObject::notify signal for the #ClutterActor:mapped
259  * property of #ClutterActor, and check the presence of
260  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
261  *
262  * It is also important to note that Clutter may delay the changes of
263  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
264  * limitations, or during the reparenting of an actor, to optimize
265  * unnecessary (and potentially expensive) state changes.
266  *
267  * Since: 0.2
268  */
269
270 /**
271  * CLUTTER_ACTOR_IS_REALIZED:
272  * @a: a #ClutterActor
273  *
274  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
275  *
276  * The realized state has an actor-dependant interpretation. If an
277  * actor wants to delay allocating resources until it is attached to a
278  * stage, it may use the realize state to do so. However it is
279  * perfectly acceptable for an actor to allocate Cogl resources before
280  * being realized because there is only one drawing context used by Clutter
281  * so any resources will work on any stage.  If an actor is mapped it
282  * must also be realized, but an actor can be realized and unmapped
283  * (this is so hiding an actor temporarily doesn't do an expensive
284  * unrealize/realize).
285  *
286  * To be realized an actor must be inside a stage, and all its parents
287  * must be realized.
288  *
289  * Since: 0.2
290  */
291
292 /**
293  * CLUTTER_ACTOR_IS_VISIBLE:
294  * @a: a #ClutterActor
295  *
296  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
297  * Equivalent to the ClutterActor::visible object property.
298  *
299  * Note that an actor is only painted onscreen if it's mapped, which
300  * means it's visible, and all its parents are visible, and one of the
301  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
302  *
303  * Since: 0.2
304  */
305
306 /**
307  * CLUTTER_ACTOR_IS_REACTIVE:
308  * @a: a #ClutterActor
309  *
310  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
311  *
312  * Only reactive actors will receive event-related signals.
313  *
314  * Since: 0.6
315  */
316
317 #ifdef HAVE_CONFIG_H
318 #include "config.h"
319 #endif
320
321 #include <math.h>
322
323 #include "cogl/cogl.h"
324
325 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
326 #define CLUTTER_ENABLE_EXPERIMENTAL_API
327
328 #include "clutter-actor-private.h"
329
330 #include "clutter-action.h"
331 #include "clutter-actor-meta-private.h"
332 #include "clutter-animatable.h"
333 #include "clutter-color-static.h"
334 #include "clutter-color.h"
335 #include "clutter-constraint.h"
336 #include "clutter-container.h"
337 #include "clutter-debug.h"
338 #include "clutter-effect-private.h"
339 #include "clutter-enum-types.h"
340 #include "clutter-fixed-layout.h"
341 #include "clutter-flatten-effect.h"
342 #include "clutter-interval.h"
343 #include "clutter-main.h"
344 #include "clutter-marshal.h"
345 #include "clutter-paint-volume-private.h"
346 #include "clutter-private.h"
347 #include "clutter-profile.h"
348 #include "clutter-scriptable.h"
349 #include "clutter-script-private.h"
350 #include "clutter-stage-private.h"
351 #include "clutter-units.h"
352
353 #include "deprecated/clutter-behaviour.h"
354 #include "deprecated/clutter-container.h"
355
356 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
357 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
358
359 /* Internal enum used to control mapped state update.  This is a hint
360  * which indicates when to do something other than just enforce
361  * invariants.
362  */
363 typedef enum {
364   MAP_STATE_CHECK,           /* just enforce invariants. */
365   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
366                               * used when about to unparent.
367                               */
368   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
369                               * used to set mapped on toplevels.
370                               */
371   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
372                               * used just before unmapping parent.
373                               */
374 } MapStateChange;
375
376 /* 3 entries should be a good compromise, few layout managers
377  * will ask for 3 different preferred size in each allocation cycle */
378 #define N_CACHED_SIZE_REQUESTS 3
379
380 struct _ClutterActorPrivate
381 {
382   /* request mode */
383   ClutterRequestMode request_mode;
384
385   /* our cached size requests for different width / height */
386   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
387   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
388
389   /* An age of 0 means the entry is not set */
390   guint cached_height_age;
391   guint cached_width_age;
392
393   /* the bounding box of the actor, relative to the parent's
394    * allocation
395    */
396   ClutterActorBox allocation;
397   ClutterAllocationFlags allocation_flags;
398
399   /* depth */
400   gfloat z;
401
402   /* clip, in actor coordinates */
403   cairo_rectangle_t clip;
404
405   /* the cached transformation matrix; see apply_transform() */
406   CoglMatrix transform;
407
408   guint8 opacity;
409   gint opacity_override;
410
411   ClutterOffscreenRedirect offscreen_redirect;
412
413   /* This is an internal effect used to implement the
414      offscreen-redirect property */
415   ClutterEffect *flatten_effect;
416
417   /* scene graph */
418   ClutterActor *parent;
419   ClutterActor *prev_sibling;
420   ClutterActor *next_sibling;
421   ClutterActor *first_child;
422   ClutterActor *last_child;
423
424   gint n_children;
425
426   /* tracks whenever the children of an actor are changed; the
427    * age is incremented by 1 whenever an actor is added or
428    * removed. the age is not incremented when the first or the
429    * last child pointers are changed, or when grandchildren of
430    * an actor are changed.
431    */
432   gint age;
433
434   gchar *name; /* a non-unique name, used for debugging */
435   guint32 id; /* unique id, used for backward compatibility */
436
437   gint32 pick_id; /* per-stage unique id, used for picking */
438
439   /* a back-pointer to the Pango context that we can use
440    * to create pre-configured PangoLayout
441    */
442   PangoContext *pango_context;
443
444   /* the text direction configured for this child - either by
445    * application code, or by the actor's parent
446    */
447   ClutterTextDirection text_direction;
448
449   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
450   gint internal_child;
451
452   /* meta classes */
453   ClutterMetaGroup *actions;
454   ClutterMetaGroup *constraints;
455   ClutterMetaGroup *effects;
456
457   /* delegate object used to allocate the children of this actor */
458   ClutterLayoutManager *layout_manager;
459
460   /* used when painting, to update the paint volume */
461   ClutterEffect *current_effect;
462
463   /* This is used to store an effect which needs to be redrawn. A
464      redraw can be queued to start from a particular effect. This is
465      used by parametrised effects that can cache an image of the
466      actor. If a parameter of the effect changes then it only needs to
467      redraw the cached image, not the actual actor. The pointer is
468      only valid if is_dirty == TRUE. If the pointer is NULL then the
469      whole actor is dirty. */
470   ClutterEffect *effect_to_redraw;
471
472   /* This is used when painting effects to implement the
473      clutter_actor_continue_paint() function. It points to the node in
474      the list of effects that is next in the chain */
475   const GList *next_effect_to_paint;
476
477   ClutterPaintVolume paint_volume;
478
479   /* NB: This volume isn't relative to this actor, it is in eye
480    * coordinates so that it can remain valid after the actor changes.
481    */
482   ClutterPaintVolume last_paint_volume;
483
484   ClutterStageQueueRedrawEntry *queue_redraw_entry;
485
486   ClutterColor bg_color;
487
488   /* bitfields */
489
490   /* fixed position and sizes */
491   guint position_set                : 1;
492   guint min_width_set               : 1;
493   guint min_height_set              : 1;
494   guint natural_width_set           : 1;
495   guint natural_height_set          : 1;
496   /* cached request is invalid (implies allocation is too) */
497   guint needs_width_request         : 1;
498   /* cached request is invalid (implies allocation is too) */
499   guint needs_height_request        : 1;
500   /* cached allocation is invalid (request has changed, probably) */
501   guint needs_allocation            : 1;
502   guint show_on_set_parent          : 1;
503   guint has_clip                    : 1;
504   guint clip_to_allocation          : 1;
505   guint enable_model_view_transform : 1;
506   guint enable_paint_unmapped       : 1;
507   guint has_pointer                 : 1;
508   guint propagated_one_redraw       : 1;
509   guint paint_volume_valid          : 1;
510   guint last_paint_volume_valid     : 1;
511   guint in_clone_paint              : 1;
512   guint transform_valid             : 1;
513   /* This is TRUE if anything has queued a redraw since we were last
514      painted. In this case effect_to_redraw will point to an effect
515      the redraw was queued from or it will be NULL if the redraw was
516      queued without an effect. */
517   guint is_dirty                    : 1;
518   guint bg_color_set                : 1;
519 };
520
521 enum
522 {
523   PROP_0,
524
525   PROP_NAME,
526
527   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
528    * when set they force a size request, when gotten they
529    * get the allocation if the allocation is valid, and the
530    * request otherwise
531    */
532   PROP_X,
533   PROP_Y,
534   PROP_WIDTH,
535   PROP_HEIGHT,
536
537   /* Then the rest of these size-related properties are the "actual"
538    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
539    */
540   PROP_FIXED_X,
541   PROP_FIXED_Y,
542
543   PROP_FIXED_POSITION_SET,
544
545   PROP_MIN_WIDTH,
546   PROP_MIN_WIDTH_SET,
547
548   PROP_MIN_HEIGHT,
549   PROP_MIN_HEIGHT_SET,
550
551   PROP_NATURAL_WIDTH,
552   PROP_NATURAL_WIDTH_SET,
553
554   PROP_NATURAL_HEIGHT,
555   PROP_NATURAL_HEIGHT_SET,
556
557   PROP_REQUEST_MODE,
558
559   /* Allocation properties are read-only */
560   PROP_ALLOCATION,
561
562   PROP_DEPTH,
563
564   PROP_CLIP,
565   PROP_HAS_CLIP,
566   PROP_CLIP_TO_ALLOCATION,
567
568   PROP_OPACITY,
569
570   PROP_OFFSCREEN_REDIRECT,
571
572   PROP_VISIBLE,
573   PROP_MAPPED,
574   PROP_REALIZED,
575   PROP_REACTIVE,
576
577   PROP_SCALE_X,
578   PROP_SCALE_Y,
579   PROP_SCALE_CENTER_X,
580   PROP_SCALE_CENTER_Y,
581   PROP_SCALE_GRAVITY,
582
583   PROP_ROTATION_ANGLE_X,
584   PROP_ROTATION_ANGLE_Y,
585   PROP_ROTATION_ANGLE_Z,
586   PROP_ROTATION_CENTER_X,
587   PROP_ROTATION_CENTER_Y,
588   PROP_ROTATION_CENTER_Z,
589   /* This property only makes sense for the z rotation because the
590      others would depend on the actor having a size along the
591      z-axis */
592   PROP_ROTATION_CENTER_Z_GRAVITY,
593
594   PROP_ANCHOR_X,
595   PROP_ANCHOR_Y,
596   PROP_ANCHOR_GRAVITY,
597
598   PROP_SHOW_ON_SET_PARENT,
599
600   PROP_TEXT_DIRECTION,
601   PROP_HAS_POINTER,
602
603   PROP_ACTIONS,
604   PROP_CONSTRAINTS,
605   PROP_EFFECT,
606
607   PROP_LAYOUT_MANAGER,
608
609   PROP_X_ALIGN,
610   PROP_Y_ALIGN,
611   PROP_MARGIN_TOP,
612   PROP_MARGIN_BOTTOM,
613   PROP_MARGIN_LEFT,
614   PROP_MARGIN_RIGHT,
615
616   PROP_BACKGROUND_COLOR,
617   PROP_BACKGROUND_COLOR_SET,
618
619   PROP_FIRST_CHILD,
620   PROP_LAST_CHILD,
621
622   PROP_LAST
623 };
624
625 static GParamSpec *obj_props[PROP_LAST];
626
627 enum
628 {
629   SHOW,
630   HIDE,
631   DESTROY,
632   PARENT_SET,
633   KEY_FOCUS_IN,
634   KEY_FOCUS_OUT,
635   PAINT,
636   PICK,
637   REALIZE,
638   UNREALIZE,
639   QUEUE_REDRAW,
640   QUEUE_RELAYOUT,
641   EVENT,
642   CAPTURED_EVENT,
643   BUTTON_PRESS_EVENT,
644   BUTTON_RELEASE_EVENT,
645   SCROLL_EVENT,
646   KEY_PRESS_EVENT,
647   KEY_RELEASE_EVENT,
648   MOTION_EVENT,
649   ENTER_EVENT,
650   LEAVE_EVENT,
651   ALLOCATION_CHANGED,
652
653   LAST_SIGNAL
654 };
655
656 static guint actor_signals[LAST_SIGNAL] = { 0, };
657
658 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
659 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
660 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
661 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
662
663 /* These setters are all static for now, maybe they should be in the
664  * public API, but they are perhaps obscure enough to leave only as
665  * properties
666  */
667 static void clutter_actor_set_min_width          (ClutterActor *self,
668                                                   gfloat        min_width);
669 static void clutter_actor_set_min_height         (ClutterActor *self,
670                                                   gfloat        min_height);
671 static void clutter_actor_set_natural_width      (ClutterActor *self,
672                                                   gfloat        natural_width);
673 static void clutter_actor_set_natural_height     (ClutterActor *self,
674                                                   gfloat        natural_height);
675 static void clutter_actor_set_min_width_set      (ClutterActor *self,
676                                                   gboolean      use_min_width);
677 static void clutter_actor_set_min_height_set     (ClutterActor *self,
678                                                   gboolean      use_min_height);
679 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
680                                                   gboolean  use_natural_width);
681 static void clutter_actor_set_natural_height_set (ClutterActor *self,
682                                                   gboolean  use_natural_height);
683 static void clutter_actor_update_map_state       (ClutterActor  *self,
684                                                   MapStateChange change);
685 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
686
687 /* Helper routines for managing anchor coords */
688 static void clutter_anchor_coord_get_units (ClutterActor      *self,
689                                             const AnchorCoord *coord,
690                                             gfloat            *x,
691                                             gfloat            *y,
692                                             gfloat            *z);
693 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
694                                             gfloat             x,
695                                             gfloat             y,
696                                             gfloat             z);
697
698 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
699 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
700                                                         ClutterGravity     gravity);
701
702 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
703
704 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
705
706 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
707                                                                ClutterActor *ancestor,
708                                                                CoglMatrix *matrix);
709
710 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
711
712 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
713
714 static void on_layout_manager_changed (ClutterLayoutManager *manager,
715                                        ClutterActor         *self);
716
717 /* Helper macro which translates by the anchor coord, applies the
718    given transformation and then translates back */
719 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
720   gfloat _tx, _ty, _tz;                                                \
721   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
722   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
723   { _transform; }                                                      \
724   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
725
726 static GQuark quark_shader_data = 0;
727 static GQuark quark_actor_layout_info = 0;
728 static GQuark quark_actor_transform_info = 0;
729
730 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
731                          clutter_actor,
732                          G_TYPE_INITIALLY_UNOWNED,
733                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
734                                                 clutter_container_iface_init)
735                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
736                                                 clutter_scriptable_iface_init)
737                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
738                                                 clutter_animatable_iface_init)
739                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
740                                                 atk_implementor_iface_init));
741
742 /*< private >
743  * clutter_actor_get_debug_name:
744  * @actor: a #ClutterActor
745  *
746  * Retrieves a printable name of @actor for debugging messages
747  *
748  * Return value: a string with a printable name
749  */
750 const gchar *
751 _clutter_actor_get_debug_name (ClutterActor *actor)
752 {
753   return actor->priv->name != NULL ? actor->priv->name
754                                    : G_OBJECT_TYPE_NAME (actor);
755 }
756
757 #ifdef CLUTTER_ENABLE_DEBUG
758 /* XXX - this is for debugging only, remove once working (or leave
759  * in only in some debug mode). Should leave it for a little while
760  * until we're confident in the new map/realize/visible handling.
761  */
762 static inline void
763 clutter_actor_verify_map_state (ClutterActor *self)
764 {
765   ClutterActorPrivate *priv = self->priv;
766
767   if (CLUTTER_ACTOR_IS_REALIZED (self))
768     {
769       /* all bets are off during reparent when we're potentially realized,
770        * but should not be according to invariants
771        */
772       if (!CLUTTER_ACTOR_IN_REPARENT (self))
773         {
774           if (priv->parent == NULL)
775             {
776               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
777                 {
778                 }
779               else
780                 g_warning ("Realized non-toplevel actor '%s' should "
781                            "have a parent",
782                            _clutter_actor_get_debug_name (self));
783             }
784           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
785             {
786               g_warning ("Realized actor %s has an unrealized parent %s",
787                          _clutter_actor_get_debug_name (self),
788                          _clutter_actor_get_debug_name (priv->parent));
789             }
790         }
791     }
792
793   if (CLUTTER_ACTOR_IS_MAPPED (self))
794     {
795       if (!CLUTTER_ACTOR_IS_REALIZED (self))
796         g_warning ("Actor '%s' is mapped but not realized",
797                    _clutter_actor_get_debug_name (self));
798
799       /* remaining bets are off during reparent when we're potentially
800        * mapped, but should not be according to invariants
801        */
802       if (!CLUTTER_ACTOR_IN_REPARENT (self))
803         {
804           if (priv->parent == NULL)
805             {
806               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
807                 {
808                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
809                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
810                     {
811                       g_warning ("Toplevel actor '%s' is mapped "
812                                  "but not visible",
813                                  _clutter_actor_get_debug_name (self));
814                     }
815                 }
816               else
817                 {
818                   g_warning ("Mapped actor '%s' should have a parent",
819                              _clutter_actor_get_debug_name (self));
820                 }
821             }
822           else
823             {
824               ClutterActor *iter = self;
825
826               /* check for the enable_paint_unmapped flag on the actor
827                * and parents; if the flag is enabled at any point of this
828                * branch of the scene graph then all the later checks
829                * become pointless
830                */
831               while (iter != NULL)
832                 {
833                   if (iter->priv->enable_paint_unmapped)
834                     return;
835
836                   iter = iter->priv->parent;
837                 }
838
839               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
840                 {
841                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
842                              "is not visible",
843                              _clutter_actor_get_debug_name (self),
844                              _clutter_actor_get_debug_name (priv->parent));
845                 }
846
847               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
848                 {
849                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
850                              "is not realized",
851                              _clutter_actor_get_debug_name (self),
852                              _clutter_actor_get_debug_name (priv->parent));
853                 }
854
855               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
856                 {
857                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
858                     g_warning ("Actor '%s' is mapped but its non-toplevel "
859                                "parent '%s' is not mapped",
860                                _clutter_actor_get_debug_name (self),
861                                _clutter_actor_get_debug_name (priv->parent));
862                 }
863             }
864         }
865     }
866 }
867
868 #endif /* CLUTTER_ENABLE_DEBUG */
869
870 static void
871 clutter_actor_set_mapped (ClutterActor *self,
872                           gboolean      mapped)
873 {
874   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
875     return;
876
877   if (mapped)
878     {
879       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
880       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
881     }
882   else
883     {
884       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
885       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
886     }
887 }
888
889 /* this function updates the mapped and realized states according to
890  * invariants, in the appropriate order.
891  */
892 static void
893 clutter_actor_update_map_state (ClutterActor  *self,
894                                 MapStateChange change)
895 {
896   gboolean was_mapped;
897
898   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
899
900   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
901     {
902       /* the mapped flag on top-level actors must be set by the
903        * per-backend implementation because it might be asynchronous.
904        *
905        * That is, the MAPPED flag on toplevels currently tracks the X
906        * server mapped-ness of the window, while the expected behavior
907        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
908        * This creates some weird complexity by breaking the invariant
909        * that if we're visible and all ancestors shown then we are
910        * also mapped - instead, we are mapped if all ancestors
911        * _possibly excepting_ the stage are mapped. The stage
912        * will map/unmap for example when it is minimized or
913        * moved to another workspace.
914        *
915        * So, the only invariant on the stage is that if visible it
916        * should be realized, and that it has to be visible to be
917        * mapped.
918        */
919       if (CLUTTER_ACTOR_IS_VISIBLE (self))
920         clutter_actor_realize (self);
921
922       switch (change)
923         {
924         case MAP_STATE_CHECK:
925           break;
926
927         case MAP_STATE_MAKE_MAPPED:
928           g_assert (!was_mapped);
929           clutter_actor_set_mapped (self, TRUE);
930           break;
931
932         case MAP_STATE_MAKE_UNMAPPED:
933           g_assert (was_mapped);
934           clutter_actor_set_mapped (self, FALSE);
935           break;
936
937         case MAP_STATE_MAKE_UNREALIZED:
938           /* we only use MAKE_UNREALIZED in unparent,
939            * and unparenting a stage isn't possible.
940            * If someone wants to just unrealize a stage
941            * then clutter_actor_unrealize() doesn't
942            * go through this codepath.
943            */
944           g_warning ("Trying to force unrealize stage is not allowed");
945           break;
946         }
947
948       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
949           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
950           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
951         {
952           g_warning ("Clutter toplevel of type '%s' is not visible, but "
953                      "it is somehow still mapped",
954                      _clutter_actor_get_debug_name (self));
955         }
956     }
957   else
958     {
959       ClutterActorPrivate *priv = self->priv;
960       ClutterActor *parent = priv->parent;
961       gboolean should_be_mapped;
962       gboolean may_be_realized;
963       gboolean must_be_realized;
964
965       should_be_mapped = FALSE;
966       may_be_realized = TRUE;
967       must_be_realized = FALSE;
968
969       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
970         {
971           may_be_realized = FALSE;
972         }
973       else
974         {
975           /* Maintain invariant that if parent is mapped, and we are
976            * visible, then we are mapped ...  unless parent is a
977            * stage, in which case we map regardless of parent's map
978            * state but do require stage to be visible and realized.
979            *
980            * If parent is realized, that does not force us to be
981            * realized; but if parent is unrealized, that does force
982            * us to be unrealized.
983            *
984            * The reason we don't force children to realize with
985            * parents is _clutter_actor_rerealize(); if we require that
986            * a realized parent means children are realized, then to
987            * unrealize an actor we would have to unrealize its
988            * parents, which would end up meaning unrealizing and
989            * hiding the entire stage. So we allow unrealizing a
990            * child (as long as that child is not mapped) while that
991            * child still has a realized parent.
992            *
993            * Also, if we unrealize from leaf nodes to root, and
994            * realize from root to leaf, the invariants are never
995            * violated if we allow children to be unrealized
996            * while parents are realized.
997            *
998            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
999            * to force us to unmap, even though parent is still
1000            * mapped. This is because we're unmapping from leaf nodes
1001            * up to root nodes.
1002            */
1003           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1004               change != MAP_STATE_MAKE_UNMAPPED)
1005             {
1006               gboolean parent_is_visible_realized_toplevel;
1007
1008               parent_is_visible_realized_toplevel =
1009                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1010                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1011                  CLUTTER_ACTOR_IS_REALIZED (parent));
1012
1013               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1014                   parent_is_visible_realized_toplevel)
1015                 {
1016                   must_be_realized = TRUE;
1017                   should_be_mapped = TRUE;
1018                 }
1019             }
1020
1021           /* if the actor has been set to be painted even if unmapped
1022            * then we should map it and check for realization as well;
1023            * this is an override for the branch of the scene graph
1024            * which begins with this node
1025            */
1026           if (priv->enable_paint_unmapped)
1027             {
1028               if (priv->parent == NULL)
1029                 g_warning ("Attempting to map an unparented actor '%s'",
1030                            _clutter_actor_get_debug_name (self));
1031
1032               should_be_mapped = TRUE;
1033               must_be_realized = TRUE;
1034             }
1035
1036           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1037             may_be_realized = FALSE;
1038         }
1039
1040       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1041         {
1042           if (parent == NULL)
1043             g_warning ("Attempting to map a child that does not "
1044                        "meet the necessary invariants: the actor '%s' "
1045                        "has no parent",
1046                        _clutter_actor_get_debug_name (self));
1047           else
1048             g_warning ("Attempting to map a child that does not "
1049                        "meet the necessary invariants: the actor '%s' "
1050                        "is parented to an unmapped actor '%s'",
1051                        _clutter_actor_get_debug_name (self),
1052                        _clutter_actor_get_debug_name (priv->parent));
1053         }
1054
1055       /* If in reparent, we temporarily suspend unmap and unrealize.
1056        *
1057        * We want to go in the order "realize, map" and "unmap, unrealize"
1058        */
1059
1060       /* Unmap */
1061       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1062         clutter_actor_set_mapped (self, FALSE);
1063
1064       /* Realize */
1065       if (must_be_realized)
1066         clutter_actor_realize (self);
1067
1068       /* if we must be realized then we may be, presumably */
1069       g_assert (!(must_be_realized && !may_be_realized));
1070
1071       /* Unrealize */
1072       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1073         clutter_actor_unrealize_not_hiding (self);
1074
1075       /* Map */
1076       if (should_be_mapped)
1077         {
1078           if (!must_be_realized)
1079             g_warning ("Somehow we think actor '%s' should be mapped but "
1080                        "not realized, which isn't allowed",
1081                        _clutter_actor_get_debug_name (self));
1082
1083           /* realization is allowed to fail (though I don't know what
1084            * an app is supposed to do about that - shouldn't it just
1085            * be a g_error? anyway, we have to avoid mapping if this
1086            * happens)
1087            */
1088           if (CLUTTER_ACTOR_IS_REALIZED (self))
1089             clutter_actor_set_mapped (self, TRUE);
1090         }
1091     }
1092
1093 #ifdef CLUTTER_ENABLE_DEBUG
1094   /* check all invariants were kept */
1095   clutter_actor_verify_map_state (self);
1096 #endif
1097 }
1098
1099 static void
1100 clutter_actor_real_map (ClutterActor *self)
1101 {
1102   ClutterActorPrivate *priv = self->priv;
1103   ClutterActor *stage, *iter;
1104
1105   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1106
1107   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1108                 _clutter_actor_get_debug_name (self));
1109
1110   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1111
1112   stage = _clutter_actor_get_stage_internal (self);
1113   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1114
1115   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1116                 priv->pick_id,
1117                 _clutter_actor_get_debug_name (self));
1118
1119   /* notify on parent mapped before potentially mapping
1120    * children, so apps see a top-down notification.
1121    */
1122   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1123
1124   for (iter = self->priv->first_child;
1125        iter != NULL;
1126        iter = iter->priv->next_sibling)
1127     {
1128       clutter_actor_map (iter);
1129     }
1130 }
1131
1132 /**
1133  * clutter_actor_map:
1134  * @self: A #ClutterActor
1135  *
1136  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1137  * and realizes its children if they are visible. Does nothing if the
1138  * actor is not visible.
1139  *
1140  * Calling this function is strongly disencouraged: the default
1141  * implementation of #ClutterActorClass.map() will map all the children
1142  * of an actor when mapping its parent.
1143  *
1144  * When overriding map, it is mandatory to chain up to the parent
1145  * implementation.
1146  *
1147  * Since: 1.0
1148  */
1149 void
1150 clutter_actor_map (ClutterActor *self)
1151 {
1152   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1153
1154   if (CLUTTER_ACTOR_IS_MAPPED (self))
1155     return;
1156
1157   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1158     return;
1159
1160   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1161 }
1162
1163 static void
1164 clutter_actor_real_unmap (ClutterActor *self)
1165 {
1166   ClutterActorPrivate *priv = self->priv;
1167   ClutterActor *iter;
1168
1169   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1170
1171   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1172                 _clutter_actor_get_debug_name (self));
1173
1174   for (iter = self->priv->first_child;
1175        iter != NULL;
1176        iter = iter->priv->next_sibling)
1177     {
1178       clutter_actor_unmap (iter);
1179     }
1180
1181   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1182
1183   /* clear the contents of the last paint volume, so that hiding + moving +
1184    * showing will not result in the wrong area being repainted
1185    */
1186   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1187   priv->last_paint_volume_valid = TRUE;
1188
1189   /* notify on parent mapped after potentially unmapping
1190    * children, so apps see a bottom-up notification.
1191    */
1192   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1193
1194   /* relinquish keyboard focus if we were unmapped while owning it */
1195   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1196     {
1197       ClutterStage *stage;
1198
1199       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1200
1201       if (stage != NULL)
1202         _clutter_stage_release_pick_id (stage, priv->pick_id);
1203
1204       priv->pick_id = -1;
1205
1206       if (stage != NULL &&
1207           clutter_stage_get_key_focus (stage) == self)
1208         {
1209           clutter_stage_set_key_focus (stage, NULL);
1210         }
1211     }
1212 }
1213
1214 /**
1215  * clutter_actor_unmap:
1216  * @self: A #ClutterActor
1217  *
1218  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1219  * unmaps its children if they were mapped.
1220  *
1221  * Calling this function is not encouraged: the default #ClutterActor
1222  * implementation of #ClutterActorClass.unmap() will also unmap any
1223  * eventual children by default when their parent is unmapped.
1224  *
1225  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1226  * chain up to the parent implementation.
1227  *
1228  * <note>It is important to note that the implementation of the
1229  * #ClutterActorClass.unmap() virtual function may be called after
1230  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1231  * implementation, but it is guaranteed to be called before the
1232  * #GObjectClass.finalize() implementation.</note>
1233  *
1234  * Since: 1.0
1235  */
1236 void
1237 clutter_actor_unmap (ClutterActor *self)
1238 {
1239   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1240
1241   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1242     return;
1243
1244   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1245 }
1246
1247 static void
1248 clutter_actor_real_show (ClutterActor *self)
1249 {
1250   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1251     {
1252       ClutterActorPrivate *priv = self->priv;
1253
1254       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1255
1256       /* we notify on the "visible" flag in the clutter_actor_show()
1257        * wrapper so the entire show signal emission completes first
1258        * (?)
1259        */
1260       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1261
1262       /* we queue a relayout unless the actor is inside a
1263        * container that explicitly told us not to
1264        */
1265       if (priv->parent != NULL &&
1266           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1267         {
1268           /* While an actor is hidden the parent may not have
1269            * allocated/requested so we need to start from scratch
1270            * and avoid the short-circuiting in
1271            * clutter_actor_queue_relayout().
1272            */
1273           priv->needs_width_request  = FALSE;
1274           priv->needs_height_request = FALSE;
1275           priv->needs_allocation     = FALSE;
1276           clutter_actor_queue_relayout (self);
1277         }
1278     }
1279 }
1280
1281 static inline void
1282 set_show_on_set_parent (ClutterActor *self,
1283                         gboolean      set_show)
1284 {
1285   ClutterActorPrivate *priv = self->priv;
1286
1287   set_show = !!set_show;
1288
1289   if (priv->show_on_set_parent == set_show)
1290     return;
1291
1292   if (priv->parent == NULL)
1293     {
1294       priv->show_on_set_parent = set_show;
1295       g_object_notify_by_pspec (G_OBJECT (self),
1296                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1297     }
1298 }
1299
1300 /**
1301  * clutter_actor_show:
1302  * @self: A #ClutterActor
1303  *
1304  * Flags an actor to be displayed. An actor that isn't shown will not
1305  * be rendered on the stage.
1306  *
1307  * Actors are visible by default.
1308  *
1309  * If this function is called on an actor without a parent, the
1310  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1311  * effect.
1312  */
1313 void
1314 clutter_actor_show (ClutterActor *self)
1315 {
1316   ClutterActorPrivate *priv;
1317
1318   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1319
1320   /* simple optimization */
1321   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1322     {
1323       /* we still need to set the :show-on-set-parent property, in
1324        * case show() is called on an unparented actor
1325        */
1326       set_show_on_set_parent (self, TRUE);
1327       return;
1328     }
1329
1330 #ifdef CLUTTER_ENABLE_DEBUG
1331   clutter_actor_verify_map_state (self);
1332 #endif
1333
1334   priv = self->priv;
1335
1336   g_object_freeze_notify (G_OBJECT (self));
1337
1338   set_show_on_set_parent (self, TRUE);
1339
1340   g_signal_emit (self, actor_signals[SHOW], 0);
1341   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1342
1343   if (priv->parent != NULL)
1344     clutter_actor_queue_redraw (priv->parent);
1345
1346   g_object_thaw_notify (G_OBJECT (self));
1347 }
1348
1349 /**
1350  * clutter_actor_show_all:
1351  * @self: a #ClutterActor
1352  *
1353  * Calls clutter_actor_show() on all children of an actor (if any).
1354  *
1355  * Since: 0.2
1356  *
1357  * Deprecated: 1.10: Actors are visible by default
1358  */
1359 void
1360 clutter_actor_show_all (ClutterActor *self)
1361 {
1362   ClutterActorClass *klass;
1363
1364   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1365
1366   klass = CLUTTER_ACTOR_GET_CLASS (self);
1367   if (klass->show_all)
1368     klass->show_all (self);
1369 }
1370
1371 static void
1372 clutter_actor_real_hide (ClutterActor *self)
1373 {
1374   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1375     {
1376       ClutterActorPrivate *priv = self->priv;
1377
1378       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1379
1380       /* we notify on the "visible" flag in the clutter_actor_hide()
1381        * wrapper so the entire hide signal emission completes first
1382        * (?)
1383        */
1384       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1385
1386       /* we queue a relayout unless the actor is inside a
1387        * container that explicitly told us not to
1388        */
1389       if (priv->parent != NULL &&
1390           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1391         clutter_actor_queue_relayout (priv->parent);
1392     }
1393 }
1394
1395 /**
1396  * clutter_actor_hide:
1397  * @self: A #ClutterActor
1398  *
1399  * Flags an actor to be hidden. A hidden actor will not be
1400  * rendered on the stage.
1401  *
1402  * Actors are visible by default.
1403  *
1404  * If this function is called on an actor without a parent, the
1405  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1406  * as a side-effect.
1407  */
1408 void
1409 clutter_actor_hide (ClutterActor *self)
1410 {
1411   ClutterActorPrivate *priv;
1412
1413   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1414
1415   /* simple optimization */
1416   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1417     {
1418       /* we still need to set the :show-on-set-parent property, in
1419        * case hide() is called on an unparented actor
1420        */
1421       set_show_on_set_parent (self, FALSE);
1422       return;
1423     }
1424
1425 #ifdef CLUTTER_ENABLE_DEBUG
1426   clutter_actor_verify_map_state (self);
1427 #endif
1428
1429   priv = self->priv;
1430
1431   g_object_freeze_notify (G_OBJECT (self));
1432
1433   set_show_on_set_parent (self, FALSE);
1434
1435   g_signal_emit (self, actor_signals[HIDE], 0);
1436   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1437
1438   if (priv->parent != NULL)
1439     clutter_actor_queue_redraw (priv->parent);
1440
1441   g_object_thaw_notify (G_OBJECT (self));
1442 }
1443
1444 /**
1445  * clutter_actor_hide_all:
1446  * @self: a #ClutterActor
1447  *
1448  * Calls clutter_actor_hide() on all child actors (if any).
1449  *
1450  * Since: 0.2
1451  *
1452  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1453  *   prevent its children from being painted as well.
1454  */
1455 void
1456 clutter_actor_hide_all (ClutterActor *self)
1457 {
1458   ClutterActorClass *klass;
1459
1460   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1461
1462   klass = CLUTTER_ACTOR_GET_CLASS (self);
1463   if (klass->hide_all)
1464     klass->hide_all (self);
1465 }
1466
1467 /**
1468  * clutter_actor_realize:
1469  * @self: A #ClutterActor
1470  *
1471  * Realization informs the actor that it is attached to a stage. It
1472  * can use this to allocate resources if it wanted to delay allocation
1473  * until it would be rendered. However it is perfectly acceptable for
1474  * an actor to create resources before being realized because Clutter
1475  * only ever has a single rendering context so that actor is free to
1476  * be moved from one stage to another.
1477  *
1478  * This function does nothing if the actor is already realized.
1479  *
1480  * Because a realized actor must have realized parent actors, calling
1481  * clutter_actor_realize() will also realize all parents of the actor.
1482  *
1483  * This function does not realize child actors, except in the special
1484  * case that realizing the stage, when the stage is visible, will
1485  * suddenly map (and thus realize) the children of the stage.
1486  **/
1487 void
1488 clutter_actor_realize (ClutterActor *self)
1489 {
1490   ClutterActorPrivate *priv;
1491
1492   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1493
1494   priv = self->priv;
1495
1496 #ifdef CLUTTER_ENABLE_DEBUG
1497   clutter_actor_verify_map_state (self);
1498 #endif
1499
1500   if (CLUTTER_ACTOR_IS_REALIZED (self))
1501     return;
1502
1503   /* To be realized, our parent actors must be realized first.
1504    * This will only succeed if we're inside a toplevel.
1505    */
1506   if (priv->parent != NULL)
1507     clutter_actor_realize (priv->parent);
1508
1509   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1510     {
1511       /* toplevels can be realized at any time */
1512     }
1513   else
1514     {
1515       /* "Fail" the realization if parent is missing or unrealized;
1516        * this should really be a g_warning() not some kind of runtime
1517        * failure; how can an app possibly recover? Instead it's a bug
1518        * in the app and the app should get an explanatory warning so
1519        * someone can fix it. But for now it's too hard to fix this
1520        * because e.g. ClutterTexture needs reworking.
1521        */
1522       if (priv->parent == NULL ||
1523           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1524         return;
1525     }
1526
1527   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1528
1529   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1530   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1531
1532   g_signal_emit (self, actor_signals[REALIZE], 0);
1533
1534   /* Stage actor is allowed to unset the realized flag again in its
1535    * default signal handler, though that is a pathological situation.
1536    */
1537
1538   /* If realization "failed" we'll have to update child state. */
1539   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1540 }
1541
1542 static void
1543 clutter_actor_real_unrealize (ClutterActor *self)
1544 {
1545   /* we must be unmapped (implying our children are also unmapped) */
1546   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1547 }
1548
1549 /**
1550  * clutter_actor_unrealize:
1551  * @self: A #ClutterActor
1552  *
1553  * Unrealization informs the actor that it may be being destroyed or
1554  * moved to another stage. The actor may want to destroy any
1555  * underlying graphics resources at this point. However it is
1556  * perfectly acceptable for it to retain the resources until the actor
1557  * is destroyed because Clutter only ever uses a single rendering
1558  * context and all of the graphics resources are valid on any stage.
1559  *
1560  * Because mapped actors must be realized, actors may not be
1561  * unrealized if they are mapped. This function hides the actor to be
1562  * sure it isn't mapped, an application-visible side effect that you
1563  * may not be expecting.
1564  *
1565  * This function should not be called by application code.
1566  */
1567 void
1568 clutter_actor_unrealize (ClutterActor *self)
1569 {
1570   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1571   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1572
1573 /* This function should not really be in the public API, because
1574  * there isn't a good reason to call it. ClutterActor will already
1575  * unrealize things for you when it's important to do so.
1576  *
1577  * If you were using clutter_actor_unrealize() in a dispose
1578  * implementation, then don't, just chain up to ClutterActor's
1579  * dispose.
1580  *
1581  * If you were using clutter_actor_unrealize() to implement
1582  * unrealizing children of your container, then don't, ClutterActor
1583  * will already take care of that.
1584  *
1585  * If you were using clutter_actor_unrealize() to re-realize to
1586  * create your resources in a different way, then use
1587  * _clutter_actor_rerealize() (inside Clutter) or just call your
1588  * code that recreates your resources directly (outside Clutter).
1589  */
1590
1591 #ifdef CLUTTER_ENABLE_DEBUG
1592   clutter_actor_verify_map_state (self);
1593 #endif
1594
1595   clutter_actor_hide (self);
1596
1597   clutter_actor_unrealize_not_hiding (self);
1598 }
1599
1600 static ClutterActorTraverseVisitFlags
1601 unrealize_actor_before_children_cb (ClutterActor *self,
1602                                     int depth,
1603                                     void *user_data)
1604 {
1605   /* If an actor is already unrealized we know its children have also
1606    * already been unrealized... */
1607   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1608     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1609
1610   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1611
1612   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1613 }
1614
1615 static ClutterActorTraverseVisitFlags
1616 unrealize_actor_after_children_cb (ClutterActor *self,
1617                                    int depth,
1618                                    void *user_data)
1619 {
1620   /* We want to unset the realized flag only _after_
1621    * child actors are unrealized, to maintain invariants.
1622    */
1623   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1624   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1625   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1626 }
1627
1628 /*
1629  * clutter_actor_unrealize_not_hiding:
1630  * @self: A #ClutterActor
1631  *
1632  * Unrealization informs the actor that it may be being destroyed or
1633  * moved to another stage. The actor may want to destroy any
1634  * underlying graphics resources at this point. However it is
1635  * perfectly acceptable for it to retain the resources until the actor
1636  * is destroyed because Clutter only ever uses a single rendering
1637  * context and all of the graphics resources are valid on any stage.
1638  *
1639  * Because mapped actors must be realized, actors may not be
1640  * unrealized if they are mapped. You must hide the actor or one of
1641  * its parents before attempting to unrealize.
1642  *
1643  * This function is separate from clutter_actor_unrealize() because it
1644  * does not automatically hide the actor.
1645  * Actors need not be hidden to be unrealized, they just need to
1646  * be unmapped. In fact we don't want to mess up the application's
1647  * setting of the "visible" flag, so hiding is very undesirable.
1648  *
1649  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1650  * backward compatibility.
1651  */
1652 static void
1653 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1654 {
1655   _clutter_actor_traverse (self,
1656                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1657                            unrealize_actor_before_children_cb,
1658                            unrealize_actor_after_children_cb,
1659                            NULL);
1660 }
1661
1662 /*
1663  * _clutter_actor_rerealize:
1664  * @self: A #ClutterActor
1665  * @callback: Function to call while unrealized
1666  * @data: data for callback
1667  *
1668  * If an actor is already unrealized, this just calls the callback.
1669  *
1670  * If it is realized, it unrealizes temporarily, calls the callback,
1671  * and then re-realizes the actor.
1672  *
1673  * As a side effect, leaves all children of the actor unrealized if
1674  * the actor was realized but not showing.  This is because when we
1675  * unrealize the actor temporarily we must unrealize its children
1676  * (e.g. children of a stage can't be realized if stage window is
1677  * gone). And we aren't clever enough to save the realization state of
1678  * all children. In most cases this should not matter, because
1679  * the children will automatically realize when they next become mapped.
1680  */
1681 void
1682 _clutter_actor_rerealize (ClutterActor    *self,
1683                           ClutterCallback  callback,
1684                           void            *data)
1685 {
1686   gboolean was_mapped;
1687   gboolean was_showing;
1688   gboolean was_realized;
1689
1690   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1691
1692 #ifdef CLUTTER_ENABLE_DEBUG
1693   clutter_actor_verify_map_state (self);
1694 #endif
1695
1696   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1697   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1698   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1699
1700   /* Must be unmapped to unrealize. Note we only have to hide this
1701    * actor if it was mapped (if all parents were showing).  If actor
1702    * is merely visible (but not mapped), then that's fine, we can
1703    * leave it visible.
1704    */
1705   if (was_mapped)
1706     clutter_actor_hide (self);
1707
1708   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1709
1710   /* unrealize self and all children */
1711   clutter_actor_unrealize_not_hiding (self);
1712
1713   if (callback != NULL)
1714     {
1715       (* callback) (self, data);
1716     }
1717
1718   if (was_showing)
1719     clutter_actor_show (self); /* will realize only if mapping implies it */
1720   else if (was_realized)
1721     clutter_actor_realize (self); /* realize self and all parents */
1722 }
1723
1724 static void
1725 clutter_actor_real_pick (ClutterActor       *self,
1726                          const ClutterColor *color)
1727 {
1728   /* the default implementation is just to paint a rectangle
1729    * with the same size of the actor using the passed color
1730    */
1731   if (clutter_actor_should_pick_paint (self))
1732     {
1733       ClutterActorBox box = { 0, };
1734       float width, height;
1735
1736       clutter_actor_get_allocation_box (self, &box);
1737
1738       width = box.x2 - box.x1;
1739       height = box.y2 - box.y1;
1740
1741       cogl_set_source_color4ub (color->red,
1742                                 color->green,
1743                                 color->blue,
1744                                 color->alpha);
1745
1746       cogl_rectangle (0, 0, width, height);
1747     }
1748
1749   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1750    * with existing container classes that override the pick() virtual
1751    * and chain up to the default implementation - otherwise we'll end up
1752    * painting our children twice.
1753    *
1754    * this has to go away for 2.0; hopefully along the pick() itself.
1755    */
1756   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1757     {
1758       ClutterActor *iter;
1759
1760       for (iter = self->priv->first_child;
1761            iter != NULL;
1762            iter = iter->priv->next_sibling)
1763         clutter_actor_paint (iter);
1764     }
1765 }
1766
1767 /**
1768  * clutter_actor_should_pick_paint:
1769  * @self: A #ClutterActor
1770  *
1771  * Should be called inside the implementation of the
1772  * #ClutterActor::pick virtual function in order to check whether
1773  * the actor should paint itself in pick mode or not.
1774  *
1775  * This function should never be called directly by applications.
1776  *
1777  * Return value: %TRUE if the actor should paint its silhouette,
1778  *   %FALSE otherwise
1779  */
1780 gboolean
1781 clutter_actor_should_pick_paint (ClutterActor *self)
1782 {
1783   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1784
1785   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1786       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1787        CLUTTER_ACTOR_IS_REACTIVE (self)))
1788     return TRUE;
1789
1790   return FALSE;
1791 }
1792
1793 static void
1794 clutter_actor_real_get_preferred_width (ClutterActor *self,
1795                                         gfloat        for_height,
1796                                         gfloat       *min_width_p,
1797                                         gfloat       *natural_width_p)
1798 {
1799   ClutterActorPrivate *priv = self->priv;
1800
1801   if (priv->n_children != 0 &&
1802       priv->layout_manager != NULL)
1803     {
1804       ClutterContainer *container = CLUTTER_CONTAINER (self);
1805
1806       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1807                     "for the preferred width",
1808                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1809                     priv->layout_manager);
1810
1811       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1812                                                   container,
1813                                                   for_height,
1814                                                   min_width_p,
1815                                                   natural_width_p);
1816
1817       return;
1818     }
1819
1820   /* Default implementation is always 0x0, usually an actor
1821    * using this default is relying on someone to set the
1822    * request manually
1823    */
1824   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1825
1826   if (min_width_p)
1827     *min_width_p = 0;
1828
1829   if (natural_width_p)
1830     *natural_width_p = 0;
1831 }
1832
1833 static void
1834 clutter_actor_real_get_preferred_height (ClutterActor *self,
1835                                          gfloat        for_width,
1836                                          gfloat       *min_height_p,
1837                                          gfloat       *natural_height_p)
1838 {
1839   ClutterActorPrivate *priv = self->priv;
1840
1841   if (priv->n_children != 0 &&
1842       priv->layout_manager != NULL)
1843     {
1844       ClutterContainer *container = CLUTTER_CONTAINER (self);
1845
1846       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1847                     "for the preferred height",
1848                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1849                     priv->layout_manager);
1850
1851       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1852                                                    container,
1853                                                    for_width,
1854                                                    min_height_p,
1855                                                    natural_height_p);
1856
1857       return;
1858     }
1859   /* Default implementation is always 0x0, usually an actor
1860    * using this default is relying on someone to set the
1861    * request manually
1862    */
1863   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1864
1865   if (min_height_p)
1866     *min_height_p = 0;
1867
1868   if (natural_height_p)
1869     *natural_height_p = 0;
1870 }
1871
1872 static void
1873 clutter_actor_store_old_geometry (ClutterActor    *self,
1874                                   ClutterActorBox *box)
1875 {
1876   *box = self->priv->allocation;
1877 }
1878
1879 static inline void
1880 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1881                                           const ClutterActorBox *old)
1882 {
1883   ClutterActorPrivate *priv = self->priv;
1884   GObject *obj = G_OBJECT (self);
1885
1886   g_object_freeze_notify (obj);
1887
1888   /* to avoid excessive requisition or allocation cycles we
1889    * use the cached values.
1890    *
1891    * - if we don't have an allocation we assume that we need
1892    *   to notify anyway
1893    * - if we don't have a width or a height request we notify
1894    *   width and height
1895    * - if we have a valid allocation then we check the old
1896    *   bounding box with the current allocation and we notify
1897    *   the changes
1898    */
1899   if (priv->needs_allocation)
1900     {
1901       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1902       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1903       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1904       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1905     }
1906   else if (priv->needs_width_request || priv->needs_height_request)
1907     {
1908       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1909       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1910     }
1911   else
1912     {
1913       gfloat xu, yu;
1914       gfloat widthu, heightu;
1915
1916       xu = priv->allocation.x1;
1917       yu = priv->allocation.y1;
1918       widthu = priv->allocation.x2 - priv->allocation.x1;
1919       heightu = priv->allocation.y2 - priv->allocation.y1;
1920
1921       if (xu != old->x1)
1922         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1923
1924       if (yu != old->y1)
1925         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1926
1927       if (widthu != (old->x2 - old->x1))
1928         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1929
1930       if (heightu != (old->y2 - old->y1))
1931         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1932     }
1933
1934   g_object_thaw_notify (obj);
1935 }
1936
1937 /*< private >
1938  * clutter_actor_set_allocation_internal:
1939  * @self: a #ClutterActor
1940  * @box: a #ClutterActorBox
1941  * @flags: allocation flags
1942  *
1943  * Stores the allocation of @self.
1944  *
1945  * This function only performs basic storage and property notification.
1946  *
1947  * This function should be called by clutter_actor_set_allocation()
1948  * and by the default implementation of #ClutterActorClass.allocate().
1949  *
1950  * Return value: %TRUE if the allocation of the #ClutterActor has been
1951  *   changed, and %FALSE otherwise
1952  */
1953 static inline gboolean
1954 clutter_actor_set_allocation_internal (ClutterActor           *self,
1955                                        const ClutterActorBox  *box,
1956                                        ClutterAllocationFlags  flags)
1957 {
1958   ClutterActorPrivate *priv = self->priv;
1959   GObject *obj;
1960   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
1961   gboolean flags_changed;
1962   gboolean retval;
1963   ClutterActorBox old_alloc = { 0, };
1964
1965   obj = G_OBJECT (self);
1966
1967   g_object_freeze_notify (obj);
1968
1969   clutter_actor_store_old_geometry (self, &old_alloc);
1970
1971   x1_changed = priv->allocation.x1 != box->x1;
1972   y1_changed = priv->allocation.y1 != box->y1;
1973   x2_changed = priv->allocation.x2 != box->x2;
1974   y2_changed = priv->allocation.y2 != box->y2;
1975
1976   flags_changed = priv->allocation_flags != flags;
1977
1978   priv->allocation = *box;
1979   priv->allocation_flags = flags;
1980
1981   /* allocation is authoritative */
1982   priv->needs_width_request = FALSE;
1983   priv->needs_height_request = FALSE;
1984   priv->needs_allocation = FALSE;
1985
1986   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1987     {
1988       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
1989                     _clutter_actor_get_debug_name (self));
1990
1991       priv->transform_valid = FALSE;
1992
1993       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
1994
1995       retval = TRUE;
1996     }
1997   else
1998     retval = FALSE;
1999
2000   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2001
2002   g_object_thaw_notify (obj);
2003
2004   return retval;
2005 }
2006
2007 static void clutter_actor_real_allocate (ClutterActor           *self,
2008                                          const ClutterActorBox  *box,
2009                                          ClutterAllocationFlags  flags);
2010
2011 static inline void
2012 clutter_actor_maybe_layout_children (ClutterActor           *self,
2013                                      const ClutterActorBox  *allocation,
2014                                      ClutterAllocationFlags  flags)
2015 {
2016   ClutterActorPrivate *priv = self->priv;
2017
2018   /* this is going to be a bit hard to follow, so let's put an explanation
2019    * here.
2020    *
2021    * we want ClutterActor to have a default layout manager if the actor was
2022    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2023    *
2024    * we also want any subclass of ClutterActor that does not override the
2025    * ::allocate() virtual function to delegate to a layout manager.
2026    *
2027    * finally, we want to allow people subclassing ClutterActor and overriding
2028    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2029    *
2030    * on the other hand, we want existing actor subclasses overriding the
2031    * ::allocate() virtual function and chaining up to the parent's
2032    * implementation to continue working without allocating their children
2033    * twice, or without entering an allocation loop.
2034    *
2035    * for the first two points, we check if the class of the actor is
2036    * overridding the ::allocate() virtual function; if it isn't, then we
2037    * follow through with checking whether we have children and a layout
2038    * manager, and eventually calling clutter_layout_manager_allocate().
2039    *
2040    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2041    * allocation flags that we got passed, and if it is present, we continue
2042    * with the check above.
2043    *
2044    * if neither of these two checks yields a positive result, we just
2045    * assume that the ::allocate() virtual function that resulted in this
2046    * function being called will also allocate the children of the actor.
2047    */
2048
2049   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2050     goto check_layout;
2051
2052   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2053     goto check_layout;
2054
2055   return;
2056
2057 check_layout:
2058   if (priv->n_children != 0 &&
2059       priv->layout_manager != NULL)
2060     {
2061       ClutterContainer *container = CLUTTER_CONTAINER (self);
2062       ClutterAllocationFlags children_flags;
2063       ClutterActorBox children_box;
2064
2065       /* normalize the box passed to the layout manager */
2066       children_box.x1 = children_box.y1 = 0.f;
2067       children_box.x2 = (allocation->x2 - allocation->x1);
2068       children_box.y2 = (allocation->y2 - allocation->y1);
2069
2070       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2071        * the actor's children, since it refers only to the current
2072        * actor's allocation.
2073        */
2074       children_flags = flags;
2075       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2076
2077       CLUTTER_NOTE (LAYOUT,
2078                     "Allocating %d children of %s "
2079                     "at { %.2f, %.2f - %.2f x %.2f } "
2080                     "using %s",
2081                     priv->n_children,
2082                     _clutter_actor_get_debug_name (self),
2083                     allocation->x1,
2084                     allocation->y1,
2085                     (allocation->x2 - allocation->x1),
2086                     (allocation->y2 - allocation->y1),
2087                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2088
2089       clutter_layout_manager_allocate (priv->layout_manager,
2090                                        container,
2091                                        &children_box,
2092                                        children_flags);
2093     }
2094 }
2095
2096 static void
2097 clutter_actor_real_allocate (ClutterActor           *self,
2098                              const ClutterActorBox  *box,
2099                              ClutterAllocationFlags  flags)
2100 {
2101   ClutterActorPrivate *priv = self->priv;
2102   gboolean changed;
2103
2104   g_object_freeze_notify (G_OBJECT (self));
2105
2106   changed = clutter_actor_set_allocation_internal (self, box, flags);
2107
2108   /* we allocate our children before we notify changes in our geometry,
2109    * so that people connecting to properties will be able to get valid
2110    * data out of the sub-tree of the scene graph that has this actor at
2111    * the root.
2112    */
2113   clutter_actor_maybe_layout_children (self, box, flags);
2114
2115   if (changed)
2116     {
2117       ClutterActorBox signal_box = priv->allocation;
2118       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2119
2120       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2121                      &signal_box,
2122                      signal_flags);
2123     }
2124
2125   g_object_thaw_notify (G_OBJECT (self));
2126 }
2127
2128 static void
2129 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2130                                     ClutterActor *origin)
2131 {
2132   /* no point in queuing a redraw on a destroyed actor */
2133   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2134     return;
2135
2136   /* NB: We can't bail out early here if the actor is hidden in case
2137    * the actor bas been cloned. In this case the clone will need to
2138    * receive the signal so it can queue its own redraw.
2139    */
2140
2141   /* calls klass->queue_redraw in default handler */
2142   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2143 }
2144
2145 static void
2146 clutter_actor_real_queue_redraw (ClutterActor *self,
2147                                  ClutterActor *origin)
2148 {
2149   ClutterActor *parent;
2150
2151   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2152                 _clutter_actor_get_debug_name (self),
2153                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2154                                : "same actor");
2155
2156   /* no point in queuing a redraw on a destroyed actor */
2157   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2158     return;
2159
2160   /* If the queue redraw is coming from a child then the actor has
2161      become dirty and any queued effect is no longer valid */
2162   if (self != origin)
2163     {
2164       self->priv->is_dirty = TRUE;
2165       self->priv->effect_to_redraw = NULL;
2166     }
2167
2168   /* If the actor isn't visible, we still had to emit the signal
2169    * to allow for a ClutterClone, but the appearance of the parent
2170    * won't change so we don't have to propagate up the hierarchy.
2171    */
2172   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2173     return;
2174
2175   /* Although we could determine here that a full stage redraw
2176    * has already been queued and immediately bail out, we actually
2177    * guarantee that we will propagate a queue-redraw signal to our
2178    * parent at least once so that it's possible to implement a
2179    * container that tracks which of its children have queued a
2180    * redraw.
2181    */
2182   if (self->priv->propagated_one_redraw)
2183     {
2184       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2185       if (stage != NULL &&
2186           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2187         return;
2188     }
2189
2190   self->priv->propagated_one_redraw = TRUE;
2191
2192   /* notify parents, if they are all visible eventually we'll
2193    * queue redraw on the stage, which queues the redraw idle.
2194    */
2195   parent = clutter_actor_get_parent (self);
2196   if (parent != NULL)
2197     {
2198       /* this will go up recursively */
2199       _clutter_actor_signal_queue_redraw (parent, origin);
2200     }
2201 }
2202
2203 static void
2204 clutter_actor_real_queue_relayout (ClutterActor *self)
2205 {
2206   ClutterActorPrivate *priv = self->priv;
2207
2208   /* no point in queueing a redraw on a destroyed actor */
2209   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2210     return;
2211
2212   priv->needs_width_request  = TRUE;
2213   priv->needs_height_request = TRUE;
2214   priv->needs_allocation     = TRUE;
2215
2216   /* reset the cached size requests */
2217   memset (priv->width_requests, 0,
2218           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2219   memset (priv->height_requests, 0,
2220           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2221
2222   /* We need to go all the way up the hierarchy */
2223   if (priv->parent != NULL)
2224     _clutter_actor_queue_only_relayout (priv->parent);
2225 }
2226
2227 /**
2228  * clutter_actor_apply_relative_transform_to_point:
2229  * @self: A #ClutterActor
2230  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2231  *   default #ClutterStage
2232  * @point: A point as #ClutterVertex
2233  * @vertex: (out caller-allocates): The translated #ClutterVertex
2234  *
2235  * Transforms @point in coordinates relative to the actor into
2236  * ancestor-relative coordinates using the relevant transform
2237  * stack (i.e. scale, rotation, etc).
2238  *
2239  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2240  * this case, the coordinates returned will be the coordinates on
2241  * the stage before the projection is applied. This is different from
2242  * the behaviour of clutter_actor_apply_transform_to_point().
2243  *
2244  * Since: 0.6
2245  */
2246 void
2247 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2248                                                  ClutterActor        *ancestor,
2249                                                  const ClutterVertex *point,
2250                                                  ClutterVertex       *vertex)
2251 {
2252   gfloat w;
2253   CoglMatrix matrix;
2254
2255   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2256   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2257   g_return_if_fail (point != NULL);
2258   g_return_if_fail (vertex != NULL);
2259
2260   *vertex = *point;
2261   w = 1.0;
2262
2263   if (ancestor == NULL)
2264     ancestor = _clutter_actor_get_stage_internal (self);
2265
2266   if (ancestor == NULL)
2267     {
2268       *vertex = *point;
2269       return;
2270     }
2271
2272   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2273   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2274 }
2275
2276 static gboolean
2277 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2278                                          const ClutterVertex *vertices_in,
2279                                          ClutterVertex *vertices_out,
2280                                          int n_vertices)
2281 {
2282   ClutterActor *stage;
2283   CoglMatrix modelview;
2284   CoglMatrix projection;
2285   float viewport[4];
2286
2287   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2288
2289   stage = _clutter_actor_get_stage_internal (self);
2290
2291   /* We really can't do anything meaningful in this case so don't try
2292    * to do any transform */
2293   if (stage == NULL)
2294     return FALSE;
2295
2296   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2297    * that gets us to stage coordinates, we want to go all the way to eye
2298    * coordinates */
2299   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2300
2301   /* Fetch the projection and viewport */
2302   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2303   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2304                                &viewport[0],
2305                                &viewport[1],
2306                                &viewport[2],
2307                                &viewport[3]);
2308
2309   _clutter_util_fully_transform_vertices (&modelview,
2310                                           &projection,
2311                                           viewport,
2312                                           vertices_in,
2313                                           vertices_out,
2314                                           n_vertices);
2315
2316   return TRUE;
2317 }
2318
2319 /**
2320  * clutter_actor_apply_transform_to_point:
2321  * @self: A #ClutterActor
2322  * @point: A point as #ClutterVertex
2323  * @vertex: (out caller-allocates): The translated #ClutterVertex
2324  *
2325  * Transforms @point in coordinates relative to the actor
2326  * into screen-relative coordinates with the current actor
2327  * transformation (i.e. scale, rotation, etc)
2328  *
2329  * Since: 0.4
2330  **/
2331 void
2332 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2333                                         const ClutterVertex *point,
2334                                         ClutterVertex       *vertex)
2335 {
2336   g_return_if_fail (point != NULL);
2337   g_return_if_fail (vertex != NULL);
2338   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2339 }
2340
2341 /*
2342  * _clutter_actor_get_relative_transformation_matrix:
2343  * @self: The actor whose coordinate space you want to transform from.
2344  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2345  *            or %NULL if you want to transform all the way to eye coordinates.
2346  * @matrix: A #CoglMatrix to store the transformation
2347  *
2348  * This gets a transformation @matrix that will transform coordinates from the
2349  * coordinate space of @self into the coordinate space of @ancestor.
2350  *
2351  * For example if you need a matrix that can transform the local actor
2352  * coordinates of @self into stage coordinates you would pass the actor's stage
2353  * pointer as the @ancestor.
2354  *
2355  * If you pass %NULL then the transformation will take you all the way through
2356  * to eye coordinates. This can be useful if you want to extract the entire
2357  * modelview transform that Clutter applies before applying the projection
2358  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2359  * using cogl_set_modelview_matrix() for example then you would want a matrix
2360  * that transforms into eye coordinates.
2361  *
2362  * <note><para>This function explicitly initializes the given @matrix. If you just
2363  * want clutter to multiply a relative transformation with an existing matrix
2364  * you can use clutter_actor_apply_relative_transformation_matrix()
2365  * instead.</para></note>
2366  *
2367  */
2368 /* XXX: We should consider caching the stage relative modelview along with
2369  * the actor itself */
2370 static void
2371 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2372                                                    ClutterActor *ancestor,
2373                                                    CoglMatrix *matrix)
2374 {
2375   cogl_matrix_init_identity (matrix);
2376
2377   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2378 }
2379
2380 /* Project the given @box into stage window coordinates, writing the
2381  * transformed vertices to @verts[]. */
2382 static gboolean
2383 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2384                                           const ClutterActorBox *box,
2385                                           ClutterVertex          verts[])
2386 {
2387   ClutterVertex box_vertices[4];
2388
2389   box_vertices[0].x = box->x1;
2390   box_vertices[0].y = box->y1;
2391   box_vertices[0].z = 0;
2392   box_vertices[1].x = box->x2;
2393   box_vertices[1].y = box->y1;
2394   box_vertices[1].z = 0;
2395   box_vertices[2].x = box->x1;
2396   box_vertices[2].y = box->y2;
2397   box_vertices[2].z = 0;
2398   box_vertices[3].x = box->x2;
2399   box_vertices[3].y = box->y2;
2400   box_vertices[3].z = 0;
2401
2402   return
2403     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2404 }
2405
2406 /**
2407  * clutter_actor_get_allocation_vertices:
2408  * @self: A #ClutterActor
2409  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2410  *   against, or %NULL to use the #ClutterStage
2411  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2412  *   location for an array of 4 #ClutterVertex in which to store the result
2413  *
2414  * Calculates the transformed coordinates of the four corners of the
2415  * actor in the plane of @ancestor. The returned vertices relate to
2416  * the #ClutterActorBox coordinates as follows:
2417  * <itemizedlist>
2418  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2419  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2420  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2421  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2422  * </itemizedlist>
2423  *
2424  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2425  * this case, the coordinates returned will be the coordinates on
2426  * the stage before the projection is applied. This is different from
2427  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2428  *
2429  * Since: 0.6
2430  */
2431 void
2432 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2433                                        ClutterActor  *ancestor,
2434                                        ClutterVertex  verts[])
2435 {
2436   ClutterActorPrivate *priv;
2437   ClutterActorBox box;
2438   ClutterVertex vertices[4];
2439   CoglMatrix modelview;
2440
2441   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2442   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2443
2444   if (ancestor == NULL)
2445     ancestor = _clutter_actor_get_stage_internal (self);
2446
2447   /* Fallback to a NOP transform if the actor isn't parented under a
2448    * stage. */
2449   if (ancestor == NULL)
2450     ancestor = self;
2451
2452   priv = self->priv;
2453
2454   /* if the actor needs to be allocated we force a relayout, so that
2455    * we will have valid values to use in the transformations */
2456   if (priv->needs_allocation)
2457     {
2458       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2459       if (stage)
2460         _clutter_stage_maybe_relayout (stage);
2461       else
2462         {
2463           box.x1 = box.y1 = 0;
2464           /* The result isn't really meaningful in this case but at
2465            * least try to do something *vaguely* reasonable... */
2466           clutter_actor_get_size (self, &box.x2, &box.y2);
2467         }
2468     }
2469
2470   clutter_actor_get_allocation_box (self, &box);
2471
2472   vertices[0].x = box.x1;
2473   vertices[0].y = box.y1;
2474   vertices[0].z = 0;
2475   vertices[1].x = box.x2;
2476   vertices[1].y = box.y1;
2477   vertices[1].z = 0;
2478   vertices[2].x = box.x1;
2479   vertices[2].y = box.y2;
2480   vertices[2].z = 0;
2481   vertices[3].x = box.x2;
2482   vertices[3].y = box.y2;
2483   vertices[3].z = 0;
2484
2485   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2486                                                      &modelview);
2487
2488   cogl_matrix_transform_points (&modelview,
2489                                 3,
2490                                 sizeof (ClutterVertex),
2491                                 vertices,
2492                                 sizeof (ClutterVertex),
2493                                 vertices,
2494                                 4);
2495 }
2496
2497 /**
2498  * clutter_actor_get_abs_allocation_vertices:
2499  * @self: A #ClutterActor
2500  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2501  *   of 4 #ClutterVertex where to store the result.
2502  *
2503  * Calculates the transformed screen coordinates of the four corners of
2504  * the actor; the returned vertices relate to the #ClutterActorBox
2505  * coordinates  as follows:
2506  * <itemizedlist>
2507  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2508  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2509  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2510  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2511  * </itemizedlist>
2512  *
2513  * Since: 0.4
2514  */
2515 void
2516 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2517                                            ClutterVertex  verts[])
2518 {
2519   ClutterActorPrivate *priv;
2520   ClutterActorBox actor_space_allocation;
2521
2522   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2523
2524   priv = self->priv;
2525
2526   /* if the actor needs to be allocated we force a relayout, so that
2527    * the actor allocation box will be valid for
2528    * _clutter_actor_transform_and_project_box()
2529    */
2530   if (priv->needs_allocation)
2531     {
2532       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2533       /* There's nothing meaningful we can do now */
2534       if (!stage)
2535         return;
2536
2537       _clutter_stage_maybe_relayout (stage);
2538     }
2539
2540   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2541    * own coordinate space... */
2542   actor_space_allocation.x1 = 0;
2543   actor_space_allocation.y1 = 0;
2544   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2545   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2546   _clutter_actor_transform_and_project_box (self,
2547                                             &actor_space_allocation,
2548                                             verts);
2549 }
2550
2551 static void
2552 clutter_actor_real_apply_transform (ClutterActor *self,
2553                                     CoglMatrix   *matrix)
2554 {
2555   ClutterActorPrivate *priv = self->priv;
2556
2557   if (!priv->transform_valid)
2558     {
2559       CoglMatrix *transform = &priv->transform;
2560       const ClutterTransformInfo *info;
2561
2562       info = _clutter_actor_get_transform_info_or_defaults (self);
2563
2564       cogl_matrix_init_identity (transform);
2565
2566       cogl_matrix_translate (transform,
2567                              priv->allocation.x1,
2568                              priv->allocation.y1,
2569                              0.0);
2570
2571       if (priv->z)
2572         cogl_matrix_translate (transform, 0, 0, priv->z);
2573
2574       /*
2575        * because the rotation involves translations, we must scale
2576        * before applying the rotations (if we apply the scale after
2577        * the rotations, the translations included in the rotation are
2578        * not scaled and so the entire object will move on the screen
2579        * as a result of rotating it).
2580        */
2581       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2582         {
2583           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2584                                         &info->scale_center,
2585                                         cogl_matrix_scale (transform,
2586                                                            info->scale_x,
2587                                                            info->scale_y,
2588                                                            1.0));
2589         }
2590
2591       if (info->rz_angle)
2592         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2593                                       &info->rz_center,
2594                                       cogl_matrix_rotate (transform,
2595                                                           info->rz_angle,
2596                                                           0, 0, 1.0));
2597
2598       if (info->ry_angle)
2599         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2600                                       &info->ry_center,
2601                                       cogl_matrix_rotate (transform,
2602                                                           info->ry_angle,
2603                                                           0, 1.0, 0));
2604
2605       if (info->rx_angle)
2606         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2607                                       &info->rx_center,
2608                                       cogl_matrix_rotate (transform,
2609                                                           info->rx_angle,
2610                                                           1.0, 0, 0));
2611
2612       if (!clutter_anchor_coord_is_zero (&info->anchor))
2613         {
2614           gfloat x, y, z;
2615
2616           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2617           cogl_matrix_translate (transform, -x, -y, -z);
2618         }
2619
2620       priv->transform_valid = TRUE;
2621     }
2622
2623   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2624 }
2625
2626 /* Applies the transforms associated with this actor to the given
2627  * matrix. */
2628 void
2629 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2630                                           CoglMatrix *matrix)
2631 {
2632   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2633 }
2634
2635 /*
2636  * clutter_actor_apply_relative_transformation_matrix:
2637  * @self: The actor whose coordinate space you want to transform from.
2638  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2639  *            or %NULL if you want to transform all the way to eye coordinates.
2640  * @matrix: A #CoglMatrix to apply the transformation too.
2641  *
2642  * This multiplies a transform with @matrix that will transform coordinates
2643  * from the coordinate space of @self into the coordinate space of @ancestor.
2644  *
2645  * For example if you need a matrix that can transform the local actor
2646  * coordinates of @self into stage coordinates you would pass the actor's stage
2647  * pointer as the @ancestor.
2648  *
2649  * If you pass %NULL then the transformation will take you all the way through
2650  * to eye coordinates. This can be useful if you want to extract the entire
2651  * modelview transform that Clutter applies before applying the projection
2652  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2653  * using cogl_set_modelview_matrix() for example then you would want a matrix
2654  * that transforms into eye coordinates.
2655  *
2656  * <note>This function doesn't initialize the given @matrix, it simply
2657  * multiplies the requested transformation matrix with the existing contents of
2658  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2659  * before calling this function, or you can use
2660  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2661  */
2662 void
2663 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2664                                                      ClutterActor *ancestor,
2665                                                      CoglMatrix *matrix)
2666 {
2667   ClutterActor *parent;
2668
2669   /* Note we terminate before ever calling stage->apply_transform()
2670    * since that would conceptually be relative to the underlying
2671    * window OpenGL coordinates so we'd need a special @ancestor
2672    * value to represent the fake parent of the stage. */
2673   if (self == ancestor)
2674     return;
2675
2676   parent = clutter_actor_get_parent (self);
2677
2678   if (parent != NULL)
2679     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2680                                                          matrix);
2681
2682   _clutter_actor_apply_modelview_transform (self, matrix);
2683 }
2684
2685 static void
2686 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2687                                        ClutterPaintVolume *pv,
2688                                        const char *label,
2689                                        const CoglColor *color)
2690 {
2691   static CoglPipeline *outline = NULL;
2692   CoglPrimitive *prim;
2693   ClutterVertex line_ends[12 * 2];
2694   int n_vertices;
2695   CoglContext *ctx =
2696     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2697   /* XXX: at some point we'll query this from the stage but we can't
2698    * do that until the osx backend uses Cogl natively. */
2699   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2700
2701   if (outline == NULL)
2702     outline = cogl_pipeline_new (ctx);
2703
2704   _clutter_paint_volume_complete (pv);
2705
2706   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2707
2708   /* Front face */
2709   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2710   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2711   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2712   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2713
2714   if (!pv->is_2d)
2715     {
2716       /* Back face */
2717       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2718       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2719       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2720       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2721
2722       /* Lines connecting front face to back face */
2723       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2724       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2725       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2726       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2727     }
2728
2729   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2730                                 n_vertices,
2731                                 (CoglVertexP3 *)line_ends);
2732
2733   cogl_pipeline_set_color (outline, color);
2734   cogl_framebuffer_draw_primitive (fb, outline, prim);
2735   cogl_object_unref (prim);
2736
2737   if (label)
2738     {
2739       PangoLayout *layout;
2740       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2741       pango_layout_set_text (layout, label, -1);
2742       cogl_pango_render_layout (layout,
2743                                 pv->vertices[0].x,
2744                                 pv->vertices[0].y,
2745                                 color,
2746                                 0);
2747       g_object_unref (layout);
2748     }
2749 }
2750
2751 static void
2752 _clutter_actor_draw_paint_volume (ClutterActor *self)
2753 {
2754   ClutterPaintVolume *pv;
2755   CoglColor color;
2756
2757   pv = _clutter_actor_get_paint_volume_mutable (self);
2758   if (!pv)
2759     {
2760       gfloat width, height;
2761       ClutterPaintVolume fake_pv;
2762
2763       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2764       _clutter_paint_volume_init_static (&fake_pv, stage);
2765
2766       clutter_actor_get_size (self, &width, &height);
2767       clutter_paint_volume_set_width (&fake_pv, width);
2768       clutter_paint_volume_set_height (&fake_pv, height);
2769
2770       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2771       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2772                                              _clutter_actor_get_debug_name (self),
2773                                              &color);
2774
2775       clutter_paint_volume_free (&fake_pv);
2776     }
2777   else
2778     {
2779       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2780       _clutter_actor_draw_paint_volume_full (self, pv,
2781                                              _clutter_actor_get_debug_name (self),
2782                                              &color);
2783     }
2784 }
2785
2786 static void
2787 _clutter_actor_paint_cull_result (ClutterActor *self,
2788                                   gboolean success,
2789                                   ClutterCullResult result)
2790 {
2791   ClutterPaintVolume *pv;
2792   CoglColor color;
2793
2794   if (success)
2795     {
2796       if (result == CLUTTER_CULL_RESULT_IN)
2797         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2798       else if (result == CLUTTER_CULL_RESULT_OUT)
2799         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2800       else
2801         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2802     }
2803   else
2804     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2805
2806   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2807     _clutter_actor_draw_paint_volume_full (self, pv,
2808                                            _clutter_actor_get_debug_name (self),
2809                                            &color);
2810   else
2811     {
2812       PangoLayout *layout;
2813       char *label =
2814         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2815       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2816       cogl_set_source_color (&color);
2817
2818       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2819       pango_layout_set_text (layout, label, -1);
2820       cogl_pango_render_layout (layout,
2821                                 0,
2822                                 0,
2823                                 &color,
2824                                 0);
2825       g_free (label);
2826       g_object_unref (layout);
2827     }
2828 }
2829
2830 static int clone_paint_level = 0;
2831
2832 void
2833 _clutter_actor_push_clone_paint (void)
2834 {
2835   clone_paint_level++;
2836 }
2837
2838 void
2839 _clutter_actor_pop_clone_paint (void)
2840 {
2841   clone_paint_level--;
2842 }
2843
2844 static gboolean
2845 in_clone_paint (void)
2846 {
2847   return clone_paint_level > 0;
2848 }
2849
2850 /* Returns TRUE if the actor can be ignored */
2851 /* FIXME: we should return a ClutterCullResult, and
2852  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2853  * means there's no point in trying to cull descendants of the current
2854  * node. */
2855 static gboolean
2856 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2857 {
2858   ClutterActorPrivate *priv = self->priv;
2859   ClutterActor *stage;
2860   const ClutterPlane *stage_clip;
2861
2862   if (!priv->last_paint_volume_valid)
2863     {
2864       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2865                     "->last_paint_volume_valid == FALSE",
2866                     _clutter_actor_get_debug_name (self));
2867       return FALSE;
2868     }
2869
2870   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2871     return FALSE;
2872
2873   stage = _clutter_actor_get_stage_internal (self);
2874   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2875   if (G_UNLIKELY (!stage_clip))
2876     {
2877       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2878                     "No stage clip set",
2879                     _clutter_actor_get_debug_name (self));
2880       return FALSE;
2881     }
2882
2883   if (cogl_get_draw_framebuffer () !=
2884       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2885     {
2886       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2887                     "Current framebuffer doesn't correspond to stage",
2888                     _clutter_actor_get_debug_name (self));
2889       return FALSE;
2890     }
2891
2892   *result_out =
2893     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2894   return TRUE;
2895 }
2896
2897 static void
2898 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2899 {
2900   ClutterActorPrivate *priv = self->priv;
2901   const ClutterPaintVolume *pv;
2902
2903   if (priv->last_paint_volume_valid)
2904     {
2905       clutter_paint_volume_free (&priv->last_paint_volume);
2906       priv->last_paint_volume_valid = FALSE;
2907     }
2908
2909   pv = clutter_actor_get_paint_volume (self);
2910   if (!pv)
2911     {
2912       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2913                     "Actor failed to report a paint volume",
2914                     _clutter_actor_get_debug_name (self));
2915       return;
2916     }
2917
2918   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2919
2920   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2921                                             NULL); /* eye coordinates */
2922
2923   priv->last_paint_volume_valid = TRUE;
2924 }
2925
2926 static inline gboolean
2927 actor_has_shader_data (ClutterActor *self)
2928 {
2929   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2930 }
2931
2932 guint32
2933 _clutter_actor_get_pick_id (ClutterActor *self)
2934 {
2935   if (self->priv->pick_id < 0)
2936     return 0;
2937
2938   return self->priv->pick_id;
2939 }
2940
2941 /* This is the same as clutter_actor_add_effect except that it doesn't
2942    queue a redraw and it doesn't notify on the effect property */
2943 static void
2944 _clutter_actor_add_effect_internal (ClutterActor  *self,
2945                                     ClutterEffect *effect)
2946 {
2947   ClutterActorPrivate *priv = self->priv;
2948
2949   if (priv->effects == NULL)
2950     {
2951       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
2952       priv->effects->actor = self;
2953     }
2954
2955   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2956 }
2957
2958 /* This is the same as clutter_actor_remove_effect except that it doesn't
2959    queue a redraw and it doesn't notify on the effect property */
2960 static void
2961 _clutter_actor_remove_effect_internal (ClutterActor  *self,
2962                                        ClutterEffect *effect)
2963 {
2964   ClutterActorPrivate *priv = self->priv;
2965
2966   if (priv->effects == NULL)
2967     return;
2968
2969   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2970 }
2971
2972 static gboolean
2973 needs_flatten_effect (ClutterActor *self)
2974 {
2975   ClutterActorPrivate *priv = self->priv;
2976
2977   if (G_UNLIKELY (clutter_paint_debug_flags &
2978                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
2979     return FALSE;
2980
2981   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
2982     return TRUE;
2983   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
2984     {
2985       if (clutter_actor_get_paint_opacity (self) < 255 &&
2986           clutter_actor_has_overlaps (self))
2987         return TRUE;
2988     }
2989
2990   return FALSE;
2991 }
2992
2993 static void
2994 add_or_remove_flatten_effect (ClutterActor *self)
2995 {
2996   ClutterActorPrivate *priv = self->priv;
2997
2998   /* Add or remove the flatten effect depending on the
2999      offscreen-redirect property. */
3000   if (needs_flatten_effect (self))
3001     {
3002       if (priv->flatten_effect == NULL)
3003         {
3004           ClutterActorMeta *actor_meta;
3005           gint priority;
3006
3007           priv->flatten_effect = _clutter_flatten_effect_new ();
3008           /* Keep a reference to the effect so that we can queue
3009              redraws from it */
3010           g_object_ref_sink (priv->flatten_effect);
3011
3012           /* Set the priority of the effect to high so that it will
3013              always be applied to the actor first. It uses an internal
3014              priority so that it won't be visible to applications */
3015           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3016           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3017           _clutter_actor_meta_set_priority (actor_meta, priority);
3018
3019           /* This will add the effect without queueing a redraw */
3020           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3021         }
3022     }
3023   else
3024     {
3025       if (priv->flatten_effect != NULL)
3026         {
3027           /* Destroy the effect so that it will lose its fbo cache of
3028              the actor */
3029           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3030           g_object_unref (priv->flatten_effect);
3031           priv->flatten_effect = NULL;
3032         }
3033     }
3034 }
3035
3036 static void
3037 clutter_actor_real_paint (ClutterActor *actor)
3038 {
3039   ClutterActorPrivate *priv = actor->priv;
3040   ClutterActor *iter;
3041
3042   /* paint the background color, if set */
3043   if (priv->bg_color_set)
3044     {
3045       float width, height;
3046       guint8 real_alpha;
3047
3048       clutter_actor_box_get_size (&priv->allocation, &width, &height);
3049
3050       real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3051                  * priv->bg_color.alpha
3052                  / 255;
3053
3054       cogl_set_source_color4ub (priv->bg_color.red,
3055                                 priv->bg_color.green,
3056                                 priv->bg_color.blue,
3057                                 real_alpha);
3058
3059       cogl_rectangle (0, 0, width, height);
3060     }
3061
3062   for (iter = priv->first_child;
3063        iter != NULL;
3064        iter = iter->priv->next_sibling)
3065     {
3066       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3067                     _clutter_actor_get_debug_name (iter),
3068                     _clutter_actor_get_debug_name (actor),
3069                     iter->priv->allocation.x1,
3070                     iter->priv->allocation.y1,
3071                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3072                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3073
3074       clutter_actor_paint (iter);
3075     }
3076 }
3077
3078 /**
3079  * clutter_actor_paint:
3080  * @self: A #ClutterActor
3081  *
3082  * Renders the actor to display.
3083  *
3084  * This function should not be called directly by applications.
3085  * Call clutter_actor_queue_redraw() to queue paints, instead.
3086  *
3087  * This function is context-aware, and will either cause a
3088  * regular paint or a pick paint.
3089  *
3090  * This function will emit the #ClutterActor::paint signal or
3091  * the #ClutterActor::pick signal, depending on the context.
3092  *
3093  * This function does not paint the actor if the actor is set to 0,
3094  * unless it is performing a pick paint.
3095  */
3096 void
3097 clutter_actor_paint (ClutterActor *self)
3098 {
3099   ClutterActorPrivate *priv;
3100   ClutterPickMode pick_mode;
3101   gboolean clip_set = FALSE;
3102   gboolean shader_applied = FALSE;
3103
3104   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3105                           "Actor real-paint counter",
3106                           "Increments each time any actor is painted",
3107                           0 /* no application private data */);
3108   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3109                           "Actor pick-paint counter",
3110                           "Increments each time any actor is painted "
3111                           "for picking",
3112                           0 /* no application private data */);
3113
3114   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3115
3116   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3117     return;
3118
3119   priv = self->priv;
3120
3121   pick_mode = _clutter_context_get_pick_mode ();
3122
3123   if (pick_mode == CLUTTER_PICK_NONE)
3124     priv->propagated_one_redraw = FALSE;
3125
3126   /* It's an important optimization that we consider painting of
3127    * actors with 0 opacity to be a NOP... */
3128   if (pick_mode == CLUTTER_PICK_NONE &&
3129       /* ignore top-levels, since they might be transparent */
3130       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3131       /* Use the override opacity if its been set */
3132       ((priv->opacity_override >= 0) ?
3133        priv->opacity_override : priv->opacity) == 0)
3134     return;
3135
3136   /* if we aren't paintable (not in a toplevel with all
3137    * parents paintable) then do nothing.
3138    */
3139   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3140     return;
3141
3142   /* mark that we are in the paint process */
3143   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3144
3145   cogl_push_matrix();
3146
3147   if (priv->enable_model_view_transform)
3148     {
3149       CoglMatrix matrix;
3150
3151       /* XXX: It could be better to cache the modelview with the actor
3152        * instead of progressively building up the transformations on
3153        * the matrix stack every time we paint. */
3154       cogl_get_modelview_matrix (&matrix);
3155       _clutter_actor_apply_modelview_transform (self, &matrix);
3156
3157 #ifdef CLUTTER_ENABLE_DEBUG
3158       /* Catch when out-of-band transforms have been made by actors not as part
3159        * of an apply_transform vfunc... */
3160       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3161         {
3162           CoglMatrix expected_matrix;
3163
3164           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3165                                                              &expected_matrix);
3166
3167           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3168             {
3169               GString *buf = g_string_sized_new (1024);
3170               ClutterActor *parent;
3171
3172               parent = self;
3173               while (parent != NULL)
3174                 {
3175                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3176
3177                   if (parent->priv->parent != NULL)
3178                     g_string_append (buf, "->");
3179
3180                   parent = parent->priv->parent;
3181                 }
3182
3183               g_warning ("Unexpected transform found when painting actor "
3184                          "\"%s\". This will be caused by one of the actor's "
3185                          "ancestors (%s) using the Cogl API directly to transform "
3186                          "children instead of using ::apply_transform().",
3187                          _clutter_actor_get_debug_name (self),
3188                          buf->str);
3189
3190               g_string_free (buf, TRUE);
3191             }
3192         }
3193 #endif /* CLUTTER_ENABLE_DEBUG */
3194
3195       cogl_set_modelview_matrix (&matrix);
3196     }
3197
3198   if (priv->has_clip)
3199     {
3200       cogl_clip_push_rectangle (priv->clip.x,
3201                                 priv->clip.y,
3202                                 priv->clip.x + priv->clip.width,
3203                                 priv->clip.y + priv->clip.height);
3204       clip_set = TRUE;
3205     }
3206   else if (priv->clip_to_allocation)
3207     {
3208       gfloat width, height;
3209
3210       width  = priv->allocation.x2 - priv->allocation.x1;
3211       height = priv->allocation.y2 - priv->allocation.y1;
3212
3213       cogl_clip_push_rectangle (0, 0, width, height);
3214       clip_set = TRUE;
3215     }
3216
3217   if (pick_mode == CLUTTER_PICK_NONE)
3218     {
3219       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3220
3221       /* We check whether we need to add the flatten effect before
3222          each paint so that we can avoid having a mechanism for
3223          applications to notify when the value of the
3224          has_overlaps virtual changes. */
3225       add_or_remove_flatten_effect (self);
3226     }
3227   else
3228     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3229
3230   /* We save the current paint volume so that the next time the
3231    * actor queues a redraw we can constrain the redraw to just
3232    * cover the union of the new bounding box and the old.
3233    *
3234    * We also fetch the current paint volume to perform culling so
3235    * we can avoid painting actors outside the current clip region.
3236    *
3237    * If we are painting inside a clone, we should neither update
3238    * the paint volume or use it to cull painting, since the paint
3239    * box represents the location of the source actor on the
3240    * screen.
3241    *
3242    * XXX: We are starting to do a lot of vertex transforms on
3243    * the CPU in a typical paint, so at some point we should
3244    * audit these and consider caching some things.
3245    *
3246    * NB: We don't perform culling while picking at this point because
3247    * clutter-stage.c doesn't setup the clipping planes appropriately.
3248    *
3249    * NB: We don't want to update the last-paint-volume during picking
3250    * because the last-paint-volume is used to determine the old screen
3251    * space location of an actor that has moved so we can know the
3252    * minimal region to redraw to clear an old view of the actor. If we
3253    * update this during picking then by the time we come around to
3254    * paint then the last-paint-volume would likely represent the new
3255    * actor position not the old.
3256    */
3257   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3258     {
3259       gboolean success;
3260       /* annoyingly gcc warns if uninitialized even though
3261        * the initialization is redundant :-( */
3262       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3263
3264       if (G_LIKELY ((clutter_paint_debug_flags &
3265                      (CLUTTER_DEBUG_DISABLE_CULLING |
3266                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3267                     (CLUTTER_DEBUG_DISABLE_CULLING |
3268                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3269         _clutter_actor_update_last_paint_volume (self);
3270
3271       success = cull_actor (self, &result);
3272
3273       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3274         _clutter_actor_paint_cull_result (self, success, result);
3275       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3276         goto done;
3277     }
3278
3279   if (priv->effects == NULL)
3280     {
3281       if (pick_mode == CLUTTER_PICK_NONE &&
3282           actor_has_shader_data (self))
3283         {
3284           _clutter_actor_shader_pre_paint (self, FALSE);
3285           shader_applied = TRUE;
3286         }
3287
3288       priv->next_effect_to_paint = NULL;
3289     }
3290   else
3291     priv->next_effect_to_paint =
3292       _clutter_meta_group_peek_metas (priv->effects);
3293
3294   clutter_actor_continue_paint (self);
3295
3296   if (shader_applied)
3297     _clutter_actor_shader_post_paint (self);
3298
3299   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3300                   pick_mode == CLUTTER_PICK_NONE))
3301     _clutter_actor_draw_paint_volume (self);
3302
3303 done:
3304   /* If we make it here then the actor has run through a complete
3305      paint run including all the effects so it's no longer dirty */
3306   if (pick_mode == CLUTTER_PICK_NONE)
3307     priv->is_dirty = FALSE;
3308
3309   if (clip_set)
3310     cogl_clip_pop();
3311
3312   cogl_pop_matrix();
3313
3314   /* paint sequence complete */
3315   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3316 }
3317
3318 /**
3319  * clutter_actor_continue_paint:
3320  * @self: A #ClutterActor
3321  *
3322  * Run the next stage of the paint sequence. This function should only
3323  * be called within the implementation of the ‘run’ virtual of a
3324  * #ClutterEffect. It will cause the run method of the next effect to
3325  * be applied, or it will paint the actual actor if the current effect
3326  * is the last effect in the chain.
3327  *
3328  * Since: 1.8
3329  */
3330 void
3331 clutter_actor_continue_paint (ClutterActor *self)
3332 {
3333   ClutterActorPrivate *priv;
3334
3335   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3336   /* This should only be called from with in the ‘run’ implementation
3337      of a ClutterEffect */
3338   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3339
3340   priv = self->priv;
3341
3342   /* Skip any effects that are disabled */
3343   while (priv->next_effect_to_paint &&
3344          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3345     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3346
3347   /* If this has come from the last effect then we'll just paint the
3348      actual actor */
3349   if (priv->next_effect_to_paint == NULL)
3350     {
3351       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3352         {
3353           g_signal_emit (self, actor_signals[PAINT], 0);
3354         }
3355       else
3356         {
3357           ClutterColor col = { 0, };
3358
3359           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3360
3361           /* Actor will then paint silhouette of itself in supplied
3362            * color.  See clutter_stage_get_actor_at_pos() for where
3363            * picking is enabled.
3364            */
3365           g_signal_emit (self, actor_signals[PICK], 0, &col);
3366         }
3367     }
3368   else
3369     {
3370       ClutterEffect *old_current_effect;
3371       ClutterEffectPaintFlags run_flags = 0;
3372
3373       /* Cache the current effect so that we can put it back before
3374          returning */
3375       old_current_effect = priv->current_effect;
3376
3377       priv->current_effect = priv->next_effect_to_paint->data;
3378       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3379
3380       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3381         {
3382           if (priv->is_dirty)
3383             {
3384               /* If there's an effect queued with this redraw then all
3385                  effects up to that one will be considered dirty. It
3386                  is expected the queued effect will paint the cached
3387                  image and not call clutter_actor_continue_paint again
3388                  (although it should work ok if it does) */
3389               if (priv->effect_to_redraw == NULL ||
3390                   priv->current_effect != priv->effect_to_redraw)
3391                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3392             }
3393
3394           _clutter_effect_paint (priv->current_effect, run_flags);
3395         }
3396       else
3397         {
3398           /* We can't determine when an actor has been modified since
3399              its last pick so lets just assume it has always been
3400              modified */
3401           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3402
3403           _clutter_effect_pick (priv->current_effect, run_flags);
3404         }
3405
3406       priv->current_effect = old_current_effect;
3407     }
3408 }
3409
3410 static ClutterActorTraverseVisitFlags
3411 invalidate_queue_redraw_entry (ClutterActor *self,
3412                                int           depth,
3413                                gpointer      user_data)
3414 {
3415   ClutterActorPrivate *priv = self->priv;
3416
3417   if (priv->queue_redraw_entry != NULL)
3418     {
3419       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3420       priv->queue_redraw_entry = NULL;
3421     }
3422
3423   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3424 }
3425
3426 static inline void
3427 remove_child (ClutterActor *self,
3428               ClutterActor *child)
3429 {
3430   ClutterActor *prev_sibling, *next_sibling;
3431
3432   prev_sibling = child->priv->prev_sibling;
3433   next_sibling = child->priv->next_sibling;
3434
3435   if (prev_sibling != NULL)
3436     prev_sibling->priv->next_sibling = next_sibling;
3437
3438   if (next_sibling != NULL)
3439     next_sibling->priv->prev_sibling = prev_sibling;
3440
3441   if (self->priv->first_child == child)
3442     self->priv->first_child = next_sibling;
3443
3444   if (self->priv->last_child == child)
3445     self->priv->last_child = prev_sibling;
3446
3447   child->priv->parent = NULL;
3448   child->priv->prev_sibling = NULL;
3449   child->priv->next_sibling = NULL;
3450 }
3451
3452 typedef enum {
3453   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3454   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3455   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3456   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3457   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3458   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3459
3460   /* default flags for public API */
3461   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3462                                     REMOVE_CHILD_EMIT_PARENT_SET |
3463                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3464                                     REMOVE_CHILD_CHECK_STATE |
3465                                     REMOVE_CHILD_FLUSH_QUEUE |
3466                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3467
3468   /* flags for legacy/deprecated API */
3469   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3470                                     REMOVE_CHILD_FLUSH_QUEUE |
3471                                     REMOVE_CHILD_EMIT_PARENT_SET |
3472                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3473 } ClutterActorRemoveChildFlags;
3474
3475 /*< private >
3476  * clutter_actor_remove_child_internal:
3477  * @self: a #ClutterActor
3478  * @child: the child of @self that has to be removed
3479  * @flags: control the removal operations
3480  *
3481  * Removes @child from the list of children of @self.
3482  */
3483 static void
3484 clutter_actor_remove_child_internal (ClutterActor                 *self,
3485                                      ClutterActor                 *child,
3486                                      ClutterActorRemoveChildFlags  flags)
3487 {
3488   ClutterActor *old_first, *old_last;
3489   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3490   gboolean flush_queue;
3491   gboolean notify_first_last;
3492   gboolean was_mapped;
3493
3494   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3495   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3496   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3497   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3498   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3499   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3500
3501   g_object_freeze_notify (G_OBJECT (self));
3502
3503   if (destroy_meta)
3504     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3505
3506   if (check_state)
3507     {
3508       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3509
3510       /* we need to unrealize *before* we set parent_actor to NULL,
3511        * because in an unrealize method actors are dissociating from the
3512        * stage, which means they need to be able to
3513        * clutter_actor_get_stage().
3514        *
3515        * yhis should unmap and unrealize, unless we're reparenting.
3516        */
3517       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3518     }
3519   else
3520     was_mapped = FALSE;
3521
3522   if (flush_queue)
3523     {
3524       /* We take this opportunity to invalidate any queue redraw entry
3525        * associated with the actor and descendants since we won't be able to
3526        * determine the appropriate stage after this.
3527        *
3528        * we do this after we updated the mapped state because actors might
3529        * end up queueing redraws inside their mapped/unmapped virtual
3530        * functions, and if we invalidate the redraw entry we could end up
3531        * with an inconsistent state and weird memory corruption. see
3532        * bugs:
3533        *
3534        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3535        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3536        */
3537       _clutter_actor_traverse (child,
3538                                0,
3539                                invalidate_queue_redraw_entry,
3540                                NULL,
3541                                NULL);
3542     }
3543
3544   old_first = self->priv->first_child;
3545   old_last = self->priv->last_child;
3546
3547   remove_child (self, child);
3548
3549   self->priv->n_children -= 1;
3550
3551   self->priv->age += 1;
3552
3553   /* clutter_actor_reparent() will emit ::parent-set for us */
3554   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3555     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3556
3557   /* if the child was mapped then we need to relayout ourselves to account
3558    * for the removed child
3559    */
3560   if (was_mapped)
3561     clutter_actor_queue_relayout (self);
3562
3563   /* we need to emit the signal before dropping the reference */
3564   if (emit_actor_removed)
3565     g_signal_emit_by_name (self, "actor-removed", child);
3566
3567   if (notify_first_last)
3568     {
3569       if (old_first != self->priv->first_child)
3570         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3571
3572       if (old_last != self->priv->last_child)
3573         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3574     }
3575
3576   g_object_thaw_notify (G_OBJECT (self));
3577
3578   /* remove the reference we acquired in clutter_actor_add_child() */
3579   g_object_unref (child);
3580 }
3581
3582 static const ClutterTransformInfo default_transform_info = {
3583   0.0, { 0, },          /* rotation-x */
3584   0.0, { 0, },          /* rotation-y */
3585   0.0, { 0, },          /* rotation-z */
3586
3587   1.0, 1.0, { 0, },     /* scale */
3588
3589   { 0, },               /* anchor */
3590 };
3591
3592 /*< private >
3593  * _clutter_actor_get_transform_info_or_defaults:
3594  * @self: a #ClutterActor
3595  *
3596  * Retrieves the ClutterTransformInfo structure associated to an actor.
3597  *
3598  * If the actor does not have a ClutterTransformInfo structure associated
3599  * to it, then the default structure will be returned.
3600  *
3601  * This function should only be used for getters.
3602  *
3603  * Return value: a const pointer to the ClutterTransformInfo structure
3604  */
3605 const ClutterTransformInfo *
3606 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3607 {
3608   ClutterTransformInfo *info;
3609
3610   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3611   if (info != NULL)
3612     return info;
3613
3614   return &default_transform_info;
3615 }
3616
3617 static void
3618 clutter_transform_info_free (gpointer data)
3619 {
3620   if (data != NULL)
3621     g_slice_free (ClutterTransformInfo, data);
3622 }
3623
3624 /*< private >
3625  * _clutter_actor_get_transform_info:
3626  * @self: a #ClutterActor
3627  *
3628  * Retrieves a pointer to the ClutterTransformInfo structure.
3629  *
3630  * If the actor does not have a ClutterTransformInfo associated to it, one
3631  * will be created and initialized to the default values.
3632  *
3633  * This function should be used for setters.
3634  *
3635  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3636  * instead.
3637  *
3638  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3639  *   structure
3640  */
3641 ClutterTransformInfo *
3642 _clutter_actor_get_transform_info (ClutterActor *self)
3643 {
3644   ClutterTransformInfo *info;
3645
3646   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3647   if (info == NULL)
3648     {
3649       info = g_slice_new (ClutterTransformInfo);
3650
3651       *info = default_transform_info;
3652
3653       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3654                                info,
3655                                clutter_transform_info_free);
3656     }
3657
3658   return info;
3659 }
3660
3661 /*< private >
3662  * clutter_actor_set_rotation_angle_internal:
3663  * @self: a #ClutterActor
3664  * @axis: the axis of the angle to change
3665  * @angle: the angle of rotation
3666  *
3667  * Sets the rotation angle on the given axis without affecting the
3668  * rotation center point.
3669  */
3670 static inline void
3671 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3672                                            ClutterRotateAxis  axis,
3673                                            gdouble            angle)
3674 {
3675   GObject *obj = G_OBJECT (self);
3676   ClutterTransformInfo *info;
3677
3678   info = _clutter_actor_get_transform_info (self);
3679
3680   g_object_freeze_notify (obj);
3681
3682   switch (axis)
3683     {
3684     case CLUTTER_X_AXIS:
3685       info->rx_angle = angle;
3686       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3687       break;
3688
3689     case CLUTTER_Y_AXIS:
3690       info->ry_angle = angle;
3691       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3692       break;
3693
3694     case CLUTTER_Z_AXIS:
3695       info->rz_angle = angle;
3696       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3697       break;
3698     }
3699
3700   self->priv->transform_valid = FALSE;
3701
3702   g_object_thaw_notify (obj);
3703
3704   clutter_actor_queue_redraw (self);
3705 }
3706
3707 /*< private >
3708  * clutter_actor_set_rotation_center_internal:
3709  * @self: a #ClutterActor
3710  * @axis: the axis of the center to change
3711  * @center: the coordinates of the rotation center
3712  *
3713  * Sets the rotation center on the given axis without affecting the
3714  * rotation angle.
3715  */
3716 static inline void
3717 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3718                                             ClutterRotateAxis    axis,
3719                                             const ClutterVertex *center)
3720 {
3721   GObject *obj = G_OBJECT (self);
3722   ClutterTransformInfo *info;
3723   ClutterVertex v = { 0, 0, 0 };
3724
3725   info = _clutter_actor_get_transform_info (self);
3726
3727   if (center != NULL)
3728     v = *center;
3729
3730   g_object_freeze_notify (obj);
3731
3732   switch (axis)
3733     {
3734     case CLUTTER_X_AXIS:
3735       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3736       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3737       break;
3738
3739     case CLUTTER_Y_AXIS:
3740       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3741       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3742       break;
3743
3744     case CLUTTER_Z_AXIS:
3745       /* if the previously set rotation center was fractional, then
3746        * setting explicit coordinates will have to notify the
3747        * :rotation-center-z-gravity property as well
3748        */
3749       if (info->rz_center.is_fractional)
3750         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3751
3752       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3753       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3754       break;
3755     }
3756
3757   self->priv->transform_valid = FALSE;
3758
3759   g_object_thaw_notify (obj);
3760
3761   clutter_actor_queue_redraw (self);
3762 }
3763
3764 static inline void
3765 clutter_actor_set_scale_factor (ClutterActor      *self,
3766                                 ClutterRotateAxis  axis,
3767                                 gdouble            factor)
3768 {
3769   GObject *obj = G_OBJECT (self);
3770   ClutterTransformInfo *info;
3771
3772   info = _clutter_actor_get_transform_info (self);
3773
3774   g_object_freeze_notify (obj);
3775
3776   switch (axis)
3777     {
3778     case CLUTTER_X_AXIS:
3779       info->scale_x = factor;
3780       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
3781       break;
3782
3783     case CLUTTER_Y_AXIS:
3784       info->scale_y = factor;
3785       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
3786       break;
3787
3788     default:
3789       g_assert_not_reached ();
3790     }
3791
3792   self->priv->transform_valid = FALSE;
3793
3794   clutter_actor_queue_redraw (self);
3795
3796   g_object_thaw_notify (obj);
3797 }
3798
3799 static inline void
3800 clutter_actor_set_scale_center (ClutterActor      *self,
3801                                 ClutterRotateAxis  axis,
3802                                 gfloat             coord)
3803 {
3804   GObject *obj = G_OBJECT (self);
3805   ClutterTransformInfo *info;
3806   gfloat center_x, center_y;
3807
3808   info = _clutter_actor_get_transform_info (self);
3809
3810   g_object_freeze_notify (obj);
3811
3812   /* get the current scale center coordinates */
3813   clutter_anchor_coord_get_units (self, &info->scale_center,
3814                                   &center_x,
3815                                   &center_y,
3816                                   NULL);
3817
3818   /* we need to notify this too, because setting explicit coordinates will
3819    * change the gravity as a side effect
3820    */
3821   if (info->scale_center.is_fractional)
3822     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3823
3824   switch (axis)
3825     {
3826     case CLUTTER_X_AXIS:
3827       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3828       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3829       break;
3830
3831     case CLUTTER_Y_AXIS:
3832       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3833       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3834       break;
3835
3836     default:
3837       g_assert_not_reached ();
3838     }
3839
3840   self->priv->transform_valid = FALSE;
3841
3842   clutter_actor_queue_redraw (self);
3843
3844   g_object_thaw_notify (obj);
3845 }
3846
3847 static inline void
3848 clutter_actor_set_anchor_coord (ClutterActor      *self,
3849                                 ClutterRotateAxis  axis,
3850                                 gfloat             coord)
3851 {
3852   GObject *obj = G_OBJECT (self);
3853   ClutterTransformInfo *info;
3854   gfloat anchor_x, anchor_y;
3855
3856   info = _clutter_actor_get_transform_info (self);
3857
3858   g_object_freeze_notify (obj);
3859
3860   clutter_anchor_coord_get_units (self, &info->anchor,
3861                                   &anchor_x,
3862                                   &anchor_y,
3863                                   NULL);
3864
3865   if (info->anchor.is_fractional)
3866     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
3867
3868   switch (axis)
3869     {
3870     case CLUTTER_X_AXIS:
3871       clutter_anchor_coord_set_units (&info->anchor,
3872                                       coord,
3873                                       anchor_y,
3874                                       0.0);
3875       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
3876       break;
3877
3878     case CLUTTER_Y_AXIS:
3879       clutter_anchor_coord_set_units (&info->anchor,
3880                                       anchor_x,
3881                                       coord,
3882                                       0.0);
3883       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
3884       break;
3885
3886     default:
3887       g_assert_not_reached ();
3888     }
3889
3890   self->priv->transform_valid = FALSE;
3891
3892   clutter_actor_queue_redraw (self);
3893
3894   g_object_thaw_notify (obj);
3895 }
3896
3897 static void
3898 clutter_actor_set_property (GObject      *object,
3899                             guint         prop_id,
3900                             const GValue *value,
3901                             GParamSpec   *pspec)
3902 {
3903   ClutterActor *actor = CLUTTER_ACTOR (object);
3904   ClutterActorPrivate *priv = actor->priv;
3905
3906   switch (prop_id)
3907     {
3908     case PROP_X:
3909       clutter_actor_set_x (actor, g_value_get_float (value));
3910       break;
3911
3912     case PROP_Y:
3913       clutter_actor_set_y (actor, g_value_get_float (value));
3914       break;
3915
3916     case PROP_WIDTH:
3917       clutter_actor_set_width (actor, g_value_get_float (value));
3918       break;
3919
3920     case PROP_HEIGHT:
3921       clutter_actor_set_height (actor, g_value_get_float (value));
3922       break;
3923
3924     case PROP_FIXED_X:
3925       clutter_actor_set_x (actor, g_value_get_float (value));
3926       break;
3927
3928     case PROP_FIXED_Y:
3929       clutter_actor_set_y (actor, g_value_get_float (value));
3930       break;
3931
3932     case PROP_FIXED_POSITION_SET:
3933       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
3934       break;
3935
3936     case PROP_MIN_WIDTH:
3937       clutter_actor_set_min_width (actor, g_value_get_float (value));
3938       break;
3939
3940     case PROP_MIN_HEIGHT:
3941       clutter_actor_set_min_height (actor, g_value_get_float (value));
3942       break;
3943
3944     case PROP_NATURAL_WIDTH:
3945       clutter_actor_set_natural_width (actor, g_value_get_float (value));
3946       break;
3947
3948     case PROP_NATURAL_HEIGHT:
3949       clutter_actor_set_natural_height (actor, g_value_get_float (value));
3950       break;
3951
3952     case PROP_MIN_WIDTH_SET:
3953       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
3954       break;
3955
3956     case PROP_MIN_HEIGHT_SET:
3957       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
3958       break;
3959
3960     case PROP_NATURAL_WIDTH_SET:
3961       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
3962       break;
3963
3964     case PROP_NATURAL_HEIGHT_SET:
3965       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
3966       break;
3967
3968     case PROP_REQUEST_MODE:
3969       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
3970       break;
3971
3972     case PROP_DEPTH:
3973       clutter_actor_set_depth (actor, g_value_get_float (value));
3974       break;
3975
3976     case PROP_OPACITY:
3977       clutter_actor_set_opacity (actor, g_value_get_uint (value));
3978       break;
3979
3980     case PROP_OFFSCREEN_REDIRECT:
3981       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
3982       break;
3983
3984     case PROP_NAME:
3985       clutter_actor_set_name (actor, g_value_get_string (value));
3986       break;
3987
3988     case PROP_VISIBLE:
3989       if (g_value_get_boolean (value) == TRUE)
3990         clutter_actor_show (actor);
3991       else
3992         clutter_actor_hide (actor);
3993       break;
3994
3995     case PROP_SCALE_X:
3996       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
3997                                       g_value_get_double (value));
3998       break;
3999
4000     case PROP_SCALE_Y:
4001       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4002                                       g_value_get_double (value));
4003       break;
4004
4005     case PROP_SCALE_CENTER_X:
4006       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4007                                       g_value_get_float (value));
4008       break;
4009
4010     case PROP_SCALE_CENTER_Y:
4011       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4012                                       g_value_get_float (value));
4013       break;
4014
4015     case PROP_SCALE_GRAVITY:
4016       {
4017         const ClutterTransformInfo *info;
4018         ClutterGravity gravity;
4019
4020         info = _clutter_actor_get_transform_info_or_defaults (actor);
4021         gravity = g_value_get_enum (value);
4022
4023         clutter_actor_set_scale_with_gravity (actor,
4024                                               info->scale_x,
4025                                               info->scale_y,
4026                                               gravity);
4027       }
4028       break;
4029
4030     case PROP_CLIP:
4031       {
4032         const ClutterGeometry *geom = g_value_get_boxed (value);
4033
4034         clutter_actor_set_clip (actor,
4035                                 geom->x, geom->y,
4036                                 geom->width, geom->height);
4037       }
4038       break;
4039
4040     case PROP_CLIP_TO_ALLOCATION:
4041       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4042       break;
4043
4044     case PROP_REACTIVE:
4045       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4046       break;
4047
4048     case PROP_ROTATION_ANGLE_X:
4049       clutter_actor_set_rotation_angle_internal (actor,
4050                                                  CLUTTER_X_AXIS,
4051                                                  g_value_get_double (value));
4052       break;
4053
4054     case PROP_ROTATION_ANGLE_Y:
4055       clutter_actor_set_rotation_angle_internal (actor,
4056                                                  CLUTTER_Y_AXIS,
4057                                                  g_value_get_double (value));
4058       break;
4059
4060     case PROP_ROTATION_ANGLE_Z:
4061       clutter_actor_set_rotation_angle_internal (actor,
4062                                                  CLUTTER_Z_AXIS,
4063                                                  g_value_get_double (value));
4064       break;
4065
4066     case PROP_ROTATION_CENTER_X:
4067       clutter_actor_set_rotation_center_internal (actor,
4068                                                   CLUTTER_X_AXIS,
4069                                                   g_value_get_boxed (value));
4070       break;
4071
4072     case PROP_ROTATION_CENTER_Y:
4073       clutter_actor_set_rotation_center_internal (actor,
4074                                                   CLUTTER_Y_AXIS,
4075                                                   g_value_get_boxed (value));
4076       break;
4077
4078     case PROP_ROTATION_CENTER_Z:
4079       clutter_actor_set_rotation_center_internal (actor,
4080                                                   CLUTTER_Z_AXIS,
4081                                                   g_value_get_boxed (value));
4082       break;
4083
4084     case PROP_ROTATION_CENTER_Z_GRAVITY:
4085       {
4086         const ClutterTransformInfo *info;
4087
4088         info = _clutter_actor_get_transform_info_or_defaults (actor);
4089         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4090                                                    g_value_get_enum (value));
4091       }
4092       break;
4093
4094     case PROP_ANCHOR_X:
4095       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4096                                       g_value_get_float (value));
4097       break;
4098
4099     case PROP_ANCHOR_Y:
4100       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4101                                       g_value_get_float (value));
4102       break;
4103
4104     case PROP_ANCHOR_GRAVITY:
4105       clutter_actor_set_anchor_point_from_gravity (actor,
4106                                                    g_value_get_enum (value));
4107       break;
4108
4109     case PROP_SHOW_ON_SET_PARENT:
4110       priv->show_on_set_parent = g_value_get_boolean (value);
4111       break;
4112
4113     case PROP_TEXT_DIRECTION:
4114       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4115       break;
4116
4117     case PROP_ACTIONS:
4118       clutter_actor_add_action (actor, g_value_get_object (value));
4119       break;
4120
4121     case PROP_CONSTRAINTS:
4122       clutter_actor_add_constraint (actor, g_value_get_object (value));
4123       break;
4124
4125     case PROP_EFFECT:
4126       clutter_actor_add_effect (actor, g_value_get_object (value));
4127       break;
4128
4129     case PROP_LAYOUT_MANAGER:
4130       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4131       break;
4132
4133     case PROP_X_ALIGN:
4134       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4135       break;
4136
4137     case PROP_Y_ALIGN:
4138       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4139       break;
4140
4141     case PROP_MARGIN_TOP:
4142       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4143       break;
4144
4145     case PROP_MARGIN_BOTTOM:
4146       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4147       break;
4148
4149     case PROP_MARGIN_LEFT:
4150       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4151       break;
4152
4153     case PROP_MARGIN_RIGHT:
4154       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4155       break;
4156
4157     case PROP_BACKGROUND_COLOR:
4158       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4159       break;
4160
4161     default:
4162       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4163       break;
4164     }
4165 }
4166
4167 static void
4168 clutter_actor_get_property (GObject    *object,
4169                             guint       prop_id,
4170                             GValue     *value,
4171                             GParamSpec *pspec)
4172 {
4173   ClutterActor *actor = CLUTTER_ACTOR (object);
4174   ClutterActorPrivate *priv = actor->priv;
4175
4176   switch (prop_id)
4177     {
4178     case PROP_X:
4179       g_value_set_float (value, clutter_actor_get_x (actor));
4180       break;
4181
4182     case PROP_Y:
4183       g_value_set_float (value, clutter_actor_get_y (actor));
4184       break;
4185
4186     case PROP_WIDTH:
4187       g_value_set_float (value, clutter_actor_get_width (actor));
4188       break;
4189
4190     case PROP_HEIGHT:
4191       g_value_set_float (value, clutter_actor_get_height (actor));
4192       break;
4193
4194     case PROP_FIXED_X:
4195       {
4196         const ClutterLayoutInfo *info;
4197
4198         info = _clutter_actor_get_layout_info_or_defaults (actor);
4199         g_value_set_float (value, info->fixed_x);
4200       }
4201       break;
4202
4203     case PROP_FIXED_Y:
4204       {
4205         const ClutterLayoutInfo *info;
4206
4207         info = _clutter_actor_get_layout_info_or_defaults (actor);
4208         g_value_set_float (value, info->fixed_y);
4209       }
4210       break;
4211
4212     case PROP_FIXED_POSITION_SET:
4213       g_value_set_boolean (value, priv->position_set);
4214       break;
4215
4216     case PROP_MIN_WIDTH:
4217       {
4218         const ClutterLayoutInfo *info;
4219
4220         info = _clutter_actor_get_layout_info_or_defaults (actor);
4221         g_value_set_float (value, info->min_width);
4222       }
4223       break;
4224
4225     case PROP_MIN_HEIGHT:
4226       {
4227         const ClutterLayoutInfo *info;
4228
4229         info = _clutter_actor_get_layout_info_or_defaults (actor);
4230         g_value_set_float (value, info->min_height);
4231       }
4232       break;
4233
4234     case PROP_NATURAL_WIDTH:
4235       {
4236         const ClutterLayoutInfo *info;
4237
4238         info = _clutter_actor_get_layout_info_or_defaults (actor);
4239         g_value_set_float (value, info->natural_width);
4240       }
4241       break;
4242
4243     case PROP_NATURAL_HEIGHT:
4244       {
4245         const ClutterLayoutInfo *info;
4246
4247         info = _clutter_actor_get_layout_info_or_defaults (actor);
4248         g_value_set_float (value, info->natural_height);
4249       }
4250       break;
4251
4252     case PROP_MIN_WIDTH_SET:
4253       g_value_set_boolean (value, priv->min_width_set);
4254       break;
4255
4256     case PROP_MIN_HEIGHT_SET:
4257       g_value_set_boolean (value, priv->min_height_set);
4258       break;
4259
4260     case PROP_NATURAL_WIDTH_SET:
4261       g_value_set_boolean (value, priv->natural_width_set);
4262       break;
4263
4264     case PROP_NATURAL_HEIGHT_SET:
4265       g_value_set_boolean (value, priv->natural_height_set);
4266       break;
4267
4268     case PROP_REQUEST_MODE:
4269       g_value_set_enum (value, priv->request_mode);
4270       break;
4271
4272     case PROP_ALLOCATION:
4273       g_value_set_boxed (value, &priv->allocation);
4274       break;
4275
4276     case PROP_DEPTH:
4277       g_value_set_float (value, clutter_actor_get_depth (actor));
4278       break;
4279
4280     case PROP_OPACITY:
4281       g_value_set_uint (value, priv->opacity);
4282       break;
4283
4284     case PROP_OFFSCREEN_REDIRECT:
4285       g_value_set_enum (value, priv->offscreen_redirect);
4286       break;
4287
4288     case PROP_NAME:
4289       g_value_set_string (value, priv->name);
4290       break;
4291
4292     case PROP_VISIBLE:
4293       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4294       break;
4295
4296     case PROP_MAPPED:
4297       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4298       break;
4299
4300     case PROP_REALIZED:
4301       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4302       break;
4303
4304     case PROP_HAS_CLIP:
4305       g_value_set_boolean (value, priv->has_clip);
4306       break;
4307
4308     case PROP_CLIP:
4309       {
4310         ClutterGeometry clip;
4311
4312         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4313         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4314         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4315         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4316
4317         g_value_set_boxed (value, &clip);
4318       }
4319       break;
4320
4321     case PROP_CLIP_TO_ALLOCATION:
4322       g_value_set_boolean (value, priv->clip_to_allocation);
4323       break;
4324
4325     case PROP_SCALE_X:
4326       {
4327         const ClutterTransformInfo *info;
4328
4329         info = _clutter_actor_get_transform_info_or_defaults (actor);
4330         g_value_set_double (value, info->scale_x);
4331       }
4332       break;
4333
4334     case PROP_SCALE_Y:
4335       {
4336         const ClutterTransformInfo *info;
4337
4338         info = _clutter_actor_get_transform_info_or_defaults (actor);
4339         g_value_set_double (value, info->scale_y);
4340       }
4341       break;
4342
4343     case PROP_SCALE_CENTER_X:
4344       {
4345         gfloat center;
4346
4347         clutter_actor_get_scale_center (actor, &center, NULL);
4348
4349         g_value_set_float (value, center);
4350       }
4351       break;
4352
4353     case PROP_SCALE_CENTER_Y:
4354       {
4355         gfloat center;
4356
4357         clutter_actor_get_scale_center (actor, NULL, &center);
4358
4359         g_value_set_float (value, center);
4360       }
4361       break;
4362
4363     case PROP_SCALE_GRAVITY:
4364       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4365       break;
4366
4367     case PROP_REACTIVE:
4368       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4369       break;
4370
4371     case PROP_ROTATION_ANGLE_X:
4372       {
4373         const ClutterTransformInfo *info;
4374
4375         info = _clutter_actor_get_transform_info_or_defaults (actor);
4376         g_value_set_double (value, info->rx_angle);
4377       }
4378       break;
4379
4380     case PROP_ROTATION_ANGLE_Y:
4381       {
4382         const ClutterTransformInfo *info;
4383
4384         info = _clutter_actor_get_transform_info_or_defaults (actor);
4385         g_value_set_double (value, info->ry_angle);
4386       }
4387       break;
4388
4389     case PROP_ROTATION_ANGLE_Z:
4390       {
4391         const ClutterTransformInfo *info;
4392
4393         info = _clutter_actor_get_transform_info_or_defaults (actor);
4394         g_value_set_double (value, info->rz_angle);
4395       }
4396       break;
4397
4398     case PROP_ROTATION_CENTER_X:
4399       {
4400         ClutterVertex center;
4401
4402         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4403                                     &center.x,
4404                                     &center.y,
4405                                     &center.z);
4406
4407         g_value_set_boxed (value, &center);
4408       }
4409       break;
4410
4411     case PROP_ROTATION_CENTER_Y:
4412       {
4413         ClutterVertex center;
4414
4415         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4416                                     &center.x,
4417                                     &center.y,
4418                                     &center.z);
4419
4420         g_value_set_boxed (value, &center);
4421       }
4422       break;
4423
4424     case PROP_ROTATION_CENTER_Z:
4425       {
4426         ClutterVertex center;
4427
4428         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4429                                     &center.x,
4430                                     &center.y,
4431                                     &center.z);
4432
4433         g_value_set_boxed (value, &center);
4434       }
4435       break;
4436
4437     case PROP_ROTATION_CENTER_Z_GRAVITY:
4438       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4439       break;
4440
4441     case PROP_ANCHOR_X:
4442       {
4443         const ClutterTransformInfo *info;
4444         gfloat anchor_x;
4445
4446         info = _clutter_actor_get_transform_info_or_defaults (actor);
4447         clutter_anchor_coord_get_units (actor, &info->anchor,
4448                                         &anchor_x,
4449                                         NULL,
4450                                         NULL);
4451         g_value_set_float (value, anchor_x);
4452       }
4453       break;
4454
4455     case PROP_ANCHOR_Y:
4456       {
4457         const ClutterTransformInfo *info;
4458         gfloat anchor_y;
4459
4460         info = _clutter_actor_get_transform_info_or_defaults (actor);
4461         clutter_anchor_coord_get_units (actor, &info->anchor,
4462                                         NULL,
4463                                         &anchor_y,
4464                                         NULL);
4465         g_value_set_float (value, anchor_y);
4466       }
4467       break;
4468
4469     case PROP_ANCHOR_GRAVITY:
4470       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4471       break;
4472
4473     case PROP_SHOW_ON_SET_PARENT:
4474       g_value_set_boolean (value, priv->show_on_set_parent);
4475       break;
4476
4477     case PROP_TEXT_DIRECTION:
4478       g_value_set_enum (value, priv->text_direction);
4479       break;
4480
4481     case PROP_HAS_POINTER:
4482       g_value_set_boolean (value, priv->has_pointer);
4483       break;
4484
4485     case PROP_LAYOUT_MANAGER:
4486       g_value_set_object (value, priv->layout_manager);
4487       break;
4488
4489     case PROP_X_ALIGN:
4490       {
4491         const ClutterLayoutInfo *info;
4492
4493         info = _clutter_actor_get_layout_info_or_defaults (actor);
4494         g_value_set_enum (value, info->x_align);
4495       }
4496       break;
4497
4498     case PROP_Y_ALIGN:
4499       {
4500         const ClutterLayoutInfo *info;
4501
4502         info = _clutter_actor_get_layout_info_or_defaults (actor);
4503         g_value_set_enum (value, info->y_align);
4504       }
4505       break;
4506
4507     case PROP_MARGIN_TOP:
4508       {
4509         const ClutterLayoutInfo *info;
4510
4511         info = _clutter_actor_get_layout_info_or_defaults (actor);
4512         g_value_set_float (value, info->margin.top);
4513       }
4514       break;
4515
4516     case PROP_MARGIN_BOTTOM:
4517       {
4518         const ClutterLayoutInfo *info;
4519
4520         info = _clutter_actor_get_layout_info_or_defaults (actor);
4521         g_value_set_float (value, info->margin.bottom);
4522       }
4523       break;
4524
4525     case PROP_MARGIN_LEFT:
4526       {
4527         const ClutterLayoutInfo *info;
4528
4529         info = _clutter_actor_get_layout_info_or_defaults (actor);
4530         g_value_set_float (value, info->margin.left);
4531       }
4532       break;
4533
4534     case PROP_MARGIN_RIGHT:
4535       {
4536         const ClutterLayoutInfo *info;
4537
4538         info = _clutter_actor_get_layout_info_or_defaults (actor);
4539         g_value_set_float (value, info->margin.right);
4540       }
4541       break;
4542
4543     case PROP_BACKGROUND_COLOR_SET:
4544       g_value_set_boolean (value, priv->bg_color_set);
4545       break;
4546
4547     case PROP_BACKGROUND_COLOR:
4548       g_value_set_boxed (value, &priv->bg_color);
4549       break;
4550
4551     case PROP_FIRST_CHILD:
4552       g_value_set_object (value, priv->first_child);
4553       break;
4554
4555     case PROP_LAST_CHILD:
4556       g_value_set_object (value, priv->last_child);
4557       break;
4558
4559     default:
4560       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4561       break;
4562     }
4563 }
4564
4565 static void
4566 clutter_actor_dispose (GObject *object)
4567 {
4568   ClutterActor *self = CLUTTER_ACTOR (object);
4569   ClutterActorPrivate *priv = self->priv;
4570
4571   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4572                 priv->id,
4573                 g_type_name (G_OBJECT_TYPE (self)),
4574                 object->ref_count);
4575
4576   g_signal_emit (self, actor_signals[DESTROY], 0);
4577
4578   /* avoid recursing when called from clutter_actor_destroy() */
4579   if (priv->parent != NULL)
4580     {
4581       ClutterActor *parent = priv->parent;
4582
4583       /* go through the Container implementation unless this
4584        * is an internal child and has been marked as such.
4585        *
4586        * removing the actor from its parent will reset the
4587        * realized and mapped states.
4588        */
4589       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4590         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4591       else
4592         clutter_actor_remove_child_internal (parent, self,
4593                                              REMOVE_CHILD_LEGACY_FLAGS);
4594     }
4595
4596   /* parent must be gone at this point */
4597   g_assert (priv->parent == NULL);
4598
4599   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4600     {
4601       /* can't be mapped or realized with no parent */
4602       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4603       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4604     }
4605
4606   g_clear_object (&priv->pango_context);
4607   g_clear_object (&priv->actions);
4608   g_clear_object (&priv->constraints);
4609   g_clear_object (&priv->effects);
4610   g_clear_object (&priv->flatten_effect);
4611
4612   if (priv->layout_manager != NULL)
4613     {
4614       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4615       g_object_unref (priv->layout_manager);
4616       priv->layout_manager = NULL;
4617     }
4618
4619   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4620 }
4621
4622 static void
4623 clutter_actor_finalize (GObject *object)
4624 {
4625   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4626
4627   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4628                 priv->name != NULL ? priv->name : "<none>",
4629                 priv->id,
4630                 g_type_name (G_OBJECT_TYPE (object)));
4631
4632   _clutter_context_release_id (priv->id);
4633
4634   g_free (priv->name);
4635
4636   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4637 }
4638
4639
4640 /**
4641  * clutter_actor_get_accessible:
4642  * @self: a #ClutterActor
4643  *
4644  * Returns the accessible object that describes the actor to an
4645  * assistive technology.
4646  *
4647  * If no class-specific #AtkObject implementation is available for the
4648  * actor instance in question, it will inherit an #AtkObject
4649  * implementation from the first ancestor class for which such an
4650  * implementation is defined.
4651  *
4652  * The documentation of the <ulink
4653  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4654  * library contains more information about accessible objects and
4655  * their uses.
4656  *
4657  * Returns: (transfer none): the #AtkObject associated with @actor
4658  */
4659 AtkObject *
4660 clutter_actor_get_accessible (ClutterActor *self)
4661 {
4662   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4663
4664   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4665 }
4666
4667 static AtkObject *
4668 clutter_actor_real_get_accessible (ClutterActor *actor)
4669 {
4670   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4671 }
4672
4673 static AtkObject *
4674 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4675 {
4676   AtkObject *accessible;
4677
4678   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4679   if (accessible != NULL)
4680     g_object_ref (accessible);
4681
4682   return accessible;
4683 }
4684
4685 static void
4686 atk_implementor_iface_init (AtkImplementorIface *iface)
4687 {
4688   iface->ref_accessible = _clutter_actor_ref_accessible;
4689 }
4690
4691 static gboolean
4692 clutter_actor_update_default_paint_volume (ClutterActor       *self,
4693                                            ClutterPaintVolume *volume)
4694 {
4695   ClutterActorPrivate *priv = self->priv;
4696   gboolean res = FALSE;
4697
4698   /* we start from the allocation */
4699   clutter_paint_volume_set_width (volume,
4700                                   priv->allocation.x2 - priv->allocation.x1);
4701   clutter_paint_volume_set_height (volume,
4702                                    priv->allocation.y2 - priv->allocation.y1);
4703
4704   /* if the actor has a clip set then we have a pretty definite
4705    * size for the paint volume: the actor cannot possibly paint
4706    * outside the clip region.
4707    */
4708   if (priv->clip_to_allocation)
4709     {
4710       /* the allocation has already been set, so we just flip the
4711        * return value
4712        */
4713       res = TRUE;
4714     }
4715   else
4716     {
4717       ClutterActor *child;
4718
4719       if (priv->has_clip &&
4720           priv->clip.width >= 0 &&
4721           priv->clip.height >= 0)
4722         {
4723           ClutterVertex origin;
4724
4725           origin.x = priv->clip.x;
4726           origin.y = priv->clip.y;
4727           origin.z = 0;
4728
4729           clutter_paint_volume_set_origin (volume, &origin);
4730           clutter_paint_volume_set_width (volume, priv->clip.width);
4731           clutter_paint_volume_set_height (volume, priv->clip.height);
4732
4733           res = TRUE;
4734         }
4735
4736       /* if we don't have children we just bail out here... */
4737       if (priv->n_children == 0)
4738         return res;
4739
4740       /* ...but if we have children then we ask for their paint volume in
4741        * our coordinates. if any of our children replies that it doesn't
4742        * have a paint volume, we bail out
4743        */
4744       for (child = priv->first_child;
4745            child != NULL;
4746            child = child->priv->next_sibling)
4747         {
4748           const ClutterPaintVolume *child_volume;
4749
4750           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4751           if (child_volume == NULL)
4752             {
4753               res = FALSE;
4754               break;
4755             }
4756
4757           clutter_paint_volume_union (volume, child_volume);
4758           res = TRUE;
4759         }
4760     }
4761
4762   return res;
4763
4764 }
4765
4766 static gboolean
4767 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4768                                      ClutterPaintVolume *volume)
4769 {
4770   ClutterActorClass *klass;
4771   gboolean res;
4772
4773   klass = CLUTTER_ACTOR_GET_CLASS (self);
4774
4775   /* XXX - this thoroughly sucks, but we don't want to penalize users
4776    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
4777    * redraw. This should go away in 2.0.
4778    */
4779   if (klass->paint == clutter_actor_real_paint &&
4780       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
4781     {
4782       res = TRUE;
4783     }
4784   else
4785     {
4786       /* this is the default return value: we cannot know if a class
4787        * is going to paint outside its allocation, so we take the
4788        * conservative approach.
4789        */
4790       res = FALSE;
4791     }
4792
4793   if (clutter_actor_update_default_paint_volume (self, volume))
4794     return res;
4795
4796   return FALSE;
4797 }
4798
4799 /**
4800  * clutter_actor_get_default_paint_volume:
4801  * @self: a #ClutterActor
4802  *
4803  * Retrieves the default paint volume for @self.
4804  *
4805  * This function provides the same #ClutterPaintVolume that would be
4806  * computed by the default implementation inside #ClutterActor of the
4807  * #ClutterActorClass.get_paint_volume() virtual function.
4808  *
4809  * This function should only be used by #ClutterActor subclasses that
4810  * cannot chain up to the parent implementation when computing their
4811  * paint volume.
4812  *
4813  * Return value: (transfer none): a pointer to the default
4814  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
4815  *   the actor could not compute a valid paint volume. The returned value
4816  *   is not guaranteed to be stable across multiple frames, so if you
4817  *   want to retain it, you will need to copy it using
4818  *   clutter_paint_volume_copy().
4819  *
4820  * Since: 1.10
4821  */
4822 const ClutterPaintVolume *
4823 clutter_actor_get_default_paint_volume (ClutterActor *self)
4824 {
4825   ClutterPaintVolume volume;
4826   ClutterPaintVolume *res;
4827
4828   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4829
4830   res = NULL;
4831   _clutter_paint_volume_init_static (&volume, self);
4832   if (clutter_actor_update_default_paint_volume (self, &volume))
4833     {
4834       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
4835
4836       if (stage != NULL)
4837         {
4838           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
4839           _clutter_paint_volume_copy_static (&volume, res);
4840         }
4841     }
4842
4843   clutter_paint_volume_free (&volume);
4844
4845   return res;
4846 }
4847
4848 static gboolean
4849 clutter_actor_real_has_overlaps (ClutterActor *self)
4850 {
4851   /* By default we'll assume that all actors need an offscreen redirect to get
4852    * the correct opacity. Actors such as ClutterTexture that would never need
4853    * an offscreen redirect can override this to return FALSE. */
4854   return TRUE;
4855 }
4856
4857 static void
4858 clutter_actor_real_destroy (ClutterActor *actor)
4859 {
4860   ClutterActorIter iter;
4861
4862   clutter_actor_iter_init (&iter, actor);
4863   while (clutter_actor_iter_next (&iter, NULL))
4864     clutter_actor_iter_destroy (&iter);
4865 }
4866
4867 static GObject *
4868 clutter_actor_constructor (GType gtype,
4869                            guint n_props,
4870                            GObjectConstructParam *props)
4871 {
4872   GObjectClass *gobject_class;
4873   ClutterActor *self;
4874   GObject *retval;
4875
4876   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
4877   retval = gobject_class->constructor (gtype, n_props, props);
4878   self = CLUTTER_ACTOR (retval);
4879
4880   if (self->priv->layout_manager == NULL)
4881     {
4882       ClutterLayoutManager *default_layout;
4883
4884       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
4885
4886       default_layout = clutter_fixed_layout_new ();
4887       clutter_actor_set_layout_manager (self, default_layout);
4888     }
4889
4890   return retval;
4891 }
4892
4893 static void
4894 clutter_actor_class_init (ClutterActorClass *klass)
4895 {
4896   GObjectClass *object_class = G_OBJECT_CLASS (klass);
4897
4898   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
4899   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
4900   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
4901
4902   object_class->constructor = clutter_actor_constructor;
4903   object_class->set_property = clutter_actor_set_property;
4904   object_class->get_property = clutter_actor_get_property;
4905   object_class->dispose = clutter_actor_dispose;
4906   object_class->finalize = clutter_actor_finalize;
4907
4908   klass->show = clutter_actor_real_show;
4909   klass->show_all = clutter_actor_show;
4910   klass->hide = clutter_actor_real_hide;
4911   klass->hide_all = clutter_actor_hide;
4912   klass->map = clutter_actor_real_map;
4913   klass->unmap = clutter_actor_real_unmap;
4914   klass->unrealize = clutter_actor_real_unrealize;
4915   klass->pick = clutter_actor_real_pick;
4916   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
4917   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4918   klass->allocate = clutter_actor_real_allocate;
4919   klass->queue_redraw = clutter_actor_real_queue_redraw;
4920   klass->queue_relayout = clutter_actor_real_queue_relayout;
4921   klass->apply_transform = clutter_actor_real_apply_transform;
4922   klass->get_accessible = clutter_actor_real_get_accessible;
4923   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
4924   klass->has_overlaps = clutter_actor_real_has_overlaps;
4925   klass->paint = clutter_actor_real_paint;
4926   klass->destroy = clutter_actor_real_destroy;
4927
4928   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
4929
4930   /**
4931    * ClutterActor:x:
4932    *
4933    * X coordinate of the actor in pixels. If written, forces a fixed
4934    * position for the actor. If read, returns the fixed position if any,
4935    * otherwise the allocation if available, otherwise 0.
4936    */
4937   obj_props[PROP_X] =
4938     g_param_spec_float ("x",
4939                         P_("X coordinate"),
4940                         P_("X coordinate of the actor"),
4941                         -G_MAXFLOAT, G_MAXFLOAT,
4942                         0.0,
4943                         CLUTTER_PARAM_READWRITE);
4944
4945   /**
4946    * ClutterActor:y:
4947    *
4948    * Y coordinate of the actor in pixels. If written, forces a fixed
4949    * position for the actor.  If read, returns the fixed position if
4950    * any, otherwise the allocation if available, otherwise 0.
4951    */
4952   obj_props[PROP_Y] =
4953     g_param_spec_float ("y",
4954                         P_("Y coordinate"),
4955                         P_("Y coordinate of the actor"),
4956                         -G_MAXFLOAT, G_MAXFLOAT,
4957                         0.0,
4958                         CLUTTER_PARAM_READWRITE);
4959
4960   /**
4961    * ClutterActor:width:
4962    *
4963    * Width of the actor (in pixels). If written, forces the minimum and
4964    * natural size request of the actor to the given width. If read, returns
4965    * the allocated width if available, otherwise the width request.
4966    */
4967   obj_props[PROP_WIDTH] =
4968     g_param_spec_float ("width",
4969                         P_("Width"),
4970                         P_("Width of the actor"),
4971                         0.0, G_MAXFLOAT,
4972                         0.0,
4973                         CLUTTER_PARAM_READWRITE);
4974
4975   /**
4976    * ClutterActor:height:
4977    *
4978    * Height of the actor (in pixels).  If written, forces the minimum and
4979    * natural size request of the actor to the given height. If read, returns
4980    * the allocated height if available, otherwise the height request.
4981    */
4982   obj_props[PROP_HEIGHT] =
4983     g_param_spec_float ("height",
4984                         P_("Height"),
4985                         P_("Height of the actor"),
4986                         0.0, G_MAXFLOAT,
4987                         0.0,
4988                         CLUTTER_PARAM_READWRITE);
4989
4990   /**
4991    * ClutterActor:fixed-x:
4992    *
4993    * The fixed X position of the actor in pixels.
4994    *
4995    * Writing this property sets #ClutterActor:fixed-position-set
4996    * property as well, as a side effect
4997    *
4998    * Since: 0.8
4999    */
5000   obj_props[PROP_FIXED_X] =
5001     g_param_spec_float ("fixed-x",
5002                         P_("Fixed X"),
5003                         P_("Forced X position of the actor"),
5004                         -G_MAXFLOAT, G_MAXFLOAT,
5005                         0.0,
5006                         CLUTTER_PARAM_READWRITE);
5007
5008   /**
5009    * ClutterActor:fixed-y:
5010    *
5011    * The fixed Y position of the actor in pixels.
5012    *
5013    * Writing this property sets the #ClutterActor:fixed-position-set
5014    * property as well, as a side effect
5015    *
5016    * Since: 0.8
5017    */
5018   obj_props[PROP_FIXED_Y] =
5019     g_param_spec_float ("fixed-y",
5020                         P_("Fixed Y"),
5021                         P_("Forced Y position of the actor"),
5022                         -G_MAXFLOAT, G_MAXFLOAT,
5023                         0,
5024                         CLUTTER_PARAM_READWRITE);
5025
5026   /**
5027    * ClutterActor:fixed-position-set:
5028    *
5029    * This flag controls whether the #ClutterActor:fixed-x and
5030    * #ClutterActor:fixed-y properties are used
5031    *
5032    * Since: 0.8
5033    */
5034   obj_props[PROP_FIXED_POSITION_SET] =
5035     g_param_spec_boolean ("fixed-position-set",
5036                           P_("Fixed position set"),
5037                           P_("Whether to use fixed positioning for the actor"),
5038                           FALSE,
5039                           CLUTTER_PARAM_READWRITE);
5040
5041   /**
5042    * ClutterActor:min-width:
5043    *
5044    * A forced minimum width request for the actor, in pixels
5045    *
5046    * Writing this property sets the #ClutterActor:min-width-set property
5047    * as well, as a side effect.
5048    *
5049    *This property overrides the usual width request of the actor.
5050    *
5051    * Since: 0.8
5052    */
5053   obj_props[PROP_MIN_WIDTH] =
5054     g_param_spec_float ("min-width",
5055                         P_("Min Width"),
5056                         P_("Forced minimum width request for the actor"),
5057                         0.0, G_MAXFLOAT,
5058                         0.0,
5059                         CLUTTER_PARAM_READWRITE);
5060
5061   /**
5062    * ClutterActor:min-height:
5063    *
5064    * A forced minimum height request for the actor, in pixels
5065    *
5066    * Writing this property sets the #ClutterActor:min-height-set property
5067    * as well, as a side effect. This property overrides the usual height
5068    * request of the actor.
5069    *
5070    * Since: 0.8
5071    */
5072   obj_props[PROP_MIN_HEIGHT] =
5073     g_param_spec_float ("min-height",
5074                         P_("Min Height"),
5075                         P_("Forced minimum height request for the actor"),
5076                         0.0, G_MAXFLOAT,
5077                         0.0,
5078                         CLUTTER_PARAM_READWRITE);
5079
5080   /**
5081    * ClutterActor:natural-width:
5082    *
5083    * A forced natural width request for the actor, in pixels
5084    *
5085    * Writing this property sets the #ClutterActor:natural-width-set
5086    * property as well, as a side effect. This property overrides the
5087    * usual width request of the actor
5088    *
5089    * Since: 0.8
5090    */
5091   obj_props[PROP_NATURAL_WIDTH] =
5092     g_param_spec_float ("natural-width",
5093                         P_("Natural Width"),
5094                         P_("Forced natural width request for the actor"),
5095                         0.0, G_MAXFLOAT,
5096                         0.0,
5097                         CLUTTER_PARAM_READWRITE);
5098
5099   /**
5100    * ClutterActor:natural-height:
5101    *
5102    * A forced natural height request for the actor, in pixels
5103    *
5104    * Writing this property sets the #ClutterActor:natural-height-set
5105    * property as well, as a side effect. This property overrides the
5106    * usual height request of the actor
5107    *
5108    * Since: 0.8
5109    */
5110   obj_props[PROP_NATURAL_HEIGHT] =
5111     g_param_spec_float ("natural-height",
5112                         P_("Natural Height"),
5113                         P_("Forced natural height request for the actor"),
5114                         0.0, G_MAXFLOAT,
5115                         0.0,
5116                         CLUTTER_PARAM_READWRITE);
5117
5118   /**
5119    * ClutterActor:min-width-set:
5120    *
5121    * This flag controls whether the #ClutterActor:min-width property
5122    * is used
5123    *
5124    * Since: 0.8
5125    */
5126   obj_props[PROP_MIN_WIDTH_SET] =
5127     g_param_spec_boolean ("min-width-set",
5128                           P_("Minimum width set"),
5129                           P_("Whether to use the min-width property"),
5130                           FALSE,
5131                           CLUTTER_PARAM_READWRITE);
5132
5133   /**
5134    * ClutterActor:min-height-set:
5135    *
5136    * This flag controls whether the #ClutterActor:min-height property
5137    * is used
5138    *
5139    * Since: 0.8
5140    */
5141   obj_props[PROP_MIN_HEIGHT_SET] =
5142     g_param_spec_boolean ("min-height-set",
5143                           P_("Minimum height set"),
5144                           P_("Whether to use the min-height property"),
5145                           FALSE,
5146                           CLUTTER_PARAM_READWRITE);
5147
5148   /**
5149    * ClutterActor:natural-width-set:
5150    *
5151    * This flag controls whether the #ClutterActor:natural-width property
5152    * is used
5153    *
5154    * Since: 0.8
5155    */
5156   obj_props[PROP_NATURAL_WIDTH_SET] =
5157     g_param_spec_boolean ("natural-width-set",
5158                           P_("Natural width set"),
5159                           P_("Whether to use the natural-width property"),
5160                           FALSE,
5161                           CLUTTER_PARAM_READWRITE);
5162
5163   /**
5164    * ClutterActor:natural-height-set:
5165    *
5166    * This flag controls whether the #ClutterActor:natural-height property
5167    * is used
5168    *
5169    * Since: 0.8
5170    */
5171   obj_props[PROP_NATURAL_HEIGHT_SET] =
5172     g_param_spec_boolean ("natural-height-set",
5173                           P_("Natural height set"),
5174                           P_("Whether to use the natural-height property"),
5175                           FALSE,
5176                           CLUTTER_PARAM_READWRITE);
5177
5178   /**
5179    * ClutterActor:allocation:
5180    *
5181    * The allocation for the actor, in pixels
5182    *
5183    * This is property is read-only, but you might monitor it to know when an
5184    * actor moves or resizes
5185    *
5186    * Since: 0.8
5187    */
5188   obj_props[PROP_ALLOCATION] =
5189     g_param_spec_boxed ("allocation",
5190                         P_("Allocation"),
5191                         P_("The actor's allocation"),
5192                         CLUTTER_TYPE_ACTOR_BOX,
5193                         CLUTTER_PARAM_READABLE);
5194
5195   /**
5196    * ClutterActor:request-mode:
5197    *
5198    * Request mode for the #ClutterActor. The request mode determines the
5199    * type of geometry management used by the actor, either height for width
5200    * (the default) or width for height.
5201    *
5202    * For actors implementing height for width, the parent container should get
5203    * the preferred width first, and then the preferred height for that width.
5204    *
5205    * For actors implementing width for height, the parent container should get
5206    * the preferred height first, and then the preferred width for that height.
5207    *
5208    * For instance:
5209    *
5210    * |[
5211    *   ClutterRequestMode mode;
5212    *   gfloat natural_width, min_width;
5213    *   gfloat natural_height, min_height;
5214    *
5215    *   mode = clutter_actor_get_request_mode (child);
5216    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5217    *     {
5218    *       clutter_actor_get_preferred_width (child, -1,
5219    *                                          &amp;min_width,
5220    *                                          &amp;natural_width);
5221    *       clutter_actor_get_preferred_height (child, natural_width,
5222    *                                           &amp;min_height,
5223    *                                           &amp;natural_height);
5224    *     }
5225    *   else
5226    *     {
5227    *       clutter_actor_get_preferred_height (child, -1,
5228    *                                           &amp;min_height,
5229    *                                           &amp;natural_height);
5230    *       clutter_actor_get_preferred_width (child, natural_height,
5231    *                                          &amp;min_width,
5232    *                                          &amp;natural_width);
5233    *     }
5234    * ]|
5235    *
5236    * will retrieve the minimum and natural width and height depending on the
5237    * preferred request mode of the #ClutterActor "child".
5238    *
5239    * The clutter_actor_get_preferred_size() function will implement this
5240    * check for you.
5241    *
5242    * Since: 0.8
5243    */
5244   obj_props[PROP_REQUEST_MODE] =
5245     g_param_spec_enum ("request-mode",
5246                        P_("Request Mode"),
5247                        P_("The actor's request mode"),
5248                        CLUTTER_TYPE_REQUEST_MODE,
5249                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5250                        CLUTTER_PARAM_READWRITE);
5251
5252   /**
5253    * ClutterActor:depth:
5254    *
5255    * The position of the actor on the Z axis
5256    *
5257    * Since: 0.6
5258    */
5259   obj_props[PROP_DEPTH] =
5260     g_param_spec_float ("depth",
5261                         P_("Depth"),
5262                         P_("Position on the Z axis"),
5263                         -G_MAXFLOAT, G_MAXFLOAT,
5264                         0.0,
5265                         CLUTTER_PARAM_READWRITE);
5266
5267   /**
5268    * ClutterActor:opacity:
5269    *
5270    * Opacity of an actor, between 0 (fully transparent) and
5271    * 255 (fully opaque)
5272    */
5273   obj_props[PROP_OPACITY] =
5274     g_param_spec_uint ("opacity",
5275                        P_("Opacity"),
5276                        P_("Opacity of an actor"),
5277                        0, 255,
5278                        255,
5279                        CLUTTER_PARAM_READWRITE);
5280
5281   /**
5282    * ClutterActor:offscreen-redirect:
5283    *
5284    * Determines the conditions in which the actor will be redirected
5285    * to an offscreen framebuffer while being painted. For example this
5286    * can be used to cache an actor in a framebuffer or for improved
5287    * handling of transparent actors. See
5288    * clutter_actor_set_offscreen_redirect() for details.
5289    *
5290    * Since: 1.8
5291    */
5292   obj_props[PROP_OFFSCREEN_REDIRECT] =
5293     g_param_spec_flags ("offscreen-redirect",
5294                         P_("Offscreen redirect"),
5295                         P_("Flags controlling when to flatten the actor into a single image"),
5296                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5297                         0,
5298                         CLUTTER_PARAM_READWRITE);
5299
5300   /**
5301    * ClutterActor:visible:
5302    *
5303    * Whether the actor is set to be visible or not
5304    *
5305    * See also #ClutterActor:mapped
5306    */
5307   obj_props[PROP_VISIBLE] =
5308     g_param_spec_boolean ("visible",
5309                           P_("Visible"),
5310                           P_("Whether the actor is visible or not"),
5311                           FALSE,
5312                           CLUTTER_PARAM_READWRITE);
5313
5314   /**
5315    * ClutterActor:mapped:
5316    *
5317    * Whether the actor is mapped (will be painted when the stage
5318    * to which it belongs is mapped)
5319    *
5320    * Since: 1.0
5321    */
5322   obj_props[PROP_MAPPED] =
5323     g_param_spec_boolean ("mapped",
5324                           P_("Mapped"),
5325                           P_("Whether the actor will be painted"),
5326                           FALSE,
5327                           CLUTTER_PARAM_READABLE);
5328
5329   /**
5330    * ClutterActor:realized:
5331    *
5332    * Whether the actor has been realized
5333    *
5334    * Since: 1.0
5335    */
5336   obj_props[PROP_REALIZED] =
5337     g_param_spec_boolean ("realized",
5338                           P_("Realized"),
5339                           P_("Whether the actor has been realized"),
5340                           FALSE,
5341                           CLUTTER_PARAM_READABLE);
5342
5343   /**
5344    * ClutterActor:reactive:
5345    *
5346    * Whether the actor is reactive to events or not
5347    *
5348    * Only reactive actors will emit event-related signals
5349    *
5350    * Since: 0.6
5351    */
5352   obj_props[PROP_REACTIVE] =
5353     g_param_spec_boolean ("reactive",
5354                           P_("Reactive"),
5355                           P_("Whether the actor is reactive to events"),
5356                           FALSE,
5357                           CLUTTER_PARAM_READWRITE);
5358
5359   /**
5360    * ClutterActor:has-clip:
5361    *
5362    * Whether the actor has the #ClutterActor:clip property set or not
5363    */
5364   obj_props[PROP_HAS_CLIP] =
5365     g_param_spec_boolean ("has-clip",
5366                           P_("Has Clip"),
5367                           P_("Whether the actor has a clip set"),
5368                           FALSE,
5369                           CLUTTER_PARAM_READABLE);
5370
5371   /**
5372    * ClutterActor:clip:
5373    *
5374    * The clip region for the actor, in actor-relative coordinates
5375    *
5376    * Every part of the actor outside the clip region will not be
5377    * painted
5378    */
5379   obj_props[PROP_CLIP] =
5380     g_param_spec_boxed ("clip",
5381                         P_("Clip"),
5382                         P_("The clip region for the actor"),
5383                         CLUTTER_TYPE_GEOMETRY,
5384                         CLUTTER_PARAM_READWRITE);
5385
5386   /**
5387    * ClutterActor:name:
5388    *
5389    * The name of the actor
5390    *
5391    * Since: 0.2
5392    */
5393   obj_props[PROP_NAME] =
5394     g_param_spec_string ("name",
5395                          P_("Name"),
5396                          P_("Name of the actor"),
5397                          NULL,
5398                          CLUTTER_PARAM_READWRITE);
5399
5400   /**
5401    * ClutterActor:scale-x:
5402    *
5403    * The horizontal scale of the actor
5404    *
5405    * Since: 0.6
5406    */
5407   obj_props[PROP_SCALE_X] =
5408     g_param_spec_double ("scale-x",
5409                          P_("Scale X"),
5410                          P_("Scale factor on the X axis"),
5411                          0.0, G_MAXDOUBLE,
5412                          1.0,
5413                          CLUTTER_PARAM_READWRITE);
5414
5415   /**
5416    * ClutterActor:scale-y:
5417    *
5418    * The vertical scale of the actor
5419    *
5420    * Since: 0.6
5421    */
5422   obj_props[PROP_SCALE_Y] =
5423     g_param_spec_double ("scale-y",
5424                          P_("Scale Y"),
5425                          P_("Scale factor on the Y axis"),
5426                          0.0, G_MAXDOUBLE,
5427                          1.0,
5428                          CLUTTER_PARAM_READWRITE);
5429
5430   /**
5431    * ClutterActor:scale-center-x:
5432    *
5433    * The horizontal center point for scaling
5434    *
5435    * Since: 1.0
5436    */
5437   obj_props[PROP_SCALE_CENTER_X] =
5438     g_param_spec_float ("scale-center-x",
5439                         P_("Scale Center X"),
5440                         P_("Horizontal scale center"),
5441                         -G_MAXFLOAT, G_MAXFLOAT,
5442                         0.0,
5443                         CLUTTER_PARAM_READWRITE);
5444
5445   /**
5446    * ClutterActor:scale-center-y:
5447    *
5448    * The vertical center point for scaling
5449    *
5450    * Since: 1.0
5451    */
5452   obj_props[PROP_SCALE_CENTER_Y] =
5453     g_param_spec_float ("scale-center-y",
5454                         P_("Scale Center Y"),
5455                         P_("Vertical scale center"),
5456                         -G_MAXFLOAT, G_MAXFLOAT,
5457                         0.0,
5458                         CLUTTER_PARAM_READWRITE);
5459
5460   /**
5461    * ClutterActor:scale-gravity:
5462    *
5463    * The center point for scaling expressed as a #ClutterGravity
5464    *
5465    * Since: 1.0
5466    */
5467   obj_props[PROP_SCALE_GRAVITY] =
5468     g_param_spec_enum ("scale-gravity",
5469                        P_("Scale Gravity"),
5470                        P_("The center of scaling"),
5471                        CLUTTER_TYPE_GRAVITY,
5472                        CLUTTER_GRAVITY_NONE,
5473                        CLUTTER_PARAM_READWRITE);
5474
5475   /**
5476    * ClutterActor:rotation-angle-x:
5477    *
5478    * The rotation angle on the X axis
5479    *
5480    * Since: 0.6
5481    */
5482   obj_props[PROP_ROTATION_ANGLE_X] =
5483     g_param_spec_double ("rotation-angle-x",
5484                          P_("Rotation Angle X"),
5485                          P_("The rotation angle on the X axis"),
5486                          -G_MAXDOUBLE, G_MAXDOUBLE,
5487                          0.0,
5488                          CLUTTER_PARAM_READWRITE);
5489
5490   /**
5491    * ClutterActor:rotation-angle-y:
5492    *
5493    * The rotation angle on the Y axis
5494    *
5495    * Since: 0.6
5496    */
5497   obj_props[PROP_ROTATION_ANGLE_Y] =
5498     g_param_spec_double ("rotation-angle-y",
5499                          P_("Rotation Angle Y"),
5500                          P_("The rotation angle on the Y axis"),
5501                          -G_MAXDOUBLE, G_MAXDOUBLE,
5502                          0.0,
5503                          CLUTTER_PARAM_READWRITE);
5504
5505   /**
5506    * ClutterActor:rotation-angle-z:
5507    *
5508    * The rotation angle on the Z axis
5509    *
5510    * Since: 0.6
5511    */
5512   obj_props[PROP_ROTATION_ANGLE_Z] =
5513     g_param_spec_double ("rotation-angle-z",
5514                          P_("Rotation Angle Z"),
5515                          P_("The rotation angle on the Z axis"),
5516                          -G_MAXDOUBLE, G_MAXDOUBLE,
5517                          0.0,
5518                          CLUTTER_PARAM_READWRITE);
5519
5520   /**
5521    * ClutterActor:rotation-center-x:
5522    *
5523    * The rotation center on the X axis.
5524    *
5525    * Since: 0.6
5526    */
5527   obj_props[PROP_ROTATION_CENTER_X] =
5528     g_param_spec_boxed ("rotation-center-x",
5529                         P_("Rotation Center X"),
5530                         P_("The rotation center on the X axis"),
5531                         CLUTTER_TYPE_VERTEX,
5532                         CLUTTER_PARAM_READWRITE);
5533
5534   /**
5535    * ClutterActor:rotation-center-y:
5536    *
5537    * The rotation center on the Y axis.
5538    *
5539    * Since: 0.6
5540    */
5541   obj_props[PROP_ROTATION_CENTER_Y] =
5542     g_param_spec_boxed ("rotation-center-y",
5543                         P_("Rotation Center Y"),
5544                         P_("The rotation center on the Y axis"),
5545                         CLUTTER_TYPE_VERTEX,
5546                         CLUTTER_PARAM_READWRITE);
5547
5548   /**
5549    * ClutterActor:rotation-center-z:
5550    *
5551    * The rotation center on the Z axis.
5552    *
5553    * Since: 0.6
5554    */
5555   obj_props[PROP_ROTATION_CENTER_Z] =
5556     g_param_spec_boxed ("rotation-center-z",
5557                         P_("Rotation Center Z"),
5558                         P_("The rotation center on the Z axis"),
5559                         CLUTTER_TYPE_VERTEX,
5560                         CLUTTER_PARAM_READWRITE);
5561
5562   /**
5563    * ClutterActor:rotation-center-z-gravity:
5564    *
5565    * The rotation center on the Z axis expressed as a #ClutterGravity.
5566    *
5567    * Since: 1.0
5568    */
5569   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5570     g_param_spec_enum ("rotation-center-z-gravity",
5571                        P_("Rotation Center Z Gravity"),
5572                        P_("Center point for rotation around the Z axis"),
5573                        CLUTTER_TYPE_GRAVITY,
5574                        CLUTTER_GRAVITY_NONE,
5575                        CLUTTER_PARAM_READWRITE);
5576
5577   /**
5578    * ClutterActor:anchor-x:
5579    *
5580    * The X coordinate of an actor's anchor point, relative to
5581    * the actor coordinate space, in pixels
5582    *
5583    * Since: 0.8
5584    */
5585   obj_props[PROP_ANCHOR_X] =
5586     g_param_spec_float ("anchor-x",
5587                         P_("Anchor X"),
5588                         P_("X coordinate of the anchor point"),
5589                         -G_MAXFLOAT, G_MAXFLOAT,
5590                         0,
5591                         CLUTTER_PARAM_READWRITE);
5592
5593   /**
5594    * ClutterActor:anchor-y:
5595    *
5596    * The Y coordinate of an actor's anchor point, relative to
5597    * the actor coordinate space, in pixels
5598    *
5599    * Since: 0.8
5600    */
5601   obj_props[PROP_ANCHOR_Y] =
5602     g_param_spec_float ("anchor-y",
5603                         P_("Anchor Y"),
5604                         P_("Y coordinate of the anchor point"),
5605                         -G_MAXFLOAT, G_MAXFLOAT,
5606                         0,
5607                         CLUTTER_PARAM_READWRITE);
5608
5609   /**
5610    * ClutterActor:anchor-gravity:
5611    *
5612    * The anchor point expressed as a #ClutterGravity
5613    *
5614    * Since: 1.0
5615    */
5616   obj_props[PROP_ANCHOR_GRAVITY] =
5617     g_param_spec_enum ("anchor-gravity",
5618                        P_("Anchor Gravity"),
5619                        P_("The anchor point as a ClutterGravity"),
5620                        CLUTTER_TYPE_GRAVITY,
5621                        CLUTTER_GRAVITY_NONE,
5622                        CLUTTER_PARAM_READWRITE);
5623
5624   /**
5625    * ClutterActor:show-on-set-parent:
5626    *
5627    * If %TRUE, the actor is automatically shown when parented.
5628    *
5629    * Calling clutter_actor_hide() on an actor which has not been
5630    * parented will set this property to %FALSE as a side effect.
5631    *
5632    * Since: 0.8
5633    */
5634   obj_props[PROP_SHOW_ON_SET_PARENT] =
5635     g_param_spec_boolean ("show-on-set-parent",
5636                           P_("Show on set parent"),
5637                           P_("Whether the actor is shown when parented"),
5638                           TRUE,
5639                           CLUTTER_PARAM_READWRITE);
5640
5641   /**
5642    * ClutterActor:clip-to-allocation:
5643    *
5644    * Whether the clip region should track the allocated area
5645    * of the actor.
5646    *
5647    * This property is ignored if a clip area has been explicitly
5648    * set using clutter_actor_set_clip().
5649    *
5650    * Since: 1.0
5651    */
5652   obj_props[PROP_CLIP_TO_ALLOCATION] =
5653     g_param_spec_boolean ("clip-to-allocation",
5654                           P_("Clip to Allocation"),
5655                           P_("Sets the clip region to track the actor's allocation"),
5656                           FALSE,
5657                           CLUTTER_PARAM_READWRITE);
5658
5659   /**
5660    * ClutterActor:text-direction:
5661    *
5662    * The direction of the text inside a #ClutterActor.
5663    *
5664    * Since: 1.0
5665    */
5666   obj_props[PROP_TEXT_DIRECTION] =
5667     g_param_spec_enum ("text-direction",
5668                        P_("Text Direction"),
5669                        P_("Direction of the text"),
5670                        CLUTTER_TYPE_TEXT_DIRECTION,
5671                        CLUTTER_TEXT_DIRECTION_LTR,
5672                        CLUTTER_PARAM_READWRITE);
5673
5674   /**
5675    * ClutterActor:has-pointer:
5676    *
5677    * Whether the actor contains the pointer of a #ClutterInputDevice
5678    * or not.
5679    *
5680    * Since: 1.2
5681    */
5682   obj_props[PROP_HAS_POINTER] =
5683     g_param_spec_boolean ("has-pointer",
5684                           P_("Has Pointer"),
5685                           P_("Whether the actor contains the pointer of an input device"),
5686                           FALSE,
5687                           CLUTTER_PARAM_READABLE);
5688
5689   /**
5690    * ClutterActor:actions:
5691    *
5692    * Adds a #ClutterAction to the actor
5693    *
5694    * Since: 1.4
5695    */
5696   obj_props[PROP_ACTIONS] =
5697     g_param_spec_object ("actions",
5698                          P_("Actions"),
5699                          P_("Adds an action to the actor"),
5700                          CLUTTER_TYPE_ACTION,
5701                          CLUTTER_PARAM_WRITABLE);
5702
5703   /**
5704    * ClutterActor:constraints:
5705    *
5706    * Adds a #ClutterConstraint to the actor
5707    *
5708    * Since: 1.4
5709    */
5710   obj_props[PROP_CONSTRAINTS] =
5711     g_param_spec_object ("constraints",
5712                          P_("Constraints"),
5713                          P_("Adds a constraint to the actor"),
5714                          CLUTTER_TYPE_CONSTRAINT,
5715                          CLUTTER_PARAM_WRITABLE);
5716
5717   /**
5718    * ClutterActor:effect:
5719    *
5720    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5721    *
5722    * Since: 1.4
5723    */
5724   obj_props[PROP_EFFECT] =
5725     g_param_spec_object ("effect",
5726                          P_("Effect"),
5727                          P_("Add an effect to be applied on the actor"),
5728                          CLUTTER_TYPE_EFFECT,
5729                          CLUTTER_PARAM_WRITABLE);
5730
5731   /**
5732    * ClutterActor:layout-manager:
5733    *
5734    * A delegate object for controlling the layout of the children of
5735    * an actor.
5736    *
5737    * Since: 1.10
5738    */
5739   obj_props[PROP_LAYOUT_MANAGER] =
5740     g_param_spec_object ("layout-manager",
5741                          P_("Layout Manager"),
5742                          P_("The object controlling the layout of an actor's children"),
5743                          CLUTTER_TYPE_LAYOUT_MANAGER,
5744                          CLUTTER_PARAM_READWRITE);
5745
5746
5747   /**
5748    * ClutterActor:x-align:
5749    *
5750    * The alignment of an actor on the X axis, if the actor has been given
5751    * extra space for its allocation.
5752    *
5753    * Since: 1.10
5754    */
5755   obj_props[PROP_X_ALIGN] =
5756     g_param_spec_enum ("x-align",
5757                        P_("X Alignment"),
5758                        P_("The alignment of the actor on the X axis within its allocation"),
5759                        CLUTTER_TYPE_ACTOR_ALIGN,
5760                        CLUTTER_ACTOR_ALIGN_FILL,
5761                        CLUTTER_PARAM_READWRITE);
5762
5763   /**
5764    * ClutterActor:y-align:
5765    *
5766    * The alignment of an actor on the Y axis, if the actor has been given
5767    * extra space for its allocation.
5768    *
5769    * Since: 1.10
5770    */
5771   obj_props[PROP_Y_ALIGN] =
5772     g_param_spec_enum ("y-align",
5773                        P_("Y Alignment"),
5774                        P_("The alignment of the actor on the Y axis within its allocation"),
5775                        CLUTTER_TYPE_ACTOR_ALIGN,
5776                        CLUTTER_ACTOR_ALIGN_FILL,
5777                        CLUTTER_PARAM_READWRITE);
5778
5779   /**
5780    * ClutterActor:margin-top:
5781    *
5782    * The margin (in pixels) from the top of the actor.
5783    *
5784    * This property adds a margin to the actor's preferred size; the margin
5785    * will be automatically taken into account when allocating the actor.
5786    *
5787    * Since: 1.10
5788    */
5789   obj_props[PROP_MARGIN_TOP] =
5790     g_param_spec_float ("margin-top",
5791                         P_("Margin Top"),
5792                         P_("Extra space at the top"),
5793                         0.0, G_MAXFLOAT,
5794                         0.0,
5795                         CLUTTER_PARAM_READWRITE);
5796
5797   /**
5798    * ClutterActor:margin-bottom:
5799    *
5800    * The margin (in pixels) from the bottom of the actor.
5801    *
5802    * This property adds a margin to the actor's preferred size; the margin
5803    * will be automatically taken into account when allocating the actor.
5804    *
5805    * Since: 1.10
5806    */
5807   obj_props[PROP_MARGIN_BOTTOM] =
5808     g_param_spec_float ("margin-bottom",
5809                         P_("Margin Bottom"),
5810                         P_("Extra space at the bottom"),
5811                         0.0, G_MAXFLOAT,
5812                         0.0,
5813                         CLUTTER_PARAM_READWRITE);
5814
5815   /**
5816    * ClutterActor:margin-left:
5817    *
5818    * The margin (in pixels) from the left of the actor.
5819    *
5820    * This property adds a margin to the actor's preferred size; the margin
5821    * will be automatically taken into account when allocating the actor.
5822    *
5823    * Since: 1.10
5824    */
5825   obj_props[PROP_MARGIN_LEFT] =
5826     g_param_spec_float ("margin-left",
5827                         P_("Margin Left"),
5828                         P_("Extra space at the left"),
5829                         0.0, G_MAXFLOAT,
5830                         0.0,
5831                         CLUTTER_PARAM_READWRITE);
5832
5833   /**
5834    * ClutterActor:margin-right:
5835    *
5836    * The margin (in pixels) from the right of the actor.
5837    *
5838    * This property adds a margin to the actor's preferred size; the margin
5839    * will be automatically taken into account when allocating the actor.
5840    *
5841    * Since: 1.10
5842    */
5843   obj_props[PROP_MARGIN_RIGHT] =
5844     g_param_spec_float ("margin-right",
5845                         P_("Margin Right"),
5846                         P_("Extra space at the right"),
5847                         0.0, G_MAXFLOAT,
5848                         0.0,
5849                         CLUTTER_PARAM_READWRITE);
5850
5851   /**
5852    * ClutterActor:background-color-set:
5853    *
5854    * Whether the #ClutterActor:background-color property has been set.
5855    *
5856    * Since: 1.10
5857    */
5858   obj_props[PROP_BACKGROUND_COLOR_SET] =
5859     g_param_spec_boolean ("background-color-set",
5860                           P_("Background Color Set"),
5861                           P_("Whether the background color is set"),
5862                           FALSE,
5863                           CLUTTER_PARAM_READABLE);
5864
5865   /**
5866    * ClutterActor:background-color:
5867    *
5868    * Paints a solid fill of the actor's allocation using the specified
5869    * color.
5870    *
5871    * Since: 1.10
5872    */
5873   obj_props[PROP_BACKGROUND_COLOR] =
5874     clutter_param_spec_color ("background-color",
5875                               P_("Background color"),
5876                               P_("The actor's background color"),
5877                               CLUTTER_COLOR_Transparent,
5878                               CLUTTER_PARAM_READWRITE);
5879
5880   /**
5881    * ClutterActor:first-child:
5882    *
5883    * The actor's first child.
5884    *
5885    * Since: 1.10
5886    */
5887   obj_props[PROP_FIRST_CHILD] =
5888     g_param_spec_object ("first-child",
5889                          P_("First Child"),
5890                          P_("The actor's first child"),
5891                          CLUTTER_TYPE_ACTOR,
5892                          CLUTTER_PARAM_READABLE);
5893
5894   /**
5895    * ClutterActor:last-child:
5896    *
5897    * The actor's last child.
5898    *
5899    * Since: 1.10
5900    */
5901   obj_props[PROP_LAST_CHILD] =
5902     g_param_spec_object ("last-child",
5903                          P_("Last Child"),
5904                          P_("The actor's last child"),
5905                          CLUTTER_TYPE_ACTOR,
5906                          CLUTTER_PARAM_READABLE);
5907
5908   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
5909
5910   /**
5911    * ClutterActor::destroy:
5912    * @actor: the #ClutterActor which emitted the signal
5913    *
5914    * The ::destroy signal notifies that all references held on the
5915    * actor which emitted it should be released.
5916    *
5917    * The ::destroy signal should be used by all holders of a reference
5918    * on @actor.
5919    *
5920    * This signal might result in the finalization of the #ClutterActor
5921    * if all references are released.
5922    *
5923    * Composite actors and actors implementing the #ClutterContainer
5924    * interface should override the default implementation of the
5925    * class handler of this signal and call clutter_actor_destroy() on
5926    * their children. When overriding the default class handler, it is
5927    * required to chain up to the parent's implementation.
5928    *
5929    * Since: 0.2
5930    */
5931   actor_signals[DESTROY] =
5932     g_signal_new (I_("destroy"),
5933                   G_TYPE_FROM_CLASS (object_class),
5934                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
5935                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
5936                   NULL, NULL,
5937                   _clutter_marshal_VOID__VOID,
5938                   G_TYPE_NONE, 0);
5939   /**
5940    * ClutterActor::show:
5941    * @actor: the object which received the signal
5942    *
5943    * The ::show signal is emitted when an actor is visible and
5944    * rendered on the stage.
5945    *
5946    * Since: 0.2
5947    */
5948   actor_signals[SHOW] =
5949     g_signal_new (I_("show"),
5950                   G_TYPE_FROM_CLASS (object_class),
5951                   G_SIGNAL_RUN_FIRST,
5952                   G_STRUCT_OFFSET (ClutterActorClass, show),
5953                   NULL, NULL,
5954                   _clutter_marshal_VOID__VOID,
5955                   G_TYPE_NONE, 0);
5956   /**
5957    * ClutterActor::hide:
5958    * @actor: the object which received the signal
5959    *
5960    * The ::hide signal is emitted when an actor is no longer rendered
5961    * on the stage.
5962    *
5963    * Since: 0.2
5964    */
5965   actor_signals[HIDE] =
5966     g_signal_new (I_("hide"),
5967                   G_TYPE_FROM_CLASS (object_class),
5968                   G_SIGNAL_RUN_FIRST,
5969                   G_STRUCT_OFFSET (ClutterActorClass, hide),
5970                   NULL, NULL,
5971                   _clutter_marshal_VOID__VOID,
5972                   G_TYPE_NONE, 0);
5973   /**
5974    * ClutterActor::parent-set:
5975    * @actor: the object which received the signal
5976    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
5977    *
5978    * This signal is emitted when the parent of the actor changes.
5979    *
5980    * Since: 0.2
5981    */
5982   actor_signals[PARENT_SET] =
5983     g_signal_new (I_("parent-set"),
5984                   G_TYPE_FROM_CLASS (object_class),
5985                   G_SIGNAL_RUN_LAST,
5986                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
5987                   NULL, NULL,
5988                   _clutter_marshal_VOID__OBJECT,
5989                   G_TYPE_NONE, 1,
5990                   CLUTTER_TYPE_ACTOR);
5991
5992   /**
5993    * ClutterActor::queue-redraw:
5994    * @actor: the actor we're bubbling the redraw request through
5995    * @origin: the actor which initiated the redraw request
5996    *
5997    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
5998    * is called on @origin.
5999    *
6000    * The default implementation for #ClutterActor chains up to the
6001    * parent actor and queues a redraw on the parent, thus "bubbling"
6002    * the redraw queue up through the actor graph. The default
6003    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6004    * in a main loop idle handler.
6005    *
6006    * Note that the @origin actor may be the stage, or a container; it
6007    * does not have to be a leaf node in the actor graph.
6008    *
6009    * Toolkits embedding a #ClutterStage which require a redraw and
6010    * relayout cycle can stop the emission of this signal using the
6011    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6012    * themselves, like:
6013    *
6014    * |[
6015    *   static void
6016    *   on_redraw_complete (gpointer data)
6017    *   {
6018    *     ClutterStage *stage = data;
6019    *
6020    *     /&ast; execute the Clutter drawing pipeline &ast;/
6021    *     clutter_stage_ensure_redraw (stage);
6022    *   }
6023    *
6024    *   static void
6025    *   on_stage_queue_redraw (ClutterStage *stage)
6026    *   {
6027    *     /&ast; this prevents the default handler to run &ast;/
6028    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6029    *
6030    *     /&ast; queue a redraw with the host toolkit and call
6031    *      &ast; a function when the redraw has been completed
6032    *      &ast;/
6033    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6034    *   }
6035    * ]|
6036    *
6037    * <note><para>This signal is emitted before the Clutter paint
6038    * pipeline is executed. If you want to know when the pipeline has
6039    * been completed you should connect to the ::paint signal on the
6040    * Stage with g_signal_connect_after().</para></note>
6041    *
6042    * Since: 1.0
6043    */
6044   actor_signals[QUEUE_REDRAW] =
6045     g_signal_new (I_("queue-redraw"),
6046                   G_TYPE_FROM_CLASS (object_class),
6047                   G_SIGNAL_RUN_LAST,
6048                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6049                   NULL, NULL,
6050                   _clutter_marshal_VOID__OBJECT,
6051                   G_TYPE_NONE, 1,
6052                   CLUTTER_TYPE_ACTOR);
6053
6054   /**
6055    * ClutterActor::queue-relayout
6056    * @actor: the actor being queued for relayout
6057    *
6058    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6059    * is called on an actor.
6060    *
6061    * The default implementation for #ClutterActor chains up to the
6062    * parent actor and queues a relayout on the parent, thus "bubbling"
6063    * the relayout queue up through the actor graph.
6064    *
6065    * The main purpose of this signal is to allow relayout to be propagated
6066    * properly in the procense of #ClutterClone actors. Applications will
6067    * not normally need to connect to this signal.
6068    *
6069    * Since: 1.2
6070    */
6071   actor_signals[QUEUE_RELAYOUT] =
6072     g_signal_new (I_("queue-relayout"),
6073                   G_TYPE_FROM_CLASS (object_class),
6074                   G_SIGNAL_RUN_LAST,
6075                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6076                   NULL, NULL,
6077                   _clutter_marshal_VOID__VOID,
6078                   G_TYPE_NONE, 0);
6079
6080   /**
6081    * ClutterActor::event:
6082    * @actor: the actor which received the event
6083    * @event: a #ClutterEvent
6084    *
6085    * The ::event signal is emitted each time an event is received
6086    * by the @actor. This signal will be emitted on every actor,
6087    * following the hierarchy chain, until it reaches the top-level
6088    * container (the #ClutterStage).
6089    *
6090    * Return value: %TRUE if the event has been handled by the actor,
6091    *   or %FALSE to continue the emission.
6092    *
6093    * Since: 0.6
6094    */
6095   actor_signals[EVENT] =
6096     g_signal_new (I_("event"),
6097                   G_TYPE_FROM_CLASS (object_class),
6098                   G_SIGNAL_RUN_LAST,
6099                   G_STRUCT_OFFSET (ClutterActorClass, event),
6100                   _clutter_boolean_handled_accumulator, NULL,
6101                   _clutter_marshal_BOOLEAN__BOXED,
6102                   G_TYPE_BOOLEAN, 1,
6103                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6104   /**
6105    * ClutterActor::button-press-event:
6106    * @actor: the actor which received the event
6107    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6108    *
6109    * The ::button-press-event signal is emitted each time a mouse button
6110    * is pressed on @actor.
6111    *
6112    * Return value: %TRUE if the event has been handled by the actor,
6113    *   or %FALSE to continue the emission.
6114    *
6115    * Since: 0.6
6116    */
6117   actor_signals[BUTTON_PRESS_EVENT] =
6118     g_signal_new (I_("button-press-event"),
6119                   G_TYPE_FROM_CLASS (object_class),
6120                   G_SIGNAL_RUN_LAST,
6121                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6122                   _clutter_boolean_handled_accumulator, NULL,
6123                   _clutter_marshal_BOOLEAN__BOXED,
6124                   G_TYPE_BOOLEAN, 1,
6125                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6126   /**
6127    * ClutterActor::button-release-event:
6128    * @actor: the actor which received the event
6129    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6130    *
6131    * The ::button-release-event signal is emitted each time a mouse button
6132    * is released on @actor.
6133    *
6134    * Return value: %TRUE if the event has been handled by the actor,
6135    *   or %FALSE to continue the emission.
6136    *
6137    * Since: 0.6
6138    */
6139   actor_signals[BUTTON_RELEASE_EVENT] =
6140     g_signal_new (I_("button-release-event"),
6141                   G_TYPE_FROM_CLASS (object_class),
6142                   G_SIGNAL_RUN_LAST,
6143                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6144                   _clutter_boolean_handled_accumulator, NULL,
6145                   _clutter_marshal_BOOLEAN__BOXED,
6146                   G_TYPE_BOOLEAN, 1,
6147                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6148   /**
6149    * ClutterActor::scroll-event:
6150    * @actor: the actor which received the event
6151    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6152    *
6153    * The ::scroll-event signal is emitted each time the mouse is
6154    * scrolled on @actor
6155    *
6156    * Return value: %TRUE if the event has been handled by the actor,
6157    *   or %FALSE to continue the emission.
6158    *
6159    * Since: 0.6
6160    */
6161   actor_signals[SCROLL_EVENT] =
6162     g_signal_new (I_("scroll-event"),
6163                   G_TYPE_FROM_CLASS (object_class),
6164                   G_SIGNAL_RUN_LAST,
6165                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6166                   _clutter_boolean_handled_accumulator, NULL,
6167                   _clutter_marshal_BOOLEAN__BOXED,
6168                   G_TYPE_BOOLEAN, 1,
6169                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6170   /**
6171    * ClutterActor::key-press-event:
6172    * @actor: the actor which received the event
6173    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6174    *
6175    * The ::key-press-event signal is emitted each time a keyboard button
6176    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6177    *
6178    * Return value: %TRUE if the event has been handled by the actor,
6179    *   or %FALSE to continue the emission.
6180    *
6181    * Since: 0.6
6182    */
6183   actor_signals[KEY_PRESS_EVENT] =
6184     g_signal_new (I_("key-press-event"),
6185                   G_TYPE_FROM_CLASS (object_class),
6186                   G_SIGNAL_RUN_LAST,
6187                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6188                   _clutter_boolean_handled_accumulator, NULL,
6189                   _clutter_marshal_BOOLEAN__BOXED,
6190                   G_TYPE_BOOLEAN, 1,
6191                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6192   /**
6193    * ClutterActor::key-release-event:
6194    * @actor: the actor which received the event
6195    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6196    *
6197    * The ::key-release-event signal is emitted each time a keyboard button
6198    * is released while @actor has key focus (see
6199    * clutter_stage_set_key_focus()).
6200    *
6201    * Return value: %TRUE if the event has been handled by the actor,
6202    *   or %FALSE to continue the emission.
6203    *
6204    * Since: 0.6
6205    */
6206   actor_signals[KEY_RELEASE_EVENT] =
6207     g_signal_new (I_("key-release-event"),
6208                   G_TYPE_FROM_CLASS (object_class),
6209                   G_SIGNAL_RUN_LAST,
6210                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6211                   _clutter_boolean_handled_accumulator, NULL,
6212                   _clutter_marshal_BOOLEAN__BOXED,
6213                   G_TYPE_BOOLEAN, 1,
6214                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6215   /**
6216    * ClutterActor::motion-event:
6217    * @actor: the actor which received the event
6218    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6219    *
6220    * The ::motion-event signal is emitted each time the mouse pointer is
6221    * moved over @actor.
6222    *
6223    * Return value: %TRUE if the event has been handled by the actor,
6224    *   or %FALSE to continue the emission.
6225    *
6226    * Since: 0.6
6227    */
6228   actor_signals[MOTION_EVENT] =
6229     g_signal_new (I_("motion-event"),
6230                   G_TYPE_FROM_CLASS (object_class),
6231                   G_SIGNAL_RUN_LAST,
6232                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6233                   _clutter_boolean_handled_accumulator, NULL,
6234                   _clutter_marshal_BOOLEAN__BOXED,
6235                   G_TYPE_BOOLEAN, 1,
6236                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6237
6238   /**
6239    * ClutterActor::key-focus-in:
6240    * @actor: the actor which now has key focus
6241    *
6242    * The ::key-focus-in signal is emitted when @actor receives key focus.
6243    *
6244    * Since: 0.6
6245    */
6246   actor_signals[KEY_FOCUS_IN] =
6247     g_signal_new (I_("key-focus-in"),
6248                   G_TYPE_FROM_CLASS (object_class),
6249                   G_SIGNAL_RUN_LAST,
6250                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6251                   NULL, NULL,
6252                   _clutter_marshal_VOID__VOID,
6253                   G_TYPE_NONE, 0);
6254
6255   /**
6256    * ClutterActor::key-focus-out:
6257    * @actor: the actor which now has key focus
6258    *
6259    * The ::key-focus-out signal is emitted when @actor loses key focus.
6260    *
6261    * Since: 0.6
6262    */
6263   actor_signals[KEY_FOCUS_OUT] =
6264     g_signal_new (I_("key-focus-out"),
6265                   G_TYPE_FROM_CLASS (object_class),
6266                   G_SIGNAL_RUN_LAST,
6267                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6268                   NULL, NULL,
6269                   _clutter_marshal_VOID__VOID,
6270                   G_TYPE_NONE, 0);
6271
6272   /**
6273    * ClutterActor::enter-event:
6274    * @actor: the actor which the pointer has entered.
6275    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6276    *
6277    * The ::enter-event signal is emitted when the pointer enters the @actor
6278    *
6279    * Return value: %TRUE if the event has been handled by the actor,
6280    *   or %FALSE to continue the emission.
6281    *
6282    * Since: 0.6
6283    */
6284   actor_signals[ENTER_EVENT] =
6285     g_signal_new (I_("enter-event"),
6286                   G_TYPE_FROM_CLASS (object_class),
6287                   G_SIGNAL_RUN_LAST,
6288                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6289                   _clutter_boolean_handled_accumulator, NULL,
6290                   _clutter_marshal_BOOLEAN__BOXED,
6291                   G_TYPE_BOOLEAN, 1,
6292                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6293
6294   /**
6295    * ClutterActor::leave-event:
6296    * @actor: the actor which the pointer has left
6297    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6298    *
6299    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6300    *
6301    * Return value: %TRUE if the event has been handled by the actor,
6302    *   or %FALSE to continue the emission.
6303    *
6304    * Since: 0.6
6305    */
6306   actor_signals[LEAVE_EVENT] =
6307     g_signal_new (I_("leave-event"),
6308                   G_TYPE_FROM_CLASS (object_class),
6309                   G_SIGNAL_RUN_LAST,
6310                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6311                   _clutter_boolean_handled_accumulator, NULL,
6312                   _clutter_marshal_BOOLEAN__BOXED,
6313                   G_TYPE_BOOLEAN, 1,
6314                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6315
6316   /**
6317    * ClutterActor::captured-event:
6318    * @actor: the actor which received the signal
6319    * @event: a #ClutterEvent
6320    *
6321    * The ::captured-event signal is emitted when an event is captured
6322    * by Clutter. This signal will be emitted starting from the top-level
6323    * container (the #ClutterStage) to the actor which received the event
6324    * going down the hierarchy. This signal can be used to intercept every
6325    * event before the specialized events (like
6326    * ClutterActor::button-press-event or ::key-released-event) are
6327    * emitted.
6328    *
6329    * Return value: %TRUE if the event has been handled by the actor,
6330    *   or %FALSE to continue the emission.
6331    *
6332    * Since: 0.6
6333    */
6334   actor_signals[CAPTURED_EVENT] =
6335     g_signal_new (I_("captured-event"),
6336                   G_TYPE_FROM_CLASS (object_class),
6337                   G_SIGNAL_RUN_LAST,
6338                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6339                   _clutter_boolean_handled_accumulator, NULL,
6340                   _clutter_marshal_BOOLEAN__BOXED,
6341                   G_TYPE_BOOLEAN, 1,
6342                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6343
6344   /**
6345    * ClutterActor::paint:
6346    * @actor: the #ClutterActor that received the signal
6347    *
6348    * The ::paint signal is emitted each time an actor is being painted.
6349    *
6350    * Subclasses of #ClutterActor should override the class signal handler
6351    * and paint themselves in that function.
6352    *
6353    * It is possible to connect a handler to the ::paint signal in order
6354    * to set up some custom aspect of a paint.
6355    *
6356    * Since: 0.8
6357    */
6358   actor_signals[PAINT] =
6359     g_signal_new (I_("paint"),
6360                   G_TYPE_FROM_CLASS (object_class),
6361                   G_SIGNAL_RUN_LAST,
6362                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6363                   NULL, NULL,
6364                   _clutter_marshal_VOID__VOID,
6365                   G_TYPE_NONE, 0);
6366   /**
6367    * ClutterActor::realize:
6368    * @actor: the #ClutterActor that received the signal
6369    *
6370    * The ::realize signal is emitted each time an actor is being
6371    * realized.
6372    *
6373    * Since: 0.8
6374    */
6375   actor_signals[REALIZE] =
6376     g_signal_new (I_("realize"),
6377                   G_TYPE_FROM_CLASS (object_class),
6378                   G_SIGNAL_RUN_LAST,
6379                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6380                   NULL, NULL,
6381                   _clutter_marshal_VOID__VOID,
6382                   G_TYPE_NONE, 0);
6383   /**
6384    * ClutterActor::unrealize:
6385    * @actor: the #ClutterActor that received the signal
6386    *
6387    * The ::unrealize signal is emitted each time an actor is being
6388    * unrealized.
6389    *
6390    * Since: 0.8
6391    */
6392   actor_signals[UNREALIZE] =
6393     g_signal_new (I_("unrealize"),
6394                   G_TYPE_FROM_CLASS (object_class),
6395                   G_SIGNAL_RUN_LAST,
6396                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6397                   NULL, NULL,
6398                   _clutter_marshal_VOID__VOID,
6399                   G_TYPE_NONE, 0);
6400
6401   /**
6402    * ClutterActor::pick:
6403    * @actor: the #ClutterActor that received the signal
6404    * @color: the #ClutterColor to be used when picking
6405    *
6406    * The ::pick signal is emitted each time an actor is being painted
6407    * in "pick mode". The pick mode is used to identify the actor during
6408    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6409    * The actor should paint its shape using the passed @pick_color.
6410    *
6411    * Subclasses of #ClutterActor should override the class signal handler
6412    * and paint themselves in that function.
6413    *
6414    * It is possible to connect a handler to the ::pick signal in order
6415    * to set up some custom aspect of a paint in pick mode.
6416    *
6417    * Since: 1.0
6418    */
6419   actor_signals[PICK] =
6420     g_signal_new (I_("pick"),
6421                   G_TYPE_FROM_CLASS (object_class),
6422                   G_SIGNAL_RUN_LAST,
6423                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6424                   NULL, NULL,
6425                   _clutter_marshal_VOID__BOXED,
6426                   G_TYPE_NONE, 1,
6427                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6428
6429   /**
6430    * ClutterActor::allocation-changed:
6431    * @actor: the #ClutterActor that emitted the signal
6432    * @box: a #ClutterActorBox with the new allocation
6433    * @flags: #ClutterAllocationFlags for the allocation
6434    *
6435    * The ::allocation-changed signal is emitted when the
6436    * #ClutterActor:allocation property changes. Usually, application
6437    * code should just use the notifications for the :allocation property
6438    * but if you want to track the allocation flags as well, for instance
6439    * to know whether the absolute origin of @actor changed, then you might
6440    * want use this signal instead.
6441    *
6442    * Since: 1.0
6443    */
6444   actor_signals[ALLOCATION_CHANGED] =
6445     g_signal_new (I_("allocation-changed"),
6446                   G_TYPE_FROM_CLASS (object_class),
6447                   G_SIGNAL_RUN_LAST,
6448                   0,
6449                   NULL, NULL,
6450                   _clutter_marshal_VOID__BOXED_FLAGS,
6451                   G_TYPE_NONE, 2,
6452                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6453                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6454 }
6455
6456 static void
6457 clutter_actor_init (ClutterActor *self)
6458 {
6459   ClutterActorPrivate *priv;
6460
6461   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6462
6463   priv->id = _clutter_context_acquire_id (self);
6464   priv->pick_id = -1;
6465
6466   priv->opacity = 0xff;
6467   priv->show_on_set_parent = TRUE;
6468
6469   priv->needs_width_request = TRUE;
6470   priv->needs_height_request = TRUE;
6471   priv->needs_allocation = TRUE;
6472
6473   priv->cached_width_age = 1;
6474   priv->cached_height_age = 1;
6475
6476   priv->opacity_override = -1;
6477   priv->enable_model_view_transform = TRUE;
6478
6479   /* Initialize an empty paint volume to start with */
6480   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6481   priv->last_paint_volume_valid = TRUE;
6482
6483   priv->transform_valid = FALSE;
6484 }
6485
6486 /**
6487  * clutter_actor_new:
6488  *
6489  * Creates a new #ClutterActor.
6490  *
6491  * A newly created actor has a floating reference, which will be sunk
6492  * when it is added to another actor.
6493  *
6494  * Return value: (transfer full): the newly created #ClutterActor
6495  *
6496  * Since: 1.10
6497  */
6498 ClutterActor *
6499 clutter_actor_new (void)
6500 {
6501   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6502 }
6503
6504 /**
6505  * clutter_actor_destroy:
6506  * @self: a #ClutterActor
6507  *
6508  * Destroys an actor.  When an actor is destroyed, it will break any
6509  * references it holds to other objects.  If the actor is inside a
6510  * container, the actor will be removed.
6511  *
6512  * When you destroy a container, its children will be destroyed as well.
6513  *
6514  * Note: you cannot destroy the #ClutterStage returned by
6515  * clutter_stage_get_default().
6516  */
6517 void
6518 clutter_actor_destroy (ClutterActor *self)
6519 {
6520   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6521
6522   g_object_ref (self);
6523
6524   /* avoid recursion while destroying */
6525   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6526     {
6527       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6528
6529       g_object_run_dispose (G_OBJECT (self));
6530
6531       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6532     }
6533
6534   g_object_unref (self);
6535 }
6536
6537 void
6538 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6539                                     ClutterPaintVolume *clip)
6540 {
6541   ClutterActorPrivate *priv = self->priv;
6542   ClutterPaintVolume *pv;
6543   gboolean clipped;
6544
6545   /* Remove queue entry early in the process, otherwise a new
6546      queue_redraw() during signal handling could put back this
6547      object in the stage redraw list (but the entry is freed as
6548      soon as we return from this function, causing a segfault
6549      later)
6550   */
6551   priv->queue_redraw_entry = NULL;
6552
6553   /* If we've been explicitly passed a clip volume then there's
6554    * nothing more to calculate, but otherwise the only thing we know
6555    * is that the change is constrained to the given actor.
6556    *
6557    * The idea is that if we know the paint volume for where the actor
6558    * was last drawn (in eye coordinates) and we also have the paint
6559    * volume for where it will be drawn next (in actor coordinates)
6560    * then if we queue a redraw for both these volumes that will cover
6561    * everything that needs to be redrawn to clear the old view and
6562    * show the latest view of the actor.
6563    *
6564    * Don't clip this redraw if we don't know what position we had for
6565    * the previous redraw since we don't know where to set the clip so
6566    * it will clear the actor as it is currently.
6567    */
6568   if (clip)
6569     {
6570       _clutter_actor_set_queue_redraw_clip (self, clip);
6571       clipped = TRUE;
6572     }
6573   else if (G_LIKELY (priv->last_paint_volume_valid))
6574     {
6575       pv = _clutter_actor_get_paint_volume_mutable (self);
6576       if (pv)
6577         {
6578           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6579
6580           /* make sure we redraw the actors old position... */
6581           _clutter_actor_set_queue_redraw_clip (stage,
6582                                                 &priv->last_paint_volume);
6583           _clutter_actor_signal_queue_redraw (stage, stage);
6584           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6585
6586           /* XXX: Ideally the redraw signal would take a clip volume
6587            * argument, but that would be an ABI break. Until we can
6588            * break the ABI we pass the argument out-of-band
6589            */
6590
6591           /* setup the clip for the actors new position... */
6592           _clutter_actor_set_queue_redraw_clip (self, pv);
6593           clipped = TRUE;
6594         }
6595       else
6596         clipped = FALSE;
6597     }
6598   else
6599     clipped = FALSE;
6600
6601   _clutter_actor_signal_queue_redraw (self, self);
6602
6603   /* Just in case anyone is manually firing redraw signals without
6604    * using the public queue_redraw() API we are careful to ensure that
6605    * our out-of-band clip member is cleared before returning...
6606    *
6607    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6608    */
6609   if (G_LIKELY (clipped))
6610     _clutter_actor_set_queue_redraw_clip (self, NULL);
6611 }
6612
6613 static void
6614 _clutter_actor_get_allocation_clip (ClutterActor *self,
6615                                     ClutterActorBox *clip)
6616 {
6617   ClutterActorBox allocation;
6618
6619   /* XXX: we don't care if we get an out of date allocation here
6620    * because clutter_actor_queue_redraw_with_clip knows to ignore
6621    * the clip if the actor's allocation is invalid.
6622    *
6623    * This is noted because clutter_actor_get_allocation_box does some
6624    * unnecessary work to support buggy code with a comment suggesting
6625    * that it could be changed later which would be good for this use
6626    * case!
6627    */
6628   clutter_actor_get_allocation_box (self, &allocation);
6629
6630   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6631    * actor's own coordinate space but the allocation is in parent
6632    * coordinates */
6633   clip->x1 = 0;
6634   clip->y1 = 0;
6635   clip->x2 = allocation.x2 - allocation.x1;
6636   clip->y2 = allocation.y2 - allocation.y1;
6637 }
6638
6639 void
6640 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6641                                   ClutterRedrawFlags  flags,
6642                                   ClutterPaintVolume *volume,
6643                                   ClutterEffect      *effect)
6644 {
6645   ClutterActorPrivate *priv = self->priv;
6646   ClutterPaintVolume allocation_pv;
6647   ClutterPaintVolume *pv;
6648   gboolean should_free_pv;
6649   ClutterActor *stage;
6650
6651   /* Here's an outline of the actor queue redraw mechanism:
6652    *
6653    * The process starts in one of the following two functions which
6654    * are wrappers for this function:
6655    * clutter_actor_queue_redraw
6656    * _clutter_actor_queue_redraw_with_clip
6657    *
6658    * additionally, an effect can queue a redraw by wrapping this
6659    * function in clutter_effect_queue_rerun
6660    *
6661    * This functions queues an entry in a list associated with the
6662    * stage which is a list of actors that queued a redraw while
6663    * updating the timelines, performing layouting and processing other
6664    * mainloop sources before the next paint starts.
6665    *
6666    * We aim to minimize the processing done at this point because
6667    * there is a good chance other events will happen while updating
6668    * the scenegraph that would invalidate any expensive work we might
6669    * otherwise try to do here. For example we don't try and resolve
6670    * the screen space bounding box of an actor at this stage so as to
6671    * minimize how much of the screen redraw because it's possible
6672    * something else will happen which will force a full redraw anyway.
6673    *
6674    * When all updates are complete and we come to paint the stage then
6675    * we iterate this list and actually emit the "queue-redraw" signals
6676    * for each of the listed actors which will bubble up to the stage
6677    * for each actor and at that point we will transform the actors
6678    * paint volume into screen coordinates to determine the clip region
6679    * for what needs to be redrawn in the next paint.
6680    *
6681    * Besides minimizing redundant work another reason for this
6682    * deferred design is that it's more likely we will be able to
6683    * determine the paint volume of an actor once we've finished
6684    * updating the scenegraph because its allocation should be up to
6685    * date. NB: If we can't determine an actors paint volume then we
6686    * can't automatically queue a clipped redraw which can make a big
6687    * difference to performance.
6688    *
6689    * So the control flow goes like this:
6690    * One of clutter_actor_queue_redraw,
6691    *        _clutter_actor_queue_redraw_with_clip
6692    *     or clutter_effect_queue_rerun
6693    *
6694    * then control moves to:
6695    *   _clutter_stage_queue_actor_redraw
6696    *
6697    * later during _clutter_stage_do_update, once relayouting is done
6698    * and the scenegraph has been updated we will call:
6699    * _clutter_stage_finish_queue_redraws
6700    *
6701    * _clutter_stage_finish_queue_redraws will call
6702    * _clutter_actor_finish_queue_redraw for each listed actor.
6703    * Note: actors *are* allowed to queue further redraws during this
6704    * process (considering clone actors or texture_new_from_actor which
6705    * respond to their source queueing a redraw by queuing a redraw
6706    * themselves). We repeat the process until the list is empty.
6707    *
6708    * This will result in the "queue-redraw" signal being fired for
6709    * each actor which will pass control to the default signal handler:
6710    * clutter_actor_real_queue_redraw
6711    *
6712    * This will bubble up to the stages handler:
6713    * clutter_stage_real_queue_redraw
6714    *
6715    * clutter_stage_real_queue_redraw will transform the actors paint
6716    * volume into screen space and add it as a clip region for the next
6717    * paint.
6718    */
6719
6720   /* ignore queueing a redraw for actors being destroyed */
6721   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6722     return;
6723
6724   stage = _clutter_actor_get_stage_internal (self);
6725
6726   /* Ignore queueing a redraw for actors not descended from a stage */
6727   if (stage == NULL)
6728     return;
6729
6730   /* ignore queueing a redraw on stages that are being destroyed */
6731   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6732     return;
6733
6734   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6735     {
6736       ClutterActorBox allocation_clip;
6737       ClutterVertex origin;
6738
6739       /* If the actor doesn't have a valid allocation then we will
6740        * queue a full stage redraw. */
6741       if (priv->needs_allocation)
6742         {
6743           /* NB: NULL denotes an undefined clip which will result in a
6744            * full redraw... */
6745           _clutter_actor_set_queue_redraw_clip (self, NULL);
6746           _clutter_actor_signal_queue_redraw (self, self);
6747           return;
6748         }
6749
6750       _clutter_paint_volume_init_static (&allocation_pv, self);
6751       pv = &allocation_pv;
6752
6753       _clutter_actor_get_allocation_clip (self, &allocation_clip);
6754
6755       origin.x = allocation_clip.x1;
6756       origin.y = allocation_clip.y1;
6757       origin.z = 0;
6758       clutter_paint_volume_set_origin (pv, &origin);
6759       clutter_paint_volume_set_width (pv,
6760                                       allocation_clip.x2 - allocation_clip.x1);
6761       clutter_paint_volume_set_height (pv,
6762                                        allocation_clip.y2 -
6763                                        allocation_clip.y1);
6764       should_free_pv = TRUE;
6765     }
6766   else
6767     {
6768       pv = volume;
6769       should_free_pv = FALSE;
6770     }
6771
6772   self->priv->queue_redraw_entry =
6773     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6774                                        priv->queue_redraw_entry,
6775                                        self,
6776                                        pv);
6777
6778   if (should_free_pv)
6779     clutter_paint_volume_free (pv);
6780
6781   /* If this is the first redraw queued then we can directly use the
6782      effect parameter */
6783   if (!priv->is_dirty)
6784     priv->effect_to_redraw = effect;
6785   /* Otherwise we need to merge it with the existing effect parameter */
6786   else if (effect != NULL)
6787     {
6788       /* If there's already an effect then we need to use whichever is
6789          later in the chain of actors. Otherwise a full redraw has
6790          already been queued on the actor so we need to ignore the
6791          effect parameter */
6792       if (priv->effect_to_redraw != NULL)
6793         {
6794           if (priv->effects == NULL)
6795             g_warning ("Redraw queued with an effect that is "
6796                        "not applied to the actor");
6797           else
6798             {
6799               const GList *l;
6800
6801               for (l = _clutter_meta_group_peek_metas (priv->effects);
6802                    l != NULL;
6803                    l = l->next)
6804                 {
6805                   if (l->data == priv->effect_to_redraw ||
6806                       l->data == effect)
6807                     priv->effect_to_redraw = l->data;
6808                 }
6809             }
6810         }
6811     }
6812   else
6813     {
6814       /* If no effect is specified then we need to redraw the whole
6815          actor */
6816       priv->effect_to_redraw = NULL;
6817     }
6818
6819   priv->is_dirty = TRUE;
6820 }
6821
6822 /**
6823  * clutter_actor_queue_redraw:
6824  * @self: A #ClutterActor
6825  *
6826  * Queues up a redraw of an actor and any children. The redraw occurs
6827  * once the main loop becomes idle (after the current batch of events
6828  * has been processed, roughly).
6829  *
6830  * Applications rarely need to call this, as redraws are handled
6831  * automatically by modification functions.
6832  *
6833  * This function will not do anything if @self is not visible, or
6834  * if the actor is inside an invisible part of the scenegraph.
6835  *
6836  * Also be aware that painting is a NOP for actors with an opacity of
6837  * 0
6838  *
6839  * When you are implementing a custom actor you must queue a redraw
6840  * whenever some private state changes that will affect painting or
6841  * picking of your actor.
6842  */
6843 void
6844 clutter_actor_queue_redraw (ClutterActor *self)
6845 {
6846   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6847
6848   _clutter_actor_queue_redraw_full (self,
6849                                     0, /* flags */
6850                                     NULL, /* clip volume */
6851                                     NULL /* effect */);
6852 }
6853
6854 /*< private >
6855  * _clutter_actor_queue_redraw_with_clip:
6856  * @self: A #ClutterActor
6857  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
6858  *   this queue redraw.
6859  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
6860  *   redrawn or %NULL if you are just using a @flag to state your
6861  *   desired clipping.
6862  *
6863  * Queues up a clipped redraw of an actor and any children. The redraw
6864  * occurs once the main loop becomes idle (after the current batch of
6865  * events has been processed, roughly).
6866  *
6867  * If no flags are given the clip volume is defined by @volume
6868  * specified in actor coordinates and tells Clutter that only content
6869  * within this volume has been changed so Clutter can optionally
6870  * optimize the redraw.
6871  *
6872  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
6873  * should be %NULL and this tells Clutter to use the actor's current
6874  * allocation as a clip box. This flag can only be used for 2D actors,
6875  * because any actor with depth may be projected outside its
6876  * allocation.
6877  *
6878  * Applications rarely need to call this, as redraws are handled
6879  * automatically by modification functions.
6880  *
6881  * This function will not do anything if @self is not visible, or if
6882  * the actor is inside an invisible part of the scenegraph.
6883  *
6884  * Also be aware that painting is a NOP for actors with an opacity of
6885  * 0
6886  *
6887  * When you are implementing a custom actor you must queue a redraw
6888  * whenever some private state changes that will affect painting or
6889  * picking of your actor.
6890  */
6891 void
6892 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
6893                                        ClutterRedrawFlags  flags,
6894                                        ClutterPaintVolume *volume)
6895 {
6896   _clutter_actor_queue_redraw_full (self,
6897                                     flags, /* flags */
6898                                     volume, /* clip volume */
6899                                     NULL /* effect */);
6900 }
6901
6902 static void
6903 _clutter_actor_queue_only_relayout (ClutterActor *self)
6904 {
6905   ClutterActorPrivate *priv = self->priv;
6906
6907   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6908     return;
6909
6910   if (priv->needs_width_request &&
6911       priv->needs_height_request &&
6912       priv->needs_allocation)
6913     return; /* save some cpu cycles */
6914
6915 #if CLUTTER_ENABLE_DEBUG
6916   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
6917     {
6918       g_warning ("The actor '%s' is currently inside an allocation "
6919                  "cycle; calling clutter_actor_queue_relayout() is "
6920                  "not recommended",
6921                  _clutter_actor_get_debug_name (self));
6922     }
6923 #endif /* CLUTTER_ENABLE_DEBUG */
6924
6925   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
6926 }
6927
6928 /**
6929  * clutter_actor_queue_redraw_with_clip:
6930  * @self: a #ClutterActor
6931  * @clip: (allow-none): a rectangular clip region, or %NULL
6932  *
6933  * Queues a redraw on @self limited to a specific, actor-relative
6934  * rectangular area.
6935  *
6936  * If @clip is %NULL this function is equivalent to
6937  * clutter_actor_queue_redraw().
6938  *
6939  * Since: 1.10
6940  */
6941 void
6942 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
6943                                       const cairo_rectangle_int_t *clip)
6944 {
6945   ClutterPaintVolume volume;
6946   ClutterVertex origin;
6947
6948   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6949
6950   if (clip == NULL)
6951     {
6952       clutter_actor_queue_redraw (self);
6953       return;
6954     }
6955
6956   _clutter_paint_volume_init_static (&volume, self);
6957
6958   origin.x = clip->x;
6959   origin.y = clip->y;
6960   origin.z = 0.0f;
6961
6962   clutter_paint_volume_set_origin (&volume, &origin);
6963   clutter_paint_volume_set_width (&volume, clip->width);
6964   clutter_paint_volume_set_height (&volume, clip->height);
6965
6966   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
6967
6968   clutter_paint_volume_free (&volume);
6969 }
6970
6971 /**
6972  * clutter_actor_queue_relayout:
6973  * @self: A #ClutterActor
6974  *
6975  * Indicates that the actor's size request or other layout-affecting
6976  * properties may have changed. This function is used inside #ClutterActor
6977  * subclass implementations, not by applications directly.
6978  *
6979  * Queueing a new layout automatically queues a redraw as well.
6980  *
6981  * Since: 0.8
6982  */
6983 void
6984 clutter_actor_queue_relayout (ClutterActor *self)
6985 {
6986   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6987
6988   _clutter_actor_queue_only_relayout (self);
6989   clutter_actor_queue_redraw (self);
6990 }
6991
6992 /**
6993  * clutter_actor_get_preferred_size:
6994  * @self: a #ClutterActor
6995  * @min_width_p: (out) (allow-none): return location for the minimum
6996  *   width, or %NULL
6997  * @min_height_p: (out) (allow-none): return location for the minimum
6998  *   height, or %NULL
6999  * @natural_width_p: (out) (allow-none): return location for the natural
7000  *   width, or %NULL
7001  * @natural_height_p: (out) (allow-none): return location for the natural
7002  *   height, or %NULL
7003  *
7004  * Computes the preferred minimum and natural size of an actor, taking into
7005  * account the actor's geometry management (either height-for-width
7006  * or width-for-height).
7007  *
7008  * The width and height used to compute the preferred height and preferred
7009  * width are the actor's natural ones.
7010  *
7011  * If you need to control the height for the preferred width, or the width for
7012  * the preferred height, you should use clutter_actor_get_preferred_width()
7013  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7014  * geometry management using the #ClutterActor:request-mode property.
7015  *
7016  * Since: 0.8
7017  */
7018 void
7019 clutter_actor_get_preferred_size (ClutterActor *self,
7020                                   gfloat       *min_width_p,
7021                                   gfloat       *min_height_p,
7022                                   gfloat       *natural_width_p,
7023                                   gfloat       *natural_height_p)
7024 {
7025   ClutterActorPrivate *priv;
7026   gfloat min_width, min_height;
7027   gfloat natural_width, natural_height;
7028
7029   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7030
7031   priv = self->priv;
7032
7033   min_width = min_height = 0;
7034   natural_width = natural_height = 0;
7035
7036   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7037     {
7038       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7039       clutter_actor_get_preferred_width (self, -1,
7040                                          &min_width,
7041                                          &natural_width);
7042       clutter_actor_get_preferred_height (self, natural_width,
7043                                           &min_height,
7044                                           &natural_height);
7045     }
7046   else
7047     {
7048       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7049       clutter_actor_get_preferred_height (self, -1,
7050                                           &min_height,
7051                                           &natural_height);
7052       clutter_actor_get_preferred_width (self, natural_height,
7053                                          &min_width,
7054                                          &natural_width);
7055     }
7056
7057   if (min_width_p)
7058     *min_width_p = min_width;
7059
7060   if (min_height_p)
7061     *min_height_p = min_height;
7062
7063   if (natural_width_p)
7064     *natural_width_p = natural_width;
7065
7066   if (natural_height_p)
7067     *natural_height_p = natural_height;
7068 }
7069
7070 /*< private >
7071  * effective_align:
7072  * @align: a #ClutterActorAlign
7073  * @direction: a #ClutterTextDirection
7074  *
7075  * Retrieves the correct alignment depending on the text direction
7076  *
7077  * Return value: the effective alignment
7078  */
7079 static ClutterActorAlign
7080 effective_align (ClutterActorAlign    align,
7081                  ClutterTextDirection direction)
7082 {
7083   ClutterActorAlign res;
7084
7085   switch (align)
7086     {
7087     case CLUTTER_ACTOR_ALIGN_START:
7088       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7089           ? CLUTTER_ACTOR_ALIGN_END
7090           : CLUTTER_ACTOR_ALIGN_START;
7091       break;
7092
7093     case CLUTTER_ACTOR_ALIGN_END:
7094       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7095           ? CLUTTER_ACTOR_ALIGN_START
7096           : CLUTTER_ACTOR_ALIGN_END;
7097       break;
7098
7099     default:
7100       res = align;
7101       break;
7102     }
7103
7104   return res;
7105 }
7106
7107 static inline void
7108 adjust_for_margin (float  margin_start,
7109                    float  margin_end,
7110                    float *minimum_size,
7111                    float *natural_size,
7112                    float *allocated_start,
7113                    float *allocated_end)
7114 {
7115   *minimum_size -= (margin_start + margin_end);
7116   *natural_size -= (margin_start + margin_end);
7117   *allocated_start += margin_start;
7118   *allocated_end -= margin_end;
7119 }
7120
7121 static inline void
7122 adjust_for_alignment (ClutterActorAlign  alignment,
7123                       float              natural_size,
7124                       float             *allocated_start,
7125                       float             *allocated_end)
7126 {
7127   float allocated_size = *allocated_end - *allocated_start;
7128
7129   switch (alignment)
7130     {
7131     case CLUTTER_ACTOR_ALIGN_FILL:
7132       /* do nothing */
7133       break;
7134
7135     case CLUTTER_ACTOR_ALIGN_START:
7136       /* keep start */
7137       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7138       break;
7139
7140     case CLUTTER_ACTOR_ALIGN_END:
7141       if (allocated_size > natural_size)
7142         {
7143           *allocated_start += (allocated_size - natural_size);
7144           *allocated_end = *allocated_start + natural_size;
7145         }
7146       break;
7147
7148     case CLUTTER_ACTOR_ALIGN_CENTER:
7149       if (allocated_size > natural_size)
7150         {
7151           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7152           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7153         }
7154       break;
7155     }
7156 }
7157
7158 /*< private >
7159  * clutter_actor_adjust_width:
7160  * @self: a #ClutterActor
7161  * @minimum_width: (inout): the actor's preferred minimum width, which
7162  *   will be adjusted depending on the margin
7163  * @natural_width: (inout): the actor's preferred natural width, which
7164  *   will be adjusted depending on the margin
7165  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7166  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7167  *
7168  * Adjusts the preferred and allocated position and size of an actor,
7169  * depending on the margin and alignment properties.
7170  */
7171 static void
7172 clutter_actor_adjust_width (ClutterActor *self,
7173                             gfloat       *minimum_width,
7174                             gfloat       *natural_width,
7175                             gfloat       *adjusted_x1,
7176                             gfloat       *adjusted_x2)
7177 {
7178   ClutterTextDirection text_dir;
7179   const ClutterLayoutInfo *info;
7180
7181   info = _clutter_actor_get_layout_info_or_defaults (self);
7182   text_dir = clutter_actor_get_text_direction (self);
7183
7184   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7185
7186   /* this will tweak natural_width to remove the margin, so that
7187    * adjust_for_alignment() will use the correct size
7188    */
7189   adjust_for_margin (info->margin.left, info->margin.right,
7190                      minimum_width, natural_width,
7191                      adjusted_x1, adjusted_x2);
7192
7193   adjust_for_alignment (effective_align (info->x_align, text_dir),
7194                         *natural_width,
7195                         adjusted_x1, adjusted_x2);
7196 }
7197
7198 /*< private >
7199  * clutter_actor_adjust_height:
7200  * @self: a #ClutterActor
7201  * @minimum_height: (inout): the actor's preferred minimum height, which
7202  *   will be adjusted depending on the margin
7203  * @natural_height: (inout): the actor's preferred natural height, which
7204  *   will be adjusted depending on the margin
7205  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7206  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7207  *
7208  * Adjusts the preferred and allocated position and size of an actor,
7209  * depending on the margin and alignment properties.
7210  */
7211 static void
7212 clutter_actor_adjust_height (ClutterActor *self,
7213                              gfloat       *minimum_height,
7214                              gfloat       *natural_height,
7215                              gfloat       *adjusted_y1,
7216                              gfloat       *adjusted_y2)
7217 {
7218   const ClutterLayoutInfo *info;
7219
7220   info = _clutter_actor_get_layout_info_or_defaults (self);
7221
7222   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7223
7224   /* this will tweak natural_height to remove the margin, so that
7225    * adjust_for_alignment() will use the correct size
7226    */
7227   adjust_for_margin (info->margin.top, info->margin.bottom,
7228                      minimum_height, natural_height,
7229                      adjusted_y1,
7230                      adjusted_y2);
7231
7232   /* we don't use effective_align() here, because text direction
7233    * only affects the horizontal axis
7234    */
7235   adjust_for_alignment (info->y_align,
7236                         *natural_height,
7237                         adjusted_y1,
7238                         adjusted_y2);
7239
7240 }
7241
7242 /* looks for a cached size request for this for_size. If not
7243  * found, returns the oldest entry so it can be overwritten */
7244 static gboolean
7245 _clutter_actor_get_cached_size_request (gfloat         for_size,
7246                                         SizeRequest   *cached_size_requests,
7247                                         SizeRequest  **result)
7248 {
7249   guint i;
7250
7251   *result = &cached_size_requests[0];
7252
7253   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7254     {
7255       SizeRequest *sr;
7256
7257       sr = &cached_size_requests[i];
7258
7259       if (sr->age > 0 &&
7260           sr->for_size == for_size)
7261         {
7262           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7263           *result = sr;
7264           return TRUE;
7265         }
7266       else if (sr->age < (*result)->age)
7267         {
7268           *result = sr;
7269         }
7270     }
7271
7272   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7273
7274   return FALSE;
7275 }
7276
7277 /**
7278  * clutter_actor_get_preferred_width:
7279  * @self: A #ClutterActor
7280  * @for_height: available height when computing the preferred width,
7281  *   or a negative value to indicate that no height is defined
7282  * @min_width_p: (out) (allow-none): return location for minimum width,
7283  *   or %NULL
7284  * @natural_width_p: (out) (allow-none): return location for the natural
7285  *   width, or %NULL
7286  *
7287  * Computes the requested minimum and natural widths for an actor,
7288  * optionally depending on the specified height, or if they are
7289  * already computed, returns the cached values.
7290  *
7291  * An actor may not get its request - depending on the layout
7292  * manager that's in effect.
7293  *
7294  * A request should not incorporate the actor's scale or anchor point;
7295  * those transformations do not affect layout, only rendering.
7296  *
7297  * Since: 0.8
7298  */
7299 void
7300 clutter_actor_get_preferred_width (ClutterActor *self,
7301                                    gfloat        for_height,
7302                                    gfloat       *min_width_p,
7303                                    gfloat       *natural_width_p)
7304 {
7305   float request_min_width, request_natural_width;
7306   SizeRequest *cached_size_request;
7307   const ClutterLayoutInfo *info;
7308   ClutterActorPrivate *priv;
7309   gboolean found_in_cache;
7310
7311   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7312
7313   priv = self->priv;
7314
7315   info = _clutter_actor_get_layout_info_or_defaults (self);
7316
7317   /* we shortcircuit the case of a fixed size set using set_width() */
7318   if (priv->min_width_set && priv->natural_width_set)
7319     {
7320       if (min_width_p != NULL)
7321         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7322
7323       if (natural_width_p != NULL)
7324         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7325
7326       return;
7327     }
7328
7329   /* the remaining cases are:
7330    *
7331    *   - either min_width or natural_width have been set
7332    *   - neither min_width or natural_width have been set
7333    *
7334    * in both cases, we go through the cache (and through the actor in case
7335    * of cache misses) and determine the authoritative value depending on
7336    * the *_set flags.
7337    */
7338
7339   if (!priv->needs_width_request)
7340     {
7341       found_in_cache =
7342         _clutter_actor_get_cached_size_request (for_height,
7343                                                 priv->width_requests,
7344                                                 &cached_size_request);
7345     }
7346   else
7347     {
7348       /* if the actor needs a width request we use the first slot */
7349       found_in_cache = FALSE;
7350       cached_size_request = &priv->width_requests[0];
7351     }
7352
7353   if (!found_in_cache)
7354     {
7355       gfloat minimum_width, natural_width;
7356       ClutterActorClass *klass;
7357
7358       minimum_width = natural_width = 0;
7359
7360       /* adjust for the margin */
7361       if (for_height >= 0)
7362         {
7363           for_height -= (info->margin.top + info->margin.bottom);
7364           if (for_height < 0)
7365             for_height = 0;
7366         }
7367
7368       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7369
7370       klass = CLUTTER_ACTOR_GET_CLASS (self);
7371       klass->get_preferred_width (self, for_height,
7372                                   &minimum_width,
7373                                   &natural_width);
7374
7375       /* adjust for the margin */
7376       minimum_width += (info->margin.left + info->margin.right);
7377       natural_width += (info->margin.left + info->margin.right);
7378
7379       /* Due to accumulated float errors, it's better not to warn
7380        * on this, but just fix it.
7381        */
7382       if (natural_width < minimum_width)
7383         natural_width = minimum_width;
7384
7385       cached_size_request->min_size = minimum_width;
7386       cached_size_request->natural_size = natural_width;
7387       cached_size_request->for_size = for_height;
7388       cached_size_request->age = priv->cached_width_age;
7389
7390       priv->cached_width_age += 1;
7391       priv->needs_width_request = FALSE;
7392     }
7393
7394   if (!priv->min_width_set)
7395     request_min_width = cached_size_request->min_size;
7396   else
7397     request_min_width = info->min_width;
7398
7399   if (!priv->natural_width_set)
7400     request_natural_width = cached_size_request->natural_size;
7401   else
7402     request_natural_width = info->natural_width;
7403
7404   if (min_width_p)
7405     *min_width_p = request_min_width;
7406
7407   if (natural_width_p)
7408     *natural_width_p = request_natural_width;
7409 }
7410
7411 /**
7412  * clutter_actor_get_preferred_height:
7413  * @self: A #ClutterActor
7414  * @for_width: available width to assume in computing desired height,
7415  *   or a negative value to indicate that no width is defined
7416  * @min_height_p: (out) (allow-none): return location for minimum height,
7417  *   or %NULL
7418  * @natural_height_p: (out) (allow-none): return location for natural
7419  *   height, or %NULL
7420  *
7421  * Computes the requested minimum and natural heights for an actor,
7422  * or if they are already computed, returns the cached values.
7423  *
7424  * An actor may not get its request - depending on the layout
7425  * manager that's in effect.
7426  *
7427  * A request should not incorporate the actor's scale or anchor point;
7428  * those transformations do not affect layout, only rendering.
7429  *
7430  * Since: 0.8
7431  */
7432 void
7433 clutter_actor_get_preferred_height (ClutterActor *self,
7434                                     gfloat        for_width,
7435                                     gfloat       *min_height_p,
7436                                     gfloat       *natural_height_p)
7437 {
7438   float request_min_height, request_natural_height;
7439   SizeRequest *cached_size_request;
7440   const ClutterLayoutInfo *info;
7441   ClutterActorPrivate *priv;
7442   gboolean found_in_cache;
7443
7444   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7445
7446   priv = self->priv;
7447
7448   info = _clutter_actor_get_layout_info_or_defaults (self);
7449
7450   /* we shortcircuit the case of a fixed size set using set_height() */
7451   if (priv->min_height_set && priv->natural_height_set)
7452     {
7453       if (min_height_p != NULL)
7454         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7455
7456       if (natural_height_p != NULL)
7457         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7458
7459       return;
7460     }
7461
7462   /* the remaining cases are:
7463    *
7464    *   - either min_height or natural_height have been set
7465    *   - neither min_height or natural_height have been set
7466    *
7467    * in both cases, we go through the cache (and through the actor in case
7468    * of cache misses) and determine the authoritative value depending on
7469    * the *_set flags.
7470    */
7471
7472   if (!priv->needs_height_request)
7473     {
7474       found_in_cache =
7475         _clutter_actor_get_cached_size_request (for_width,
7476                                                 priv->height_requests,
7477                                                 &cached_size_request);
7478     }
7479   else
7480     {
7481       found_in_cache = FALSE;
7482       cached_size_request = &priv->height_requests[0];
7483     }
7484
7485   if (!found_in_cache)
7486     {
7487       gfloat minimum_height, natural_height;
7488       ClutterActorClass *klass;
7489
7490       minimum_height = natural_height = 0;
7491
7492       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7493
7494       /* adjust for margin */
7495       if (for_width >= 0)
7496         {
7497           for_width -= (info->margin.left + info->margin.right);
7498           if (for_width < 0)
7499             for_width = 0;
7500         }
7501
7502       klass = CLUTTER_ACTOR_GET_CLASS (self);
7503       klass->get_preferred_height (self, for_width,
7504                                    &minimum_height,
7505                                    &natural_height);
7506
7507       /* adjust for margin */
7508       minimum_height += (info->margin.top + info->margin.bottom);
7509       natural_height += (info->margin.top + info->margin.bottom);
7510
7511       /* Due to accumulated float errors, it's better not to warn
7512        * on this, but just fix it.
7513        */
7514       if (natural_height < minimum_height)
7515         natural_height = minimum_height;
7516
7517       cached_size_request->min_size = minimum_height;
7518       cached_size_request->natural_size = natural_height;
7519       cached_size_request->for_size = for_width;
7520       cached_size_request->age = priv->cached_height_age;
7521
7522       priv->cached_height_age += 1;
7523       priv->needs_height_request = FALSE;
7524     }
7525
7526   if (!priv->min_height_set)
7527     request_min_height = cached_size_request->min_size;
7528   else
7529     request_min_height = info->min_height;
7530
7531   if (!priv->natural_height_set)
7532     request_natural_height = cached_size_request->natural_size;
7533   else
7534     request_natural_height = info->natural_height;
7535
7536   if (min_height_p)
7537     *min_height_p = request_min_height;
7538
7539   if (natural_height_p)
7540     *natural_height_p = request_natural_height;
7541 }
7542
7543 /**
7544  * clutter_actor_get_allocation_box:
7545  * @self: A #ClutterActor
7546  * @box: (out): the function fills this in with the actor's allocation
7547  *
7548  * Gets the layout box an actor has been assigned. The allocation can
7549  * only be assumed valid inside a paint() method; anywhere else, it
7550  * may be out-of-date.
7551  *
7552  * An allocation does not incorporate the actor's scale or anchor point;
7553  * those transformations do not affect layout, only rendering.
7554  *
7555  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7556  * of functions inside the implementation of the get_preferred_width()
7557  * or get_preferred_height() virtual functions.</note>
7558  *
7559  * Since: 0.8
7560  */
7561 void
7562 clutter_actor_get_allocation_box (ClutterActor    *self,
7563                                   ClutterActorBox *box)
7564 {
7565   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7566
7567   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7568    * which limits calling get_allocation to inside paint() basically; or
7569    * we can 2) force a layout, which could be expensive if someone calls
7570    * get_allocation somewhere silly; or we can 3) just return the latest
7571    * value, allowing it to be out-of-date, and assume people know what
7572    * they are doing.
7573    *
7574    * The least-surprises approach that keeps existing code working is
7575    * likely to be 2). People can end up doing some inefficient things,
7576    * though, and in general code that requires 2) is probably broken.
7577    */
7578
7579   /* this implements 2) */
7580   if (G_UNLIKELY (self->priv->needs_allocation))
7581     {
7582       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7583
7584       /* do not queue a relayout on an unparented actor */
7585       if (stage)
7586         _clutter_stage_maybe_relayout (stage);
7587     }
7588
7589   /* commenting out the code above and just keeping this assigment
7590    * implements 3)
7591    */
7592   *box = self->priv->allocation;
7593 }
7594
7595 /**
7596  * clutter_actor_get_allocation_geometry:
7597  * @self: A #ClutterActor
7598  * @geom: (out): allocation geometry in pixels
7599  *
7600  * Gets the layout box an actor has been assigned.  The allocation can
7601  * only be assumed valid inside a paint() method; anywhere else, it
7602  * may be out-of-date.
7603  *
7604  * An allocation does not incorporate the actor's scale or anchor point;
7605  * those transformations do not affect layout, only rendering.
7606  *
7607  * The returned rectangle is in pixels.
7608  *
7609  * Since: 0.8
7610  */
7611 void
7612 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7613                                        ClutterGeometry *geom)
7614 {
7615   ClutterActorBox box;
7616
7617   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7618   g_return_if_fail (geom != NULL);
7619
7620   clutter_actor_get_allocation_box (self, &box);
7621
7622   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7623   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7624   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7625   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7626 }
7627
7628 static void
7629 clutter_actor_update_constraints (ClutterActor    *self,
7630                                   ClutterActorBox *allocation)
7631 {
7632   ClutterActorPrivate *priv = self->priv;
7633   const GList *constraints, *l;
7634
7635   if (priv->constraints == NULL)
7636     return;
7637
7638   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7639   for (l = constraints; l != NULL; l = l->next)
7640     {
7641       ClutterConstraint *constraint = l->data;
7642       ClutterActorMeta *meta = l->data;
7643
7644       if (clutter_actor_meta_get_enabled (meta))
7645         {
7646           _clutter_constraint_update_allocation (constraint,
7647                                                  self,
7648                                                  allocation);
7649         }
7650     }
7651 }
7652
7653 /*< private >
7654  * clutter_actor_adjust_allocation:
7655  * @self: a #ClutterActor
7656  * @allocation: (inout): the allocation to adjust
7657  *
7658  * Adjusts the passed allocation box taking into account the actor's
7659  * layout information, like alignment, expansion, and margin.
7660  */
7661 static void
7662 clutter_actor_adjust_allocation (ClutterActor    *self,
7663                                  ClutterActorBox *allocation)
7664 {
7665   ClutterActorBox adj_allocation;
7666   float alloc_width, alloc_height;
7667   float min_width, min_height;
7668   float nat_width, nat_height;
7669   ClutterRequestMode req_mode;
7670
7671   adj_allocation = *allocation;
7672
7673   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7674
7675   /* we want to hit the cache, so we use the public API */
7676   req_mode = clutter_actor_get_request_mode (self);
7677
7678   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7679     {
7680       clutter_actor_get_preferred_width (self, -1,
7681                                          &min_width,
7682                                          &nat_width);
7683       clutter_actor_get_preferred_height (self, alloc_width,
7684                                           &min_height,
7685                                           &nat_height);
7686     }
7687   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7688     {
7689       clutter_actor_get_preferred_height (self, -1,
7690                                           &min_height,
7691                                           &nat_height);
7692       clutter_actor_get_preferred_height (self, alloc_height,
7693                                           &min_width,
7694                                           &nat_width);
7695     }
7696
7697 #ifdef CLUTTER_ENABLE_DEBUG
7698   /* warn about underallocations */
7699   if (_clutter_diagnostic_enabled () &&
7700       (floorf (min_width - alloc_width) > 0 ||
7701        floorf (min_height - alloc_height) > 0))
7702     {
7703       ClutterActor *parent = clutter_actor_get_parent (self);
7704
7705       /* the only actors that are allowed to be underallocated are the Stage,
7706        * as it doesn't have an implicit size, and Actors that specifically
7707        * told us that they want to opt-out from layout control mechanisms
7708        * through the NO_LAYOUT escape hatch.
7709        */
7710       if (parent != NULL &&
7711           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7712         {
7713           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7714                      "of %.2f x %.2f from its parent actor '%s', but its "
7715                      "requested minimum size is of %.2f x %.2f",
7716                      _clutter_actor_get_debug_name (self),
7717                      alloc_width, alloc_height,
7718                      _clutter_actor_get_debug_name (parent),
7719                      min_width, min_height);
7720         }
7721     }
7722 #endif
7723
7724   clutter_actor_adjust_width (self,
7725                               &min_width,
7726                               &nat_width,
7727                               &adj_allocation.x1,
7728                               &adj_allocation.x2);
7729
7730   clutter_actor_adjust_height (self,
7731                                &min_height,
7732                                &nat_height,
7733                                &adj_allocation.y1,
7734                                &adj_allocation.y2);
7735
7736   /* we maintain the invariant that an allocation cannot be adjusted
7737    * to be outside the parent-given box
7738    */
7739   if (adj_allocation.x1 < allocation->x1 ||
7740       adj_allocation.y1 < allocation->y1 ||
7741       adj_allocation.x2 > allocation->x2 ||
7742       adj_allocation.y2 > allocation->y2)
7743     {
7744       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7745                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7746                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7747                  _clutter_actor_get_debug_name (self),
7748                  adj_allocation.x1, adj_allocation.y1,
7749                  adj_allocation.x2 - adj_allocation.x1,
7750                  adj_allocation.y2 - adj_allocation.y1,
7751                  allocation->x1, allocation->y1,
7752                  allocation->x2 - allocation->x1,
7753                  allocation->y2 - allocation->y1);
7754       return;
7755     }
7756
7757   *allocation = adj_allocation;
7758 }
7759
7760 /**
7761  * clutter_actor_allocate:
7762  * @self: A #ClutterActor
7763  * @box: new allocation of the actor, in parent-relative coordinates
7764  * @flags: flags that control the allocation
7765  *
7766  * Called by the parent of an actor to assign the actor its size.
7767  * Should never be called by applications (except when implementing
7768  * a container or layout manager).
7769  *
7770  * Actors can know from their allocation box whether they have moved
7771  * with respect to their parent actor. The @flags parameter describes
7772  * additional information about the allocation, for instance whether
7773  * the parent has moved with respect to the stage, for example because
7774  * a grandparent's origin has moved.
7775  *
7776  * Since: 0.8
7777  */
7778 void
7779 clutter_actor_allocate (ClutterActor           *self,
7780                         const ClutterActorBox  *box,
7781                         ClutterAllocationFlags  flags)
7782 {
7783   ClutterActorPrivate *priv;
7784   ClutterActorClass *klass;
7785   ClutterActorBox old_allocation, real_allocation;
7786   gboolean origin_changed, child_moved, size_changed;
7787   gboolean stage_allocation_changed;
7788
7789   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7790   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
7791     {
7792       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
7793                  "which isn't a descendent of the stage!\n",
7794                  self, _clutter_actor_get_debug_name (self));
7795       return;
7796     }
7797
7798   priv = self->priv;
7799
7800   old_allocation = priv->allocation;
7801   real_allocation = *box;
7802
7803   /* constraints are allowed to modify the allocation only here; we do
7804    * this prior to all the other checks so that we can bail out if the
7805    * allocation did not change
7806    */
7807   clutter_actor_update_constraints (self, &real_allocation);
7808
7809   /* adjust the allocation depending on the align/margin properties */
7810   clutter_actor_adjust_allocation (self, &real_allocation);
7811
7812   if (real_allocation.x2 < real_allocation.x1 ||
7813       real_allocation.y2 < real_allocation.y1)
7814     {
7815       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
7816                  _clutter_actor_get_debug_name (self),
7817                  real_allocation.x2 - real_allocation.x1,
7818                  real_allocation.y2 - real_allocation.y1);
7819     }
7820
7821   /* we allow 0-sized actors, but not negative-sized ones */
7822   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
7823   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
7824
7825   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
7826
7827   child_moved = (real_allocation.x1 != old_allocation.x1 ||
7828                  real_allocation.y1 != old_allocation.y1);
7829
7830   size_changed = (real_allocation.x2 != old_allocation.x2 ||
7831                   real_allocation.y2 != old_allocation.y2);
7832
7833   if (origin_changed || child_moved || size_changed)
7834     stage_allocation_changed = TRUE;
7835   else
7836     stage_allocation_changed = FALSE;
7837
7838   /* If we get an allocation "out of the blue"
7839    * (we did not queue relayout), then we want to
7840    * ignore it. But if we have needs_allocation set,
7841    * we want to guarantee that allocate() virtual
7842    * method is always called, i.e. that queue_relayout()
7843    * always results in an allocate() invocation on
7844    * an actor.
7845    *
7846    * The optimization here is to avoid re-allocating
7847    * actors that did not queue relayout and were
7848    * not moved.
7849    */
7850   if (!priv->needs_allocation && !stage_allocation_changed)
7851     {
7852       CLUTTER_NOTE (LAYOUT, "No allocation needed");
7853       return;
7854     }
7855
7856   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
7857    * clutter_actor_allocate(), it indicates whether the parent has its
7858    * absolute origin moved; when passed in to ClutterActor::allocate()
7859    * virtual method though, it indicates whether the child has its
7860    * absolute origin moved.  So we set it when child_moved is TRUE
7861    */
7862   if (child_moved)
7863     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
7864
7865   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7866
7867   klass = CLUTTER_ACTOR_GET_CLASS (self);
7868   klass->allocate (self, &real_allocation, flags);
7869
7870   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7871
7872   if (stage_allocation_changed)
7873     clutter_actor_queue_redraw (self);
7874 }
7875
7876 /**
7877  * clutter_actor_set_allocation:
7878  * @self: a #ClutterActor
7879  * @box: a #ClutterActorBox
7880  * @flags: allocation flags
7881  *
7882  * Stores the allocation of @self as defined by @box.
7883  *
7884  * This function can only be called from within the implementation of
7885  * the #ClutterActorClass.allocate() virtual function.
7886  *
7887  * The allocation should have been adjusted to take into account constraints,
7888  * alignment, and margin properties. If you are implementing a #ClutterActor
7889  * subclass that provides its own layout management policy for its children
7890  * instead of using a #ClutterLayoutManager delegate, you should not call
7891  * this function on the children of @self; instead, you should call
7892  * clutter_actor_allocate(), which will adjust the allocation box for
7893  * you.
7894  *
7895  * This function should only be used by subclasses of #ClutterActor
7896  * that wish to store their allocation but cannot chain up to the
7897  * parent's implementation; the default implementation of the
7898  * #ClutterActorClass.allocate() virtual function will call this
7899  * function.
7900  *
7901  * It is important to note that, while chaining up was the recommended
7902  * behaviour for #ClutterActor subclasses prior to the introduction of
7903  * this function, it is recommended to call clutter_actor_set_allocation()
7904  * instead.
7905  *
7906  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
7907  * to handle the allocation of its children, this function will call
7908  * the clutter_layout_manager_allocate() function only if the
7909  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
7910  * expected that the subclass will call clutter_layout_manager_allocate()
7911  * by itself. For instance, the following code:
7912  *
7913  * |[
7914  * static void
7915  * my_actor_allocate (ClutterActor *actor,
7916  *                    const ClutterActorBox *allocation,
7917  *                    ClutterAllocationFlags flags)
7918  * {
7919  *   ClutterActorBox new_alloc;
7920  *   ClutterAllocationFlags new_flags;
7921  *
7922  *   adjust_allocation (allocation, &amp;new_alloc);
7923  *
7924  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
7925  *
7926  *   /&ast; this will use the layout manager set on the actor &ast;/
7927  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
7928  * }
7929  * ]|
7930  *
7931  * is equivalent to this:
7932  *
7933  * |[
7934  * static void
7935  * my_actor_allocate (ClutterActor *actor,
7936  *                    const ClutterActorBox *allocation,
7937  *                    ClutterAllocationFlags flags)
7938  * {
7939  *   ClutterLayoutManager *layout;
7940  *   ClutterActorBox new_alloc;
7941  *
7942  *   adjust_allocation (allocation, &amp;new_alloc);
7943  *
7944  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
7945  *
7946  *   layout = clutter_actor_get_layout_manager (actor);
7947  *   clutter_layout_manager_allocate (layout,
7948  *                                    CLUTTER_CONTAINER (actor),
7949  *                                    &amp;new_alloc,
7950  *                                    flags);
7951  * }
7952  * ]|
7953  *
7954  * Since: 1.10
7955  */
7956 void
7957 clutter_actor_set_allocation (ClutterActor           *self,
7958                               const ClutterActorBox  *box,
7959                               ClutterAllocationFlags  flags)
7960 {
7961   ClutterActorPrivate *priv;
7962   gboolean changed;
7963
7964   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7965   g_return_if_fail (box != NULL);
7966
7967   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
7968     {
7969       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
7970                   "can only be called from within the implementation of "
7971                   "the ClutterActor::allocate() virtual function.");
7972       return;
7973     }
7974
7975   priv = self->priv;
7976
7977   g_object_freeze_notify (G_OBJECT (self));
7978
7979   changed = clutter_actor_set_allocation_internal (self, box, flags);
7980
7981   /* we allocate our children before we notify changes in our geometry,
7982    * so that people connecting to properties will be able to get valid
7983    * data out of the sub-tree of the scene graph that has this actor at
7984    * the root.
7985    */
7986   clutter_actor_maybe_layout_children (self, box, flags);
7987
7988   if (changed)
7989     {
7990       ClutterActorBox signal_box = priv->allocation;
7991       ClutterAllocationFlags signal_flags = priv->allocation_flags;
7992
7993       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
7994                      &signal_box,
7995                      signal_flags);
7996     }
7997
7998   g_object_thaw_notify (G_OBJECT (self));
7999 }
8000
8001 /**
8002  * clutter_actor_set_geometry:
8003  * @self: A #ClutterActor
8004  * @geometry: A #ClutterGeometry
8005  *
8006  * Sets the actor's fixed position and forces its minimum and natural
8007  * size, in pixels. This means the untransformed actor will have the
8008  * given geometry. This is the same as calling clutter_actor_set_position()
8009  * and clutter_actor_set_size().
8010  *
8011  * Deprecated: 1.10: Use clutter_actor_set_position() and
8012  *   clutter_actor_set_size() instead.
8013  */
8014 void
8015 clutter_actor_set_geometry (ClutterActor          *self,
8016                             const ClutterGeometry *geometry)
8017 {
8018   g_object_freeze_notify (G_OBJECT (self));
8019
8020   clutter_actor_set_position (self, geometry->x, geometry->y);
8021   clutter_actor_set_size (self, geometry->width, geometry->height);
8022
8023   g_object_thaw_notify (G_OBJECT (self));
8024 }
8025
8026 /**
8027  * clutter_actor_get_geometry:
8028  * @self: A #ClutterActor
8029  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8030  *
8031  * Gets the size and position of an actor relative to its parent
8032  * actor. This is the same as calling clutter_actor_get_position() and
8033  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8034  * requested size and position if the actor's allocation is invalid.
8035  *
8036  * Deprecated: 1.10: Use clutter_actor_get_position() and
8037  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8038  *   instead.
8039  */
8040 void
8041 clutter_actor_get_geometry (ClutterActor    *self,
8042                             ClutterGeometry *geometry)
8043 {
8044   gfloat x, y, width, height;
8045
8046   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8047   g_return_if_fail (geometry != NULL);
8048
8049   clutter_actor_get_position (self, &x, &y);
8050   clutter_actor_get_size (self, &width, &height);
8051
8052   geometry->x = (int) x;
8053   geometry->y = (int) y;
8054   geometry->width = (int) width;
8055   geometry->height = (int) height;
8056 }
8057
8058 /**
8059  * clutter_actor_set_position:
8060  * @self: A #ClutterActor
8061  * @x: New left position of actor in pixels.
8062  * @y: New top position of actor in pixels.
8063  *
8064  * Sets the actor's fixed position in pixels relative to any parent
8065  * actor.
8066  *
8067  * If a layout manager is in use, this position will override the
8068  * layout manager and force a fixed position.
8069  */
8070 void
8071 clutter_actor_set_position (ClutterActor *self,
8072                             gfloat        x,
8073                             gfloat        y)
8074 {
8075   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8076
8077   g_object_freeze_notify (G_OBJECT (self));
8078
8079   clutter_actor_set_x (self, x);
8080   clutter_actor_set_y (self, y);
8081
8082   g_object_thaw_notify (G_OBJECT (self));
8083 }
8084
8085 /**
8086  * clutter_actor_get_fixed_position_set:
8087  * @self: A #ClutterActor
8088  *
8089  * Checks whether an actor has a fixed position set (and will thus be
8090  * unaffected by any layout manager).
8091  *
8092  * Return value: %TRUE if the fixed position is set on the actor
8093  *
8094  * Since: 0.8
8095  */
8096 gboolean
8097 clutter_actor_get_fixed_position_set (ClutterActor *self)
8098 {
8099   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8100
8101   return self->priv->position_set;
8102 }
8103
8104 /**
8105  * clutter_actor_set_fixed_position_set:
8106  * @self: A #ClutterActor
8107  * @is_set: whether to use fixed position
8108  *
8109  * Sets whether an actor has a fixed position set (and will thus be
8110  * unaffected by any layout manager).
8111  *
8112  * Since: 0.8
8113  */
8114 void
8115 clutter_actor_set_fixed_position_set (ClutterActor *self,
8116                                       gboolean      is_set)
8117 {
8118   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8119
8120   if (self->priv->position_set == (is_set != FALSE))
8121     return;
8122
8123   self->priv->position_set = is_set != FALSE;
8124   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8125
8126   clutter_actor_queue_relayout (self);
8127 }
8128
8129 /**
8130  * clutter_actor_move_by:
8131  * @self: A #ClutterActor
8132  * @dx: Distance to move Actor on X axis.
8133  * @dy: Distance to move Actor on Y axis.
8134  *
8135  * Moves an actor by the specified distance relative to its current
8136  * position in pixels.
8137  *
8138  * This function modifies the fixed position of an actor and thus removes
8139  * it from any layout management. Another way to move an actor is with an
8140  * anchor point, see clutter_actor_set_anchor_point().
8141  *
8142  * Since: 0.2
8143  */
8144 void
8145 clutter_actor_move_by (ClutterActor *self,
8146                        gfloat        dx,
8147                        gfloat        dy)
8148 {
8149   const ClutterLayoutInfo *info;
8150   gfloat x, y;
8151
8152   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8153
8154   info = _clutter_actor_get_layout_info_or_defaults (self);
8155   x = info->fixed_x;
8156   y = info->fixed_y;
8157
8158   clutter_actor_set_position (self, x + dx, y + dy);
8159 }
8160
8161 static void
8162 clutter_actor_set_min_width (ClutterActor *self,
8163                              gfloat        min_width)
8164 {
8165   ClutterActorPrivate *priv = self->priv;
8166   ClutterActorBox old = { 0, };
8167   ClutterLayoutInfo *info;
8168
8169   /* if we are setting the size on a top-level actor and the
8170    * backend only supports static top-levels (e.g. framebuffers)
8171    * then we ignore the passed value and we override it with
8172    * the stage implementation's preferred size.
8173    */
8174   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8175       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8176     return;
8177
8178   info = _clutter_actor_get_layout_info (self);
8179
8180   if (priv->min_width_set && min_width == info->min_width)
8181     return;
8182
8183   g_object_freeze_notify (G_OBJECT (self));
8184
8185   clutter_actor_store_old_geometry (self, &old);
8186
8187   info->min_width = min_width;
8188   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8189   clutter_actor_set_min_width_set (self, TRUE);
8190
8191   clutter_actor_notify_if_geometry_changed (self, &old);
8192
8193   g_object_thaw_notify (G_OBJECT (self));
8194
8195   clutter_actor_queue_relayout (self);
8196 }
8197
8198 static void
8199 clutter_actor_set_min_height (ClutterActor *self,
8200                               gfloat        min_height)
8201
8202 {
8203   ClutterActorPrivate *priv = self->priv;
8204   ClutterActorBox old = { 0, };
8205   ClutterLayoutInfo *info;
8206
8207   /* if we are setting the size on a top-level actor and the
8208    * backend only supports static top-levels (e.g. framebuffers)
8209    * then we ignore the passed value and we override it with
8210    * the stage implementation's preferred size.
8211    */
8212   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8213       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8214     return;
8215
8216   info = _clutter_actor_get_layout_info (self);
8217
8218   if (priv->min_height_set && min_height == info->min_height)
8219     return;
8220
8221   g_object_freeze_notify (G_OBJECT (self));
8222
8223   clutter_actor_store_old_geometry (self, &old);
8224
8225   info->min_height = min_height;
8226   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8227   clutter_actor_set_min_height_set (self, TRUE);
8228
8229   clutter_actor_notify_if_geometry_changed (self, &old);
8230
8231   g_object_thaw_notify (G_OBJECT (self));
8232
8233   clutter_actor_queue_relayout (self);
8234 }
8235
8236 static void
8237 clutter_actor_set_natural_width (ClutterActor *self,
8238                                  gfloat        natural_width)
8239 {
8240   ClutterActorPrivate *priv = self->priv;
8241   ClutterActorBox old = { 0, };
8242   ClutterLayoutInfo *info;
8243
8244   /* if we are setting the size on a top-level actor and the
8245    * backend only supports static top-levels (e.g. framebuffers)
8246    * then we ignore the passed value and we override it with
8247    * the stage implementation's preferred size.
8248    */
8249   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8250       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8251     return;
8252
8253   info = _clutter_actor_get_layout_info (self);
8254
8255   if (priv->natural_width_set && natural_width == info->natural_width)
8256     return;
8257
8258   g_object_freeze_notify (G_OBJECT (self));
8259
8260   clutter_actor_store_old_geometry (self, &old);
8261
8262   info->natural_width = natural_width;
8263   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8264   clutter_actor_set_natural_width_set (self, TRUE);
8265
8266   clutter_actor_notify_if_geometry_changed (self, &old);
8267
8268   g_object_thaw_notify (G_OBJECT (self));
8269
8270   clutter_actor_queue_relayout (self);
8271 }
8272
8273 static void
8274 clutter_actor_set_natural_height (ClutterActor *self,
8275                                   gfloat        natural_height)
8276 {
8277   ClutterActorPrivate *priv = self->priv;
8278   ClutterActorBox old = { 0, };
8279   ClutterLayoutInfo *info;
8280
8281   /* if we are setting the size on a top-level actor and the
8282    * backend only supports static top-levels (e.g. framebuffers)
8283    * then we ignore the passed value and we override it with
8284    * the stage implementation's preferred size.
8285    */
8286   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8287       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8288     return;
8289
8290   info = _clutter_actor_get_layout_info (self);
8291
8292   if (priv->natural_height_set && natural_height == info->natural_height)
8293     return;
8294
8295   g_object_freeze_notify (G_OBJECT (self));
8296
8297   clutter_actor_store_old_geometry (self, &old);
8298
8299   info->natural_height = natural_height;
8300   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8301   clutter_actor_set_natural_height_set (self, TRUE);
8302
8303   clutter_actor_notify_if_geometry_changed (self, &old);
8304
8305   g_object_thaw_notify (G_OBJECT (self));
8306
8307   clutter_actor_queue_relayout (self);
8308 }
8309
8310 static void
8311 clutter_actor_set_min_width_set (ClutterActor *self,
8312                                  gboolean      use_min_width)
8313 {
8314   ClutterActorPrivate *priv = self->priv;
8315   ClutterActorBox old = { 0, };
8316
8317   if (priv->min_width_set == (use_min_width != FALSE))
8318     return;
8319
8320   clutter_actor_store_old_geometry (self, &old);
8321
8322   priv->min_width_set = use_min_width != FALSE;
8323   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8324
8325   clutter_actor_notify_if_geometry_changed (self, &old);
8326
8327   clutter_actor_queue_relayout (self);
8328 }
8329
8330 static void
8331 clutter_actor_set_min_height_set (ClutterActor *self,
8332                                   gboolean      use_min_height)
8333 {
8334   ClutterActorPrivate *priv = self->priv;
8335   ClutterActorBox old = { 0, };
8336
8337   if (priv->min_height_set == (use_min_height != FALSE))
8338     return;
8339
8340   clutter_actor_store_old_geometry (self, &old);
8341
8342   priv->min_height_set = use_min_height != FALSE;
8343   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8344
8345   clutter_actor_notify_if_geometry_changed (self, &old);
8346
8347   clutter_actor_queue_relayout (self);
8348 }
8349
8350 static void
8351 clutter_actor_set_natural_width_set (ClutterActor *self,
8352                                      gboolean      use_natural_width)
8353 {
8354   ClutterActorPrivate *priv = self->priv;
8355   ClutterActorBox old = { 0, };
8356
8357   if (priv->natural_width_set == (use_natural_width != FALSE))
8358     return;
8359
8360   clutter_actor_store_old_geometry (self, &old);
8361
8362   priv->natural_width_set = use_natural_width != FALSE;
8363   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8364
8365   clutter_actor_notify_if_geometry_changed (self, &old);
8366
8367   clutter_actor_queue_relayout (self);
8368 }
8369
8370 static void
8371 clutter_actor_set_natural_height_set (ClutterActor *self,
8372                                       gboolean      use_natural_height)
8373 {
8374   ClutterActorPrivate *priv = self->priv;
8375   ClutterActorBox old = { 0, };
8376
8377   if (priv->natural_height_set == (use_natural_height != FALSE))
8378     return;
8379
8380   clutter_actor_store_old_geometry (self, &old);
8381
8382   priv->natural_height_set = use_natural_height != FALSE;
8383   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8384
8385   clutter_actor_notify_if_geometry_changed (self, &old);
8386
8387   clutter_actor_queue_relayout (self);
8388 }
8389
8390 /**
8391  * clutter_actor_set_request_mode:
8392  * @self: a #ClutterActor
8393  * @mode: the request mode
8394  *
8395  * Sets the geometry request mode of @self.
8396  *
8397  * The @mode determines the order for invoking
8398  * clutter_actor_get_preferred_width() and
8399  * clutter_actor_get_preferred_height()
8400  *
8401  * Since: 1.2
8402  */
8403 void
8404 clutter_actor_set_request_mode (ClutterActor       *self,
8405                                 ClutterRequestMode  mode)
8406 {
8407   ClutterActorPrivate *priv;
8408
8409   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8410
8411   priv = self->priv;
8412
8413   if (priv->request_mode == mode)
8414     return;
8415
8416   priv->request_mode = mode;
8417
8418   priv->needs_width_request = TRUE;
8419   priv->needs_height_request = TRUE;
8420
8421   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8422
8423   clutter_actor_queue_relayout (self);
8424 }
8425
8426 /**
8427  * clutter_actor_get_request_mode:
8428  * @self: a #ClutterActor
8429  *
8430  * Retrieves the geometry request mode of @self
8431  *
8432  * Return value: the request mode for the actor
8433  *
8434  * Since: 1.2
8435  */
8436 ClutterRequestMode
8437 clutter_actor_get_request_mode (ClutterActor *self)
8438 {
8439   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8440                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8441
8442   return self->priv->request_mode;
8443 }
8444
8445 /* variant of set_width() without checks and without notification
8446  * freeze+thaw, for internal usage only
8447  */
8448 static inline void
8449 clutter_actor_set_width_internal (ClutterActor *self,
8450                                   gfloat        width)
8451 {
8452   if (width >= 0)
8453     {
8454       /* the Stage will use the :min-width to control the minimum
8455        * width to be resized to, so we should not be setting it
8456        * along with the :natural-width
8457        */
8458       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8459         clutter_actor_set_min_width (self, width);
8460
8461       clutter_actor_set_natural_width (self, width);
8462     }
8463   else
8464     {
8465       /* we only unset the :natural-width for the Stage */
8466       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8467         clutter_actor_set_min_width_set (self, FALSE);
8468
8469       clutter_actor_set_natural_width_set (self, FALSE);
8470     }
8471 }
8472
8473 /* variant of set_height() without checks and without notification
8474  * freeze+thaw, for internal usage only
8475  */
8476 static inline void
8477 clutter_actor_set_height_internal (ClutterActor *self,
8478                                    gfloat        height)
8479 {
8480   if (height >= 0)
8481     {
8482       /* see the comment above in set_width_internal() */
8483       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8484         clutter_actor_set_min_height (self, height);
8485
8486       clutter_actor_set_natural_height (self, height);
8487     }
8488   else
8489     {
8490       /* see the comment above in set_width_internal() */
8491       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8492         clutter_actor_set_min_height_set (self, FALSE);
8493
8494       clutter_actor_set_natural_height_set (self, FALSE);
8495     }
8496 }
8497
8498 /**
8499  * clutter_actor_set_size:
8500  * @self: A #ClutterActor
8501  * @width: New width of actor in pixels, or -1
8502  * @height: New height of actor in pixels, or -1
8503  *
8504  * Sets the actor's size request in pixels. This overrides any
8505  * "normal" size request the actor would have. For example
8506  * a text actor might normally request the size of the text;
8507  * this function would force a specific size instead.
8508  *
8509  * If @width and/or @height are -1 the actor will use its
8510  * "normal" size request instead of overriding it, i.e.
8511  * you can "unset" the size with -1.
8512  *
8513  * This function sets or unsets both the minimum and natural size.
8514  */
8515 void
8516 clutter_actor_set_size (ClutterActor *self,
8517                         gfloat        width,
8518                         gfloat        height)
8519 {
8520   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8521
8522   g_object_freeze_notify (G_OBJECT (self));
8523
8524   clutter_actor_set_width_internal (self, width);
8525   clutter_actor_set_height_internal (self, height);
8526
8527   g_object_thaw_notify (G_OBJECT (self));
8528 }
8529
8530 /**
8531  * clutter_actor_get_size:
8532  * @self: A #ClutterActor
8533  * @width: (out) (allow-none): return location for the width, or %NULL.
8534  * @height: (out) (allow-none): return location for the height, or %NULL.
8535  *
8536  * This function tries to "do what you mean" and return
8537  * the size an actor will have. If the actor has a valid
8538  * allocation, the allocation will be returned; otherwise,
8539  * the actors natural size request will be returned.
8540  *
8541  * If you care whether you get the request vs. the allocation, you
8542  * should probably call a different function like
8543  * clutter_actor_get_allocation_box() or
8544  * clutter_actor_get_preferred_width().
8545  *
8546  * Since: 0.2
8547  */
8548 void
8549 clutter_actor_get_size (ClutterActor *self,
8550                         gfloat       *width,
8551                         gfloat       *height)
8552 {
8553   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8554
8555   if (width)
8556     *width = clutter_actor_get_width (self);
8557
8558   if (height)
8559     *height = clutter_actor_get_height (self);
8560 }
8561
8562 /**
8563  * clutter_actor_get_position:
8564  * @self: a #ClutterActor
8565  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8566  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8567  *
8568  * This function tries to "do what you mean" and tell you where the
8569  * actor is, prior to any transformations. Retrieves the fixed
8570  * position of an actor in pixels, if one has been set; otherwise, if
8571  * the allocation is valid, returns the actor's allocated position;
8572  * otherwise, returns 0,0.
8573  *
8574  * The returned position is in pixels.
8575  *
8576  * Since: 0.6
8577  */
8578 void
8579 clutter_actor_get_position (ClutterActor *self,
8580                             gfloat       *x,
8581                             gfloat       *y)
8582 {
8583   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8584
8585   if (x)
8586     *x = clutter_actor_get_x (self);
8587
8588   if (y)
8589     *y = clutter_actor_get_y (self);
8590 }
8591
8592 /**
8593  * clutter_actor_get_transformed_position:
8594  * @self: A #ClutterActor
8595  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8596  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8597  *
8598  * Gets the absolute position of an actor, in pixels relative to the stage.
8599  *
8600  * Since: 0.8
8601  */
8602 void
8603 clutter_actor_get_transformed_position (ClutterActor *self,
8604                                         gfloat       *x,
8605                                         gfloat       *y)
8606 {
8607   ClutterVertex v1;
8608   ClutterVertex v2;
8609
8610   v1.x = v1.y = v1.z = 0;
8611   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8612
8613   if (x)
8614     *x = v2.x;
8615
8616   if (y)
8617     *y = v2.y;
8618 }
8619
8620 /**
8621  * clutter_actor_get_transformed_size:
8622  * @self: A #ClutterActor
8623  * @width: (out) (allow-none): return location for the width, or %NULL
8624  * @height: (out) (allow-none): return location for the height, or %NULL
8625  *
8626  * Gets the absolute size of an actor in pixels, taking into account the
8627  * scaling factors.
8628  *
8629  * If the actor has a valid allocation, the allocated size will be used.
8630  * If the actor has not a valid allocation then the preferred size will
8631  * be transformed and returned.
8632  *
8633  * If you want the transformed allocation, see
8634  * clutter_actor_get_abs_allocation_vertices() instead.
8635  *
8636  * <note>When the actor (or one of its ancestors) is rotated around the
8637  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8638  * as a generic quadrangle; in that case this function returns the size
8639  * of the smallest rectangle that encapsulates the entire quad. Please
8640  * note that in this case no assumptions can be made about the relative
8641  * position of this envelope to the absolute position of the actor, as
8642  * returned by clutter_actor_get_transformed_position(); if you need this
8643  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8644  * to get the coords of the actual quadrangle.</note>
8645  *
8646  * Since: 0.8
8647  */
8648 void
8649 clutter_actor_get_transformed_size (ClutterActor *self,
8650                                     gfloat       *width,
8651                                     gfloat       *height)
8652 {
8653   ClutterActorPrivate *priv;
8654   ClutterVertex v[4];
8655   gfloat x_min, x_max, y_min, y_max;
8656   gint i;
8657
8658   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8659
8660   priv = self->priv;
8661
8662   /* if the actor hasn't been allocated yet, get the preferred
8663    * size and transform that
8664    */
8665   if (priv->needs_allocation)
8666     {
8667       gfloat natural_width, natural_height;
8668       ClutterActorBox box;
8669
8670       /* Make a fake allocation to transform.
8671        *
8672        * NB: _clutter_actor_transform_and_project_box expects a box in
8673        * the actor's coordinate space... */
8674
8675       box.x1 = 0;
8676       box.y1 = 0;
8677
8678       natural_width = natural_height = 0;
8679       clutter_actor_get_preferred_size (self, NULL, NULL,
8680                                         &natural_width,
8681                                         &natural_height);
8682
8683       box.x2 = natural_width;
8684       box.y2 = natural_height;
8685
8686       _clutter_actor_transform_and_project_box (self, &box, v);
8687     }
8688   else
8689     clutter_actor_get_abs_allocation_vertices (self, v);
8690
8691   x_min = x_max = v[0].x;
8692   y_min = y_max = v[0].y;
8693
8694   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8695     {
8696       if (v[i].x < x_min)
8697         x_min = v[i].x;
8698
8699       if (v[i].x > x_max)
8700         x_max = v[i].x;
8701
8702       if (v[i].y < y_min)
8703         y_min = v[i].y;
8704
8705       if (v[i].y > y_max)
8706         y_max = v[i].y;
8707     }
8708
8709   if (width)
8710     *width  = x_max - x_min;
8711
8712   if (height)
8713     *height = y_max - y_min;
8714 }
8715
8716 /**
8717  * clutter_actor_get_width:
8718  * @self: A #ClutterActor
8719  *
8720  * Retrieves the width of a #ClutterActor.
8721  *
8722  * If the actor has a valid allocation, this function will return the
8723  * width of the allocated area given to the actor.
8724  *
8725  * If the actor does not have a valid allocation, this function will
8726  * return the actor's natural width, that is the preferred width of
8727  * the actor.
8728  *
8729  * If you care whether you get the preferred width or the width that
8730  * has been assigned to the actor, you should probably call a different
8731  * function like clutter_actor_get_allocation_box() to retrieve the
8732  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8733  * preferred width.
8734  *
8735  * If an actor has a fixed width, for instance a width that has been
8736  * assigned using clutter_actor_set_width(), the width returned will
8737  * be the same value.
8738  *
8739  * Return value: the width of the actor, in pixels
8740  */
8741 gfloat
8742 clutter_actor_get_width (ClutterActor *self)
8743 {
8744   ClutterActorPrivate *priv;
8745
8746   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8747
8748   priv = self->priv;
8749
8750   if (priv->needs_allocation)
8751     {
8752       gfloat natural_width = 0;
8753
8754       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8755         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8756       else
8757         {
8758           gfloat natural_height = 0;
8759
8760           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8761           clutter_actor_get_preferred_width (self, natural_height,
8762                                              NULL,
8763                                              &natural_width);
8764         }
8765
8766       return natural_width;
8767     }
8768   else
8769     return priv->allocation.x2 - priv->allocation.x1;
8770 }
8771
8772 /**
8773  * clutter_actor_get_height:
8774  * @self: A #ClutterActor
8775  *
8776  * Retrieves the height of a #ClutterActor.
8777  *
8778  * If the actor has a valid allocation, this function will return the
8779  * height of the allocated area given to the actor.
8780  *
8781  * If the actor does not have a valid allocation, this function will
8782  * return the actor's natural height, that is the preferred height of
8783  * the actor.
8784  *
8785  * If you care whether you get the preferred height or the height that
8786  * has been assigned to the actor, you should probably call a different
8787  * function like clutter_actor_get_allocation_box() to retrieve the
8788  * allocated size or clutter_actor_get_preferred_height() to retrieve the
8789  * preferred height.
8790  *
8791  * If an actor has a fixed height, for instance a height that has been
8792  * assigned using clutter_actor_set_height(), the height returned will
8793  * be the same value.
8794  *
8795  * Return value: the height of the actor, in pixels
8796  */
8797 gfloat
8798 clutter_actor_get_height (ClutterActor *self)
8799 {
8800   ClutterActorPrivate *priv;
8801
8802   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8803
8804   priv = self->priv;
8805
8806   if (priv->needs_allocation)
8807     {
8808       gfloat natural_height = 0;
8809
8810       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8811         {
8812           gfloat natural_width = 0;
8813
8814           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8815           clutter_actor_get_preferred_height (self, natural_width,
8816                                               NULL, &natural_height);
8817         }
8818       else
8819         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8820
8821       return natural_height;
8822     }
8823   else
8824     return priv->allocation.y2 - priv->allocation.y1;
8825 }
8826
8827 /**
8828  * clutter_actor_set_width:
8829  * @self: A #ClutterActor
8830  * @width: Requested new width for the actor, in pixels, or -1
8831  *
8832  * Forces a width on an actor, causing the actor's preferred width
8833  * and height (if any) to be ignored.
8834  *
8835  * If @width is -1 the actor will use its preferred width request
8836  * instead of overriding it, i.e. you can "unset" the width with -1.
8837  *
8838  * This function sets both the minimum and natural size of the actor.
8839  *
8840  * since: 0.2
8841  */
8842 void
8843 clutter_actor_set_width (ClutterActor *self,
8844                          gfloat        width)
8845 {
8846   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8847
8848   g_object_freeze_notify (G_OBJECT (self));
8849
8850   clutter_actor_set_width_internal (self, width);
8851
8852   g_object_thaw_notify (G_OBJECT (self));
8853 }
8854
8855 /**
8856  * clutter_actor_set_height:
8857  * @self: A #ClutterActor
8858  * @height: Requested new height for the actor, in pixels, or -1
8859  *
8860  * Forces a height on an actor, causing the actor's preferred width
8861  * and height (if any) to be ignored.
8862  *
8863  * If @height is -1 the actor will use its preferred height instead of
8864  * overriding it, i.e. you can "unset" the height with -1.
8865  *
8866  * This function sets both the minimum and natural size of the actor.
8867  *
8868  * since: 0.2
8869  */
8870 void
8871 clutter_actor_set_height (ClutterActor *self,
8872                           gfloat        height)
8873 {
8874   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8875
8876   g_object_freeze_notify (G_OBJECT (self));
8877
8878   clutter_actor_set_height_internal (self, height);
8879
8880   g_object_thaw_notify (G_OBJECT (self));
8881 }
8882
8883 /**
8884  * clutter_actor_set_x:
8885  * @self: a #ClutterActor
8886  * @x: the actor's position on the X axis
8887  *
8888  * Sets the actor's X coordinate, relative to its parent, in pixels.
8889  *
8890  * Overrides any layout manager and forces a fixed position for
8891  * the actor.
8892  *
8893  * Since: 0.6
8894  */
8895 void
8896 clutter_actor_set_x (ClutterActor *self,
8897                      gfloat        x)
8898 {
8899   ClutterActorBox old = { 0, };
8900   ClutterActorPrivate *priv;
8901   ClutterLayoutInfo *info;
8902
8903   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8904
8905   priv = self->priv;
8906
8907   info = _clutter_actor_get_layout_info (self);
8908
8909   if (priv->position_set && info->fixed_x == x)
8910     return;
8911
8912   clutter_actor_store_old_geometry (self, &old);
8913
8914   info->fixed_x = x;
8915   clutter_actor_set_fixed_position_set (self, TRUE);
8916
8917   clutter_actor_notify_if_geometry_changed (self, &old);
8918
8919   clutter_actor_queue_relayout (self);
8920 }
8921
8922 /**
8923  * clutter_actor_set_y:
8924  * @self: a #ClutterActor
8925  * @y: the actor's position on the Y axis
8926  *
8927  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
8928  *
8929  * Overrides any layout manager and forces a fixed position for
8930  * the actor.
8931  *
8932  * Since: 0.6
8933  */
8934 void
8935 clutter_actor_set_y (ClutterActor *self,
8936                      gfloat        y)
8937 {
8938   ClutterActorBox old = { 0, };
8939   ClutterActorPrivate *priv;
8940   ClutterLayoutInfo *info;
8941
8942   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8943
8944   priv = self->priv;
8945
8946   info = _clutter_actor_get_layout_info (self);
8947
8948   if (priv->position_set && info->fixed_y == y)
8949     return;
8950
8951   clutter_actor_store_old_geometry (self, &old);
8952
8953   info->fixed_y = y;
8954   clutter_actor_set_fixed_position_set (self, TRUE);
8955
8956   clutter_actor_notify_if_geometry_changed (self, &old);
8957
8958   clutter_actor_queue_relayout (self);
8959 }
8960
8961 /**
8962  * clutter_actor_get_x:
8963  * @self: A #ClutterActor
8964  *
8965  * Retrieves the X coordinate of a #ClutterActor.
8966  *
8967  * This function tries to "do what you mean", by returning the
8968  * correct value depending on the actor's state.
8969  *
8970  * If the actor has a valid allocation, this function will return
8971  * the X coordinate of the origin of the allocation box.
8972  *
8973  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
8974  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8975  * function will return that coordinate.
8976  *
8977  * If both the allocation and a fixed position are missing, this function
8978  * will return 0.
8979  *
8980  * Return value: the X coordinate, in pixels, ignoring any
8981  *   transformation (i.e. scaling, rotation)
8982  */
8983 gfloat
8984 clutter_actor_get_x (ClutterActor *self)
8985 {
8986   ClutterActorPrivate *priv;
8987
8988   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8989
8990   priv = self->priv;
8991
8992   if (priv->needs_allocation)
8993     {
8994       if (priv->position_set)
8995         {
8996           const ClutterLayoutInfo *info;
8997
8998           info = _clutter_actor_get_layout_info_or_defaults (self);
8999
9000           return info->fixed_x;
9001         }
9002       else
9003         return 0;
9004     }
9005   else
9006     return priv->allocation.x1;
9007 }
9008
9009 /**
9010  * clutter_actor_get_y:
9011  * @self: A #ClutterActor
9012  *
9013  * Retrieves the Y coordinate of a #ClutterActor.
9014  *
9015  * This function tries to "do what you mean", by returning the
9016  * correct value depending on the actor's state.
9017  *
9018  * If the actor has a valid allocation, this function will return
9019  * the Y coordinate of the origin of the allocation box.
9020  *
9021  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9022  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9023  * function will return that coordinate.
9024  *
9025  * If both the allocation and a fixed position are missing, this function
9026  * will return 0.
9027  *
9028  * Return value: the Y coordinate, in pixels, ignoring any
9029  *   transformation (i.e. scaling, rotation)
9030  */
9031 gfloat
9032 clutter_actor_get_y (ClutterActor *self)
9033 {
9034   ClutterActorPrivate *priv;
9035
9036   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9037
9038   priv = self->priv;
9039
9040   if (priv->needs_allocation)
9041     {
9042       if (priv->position_set)
9043         {
9044           const ClutterLayoutInfo *info;
9045
9046           info = _clutter_actor_get_layout_info_or_defaults (self);
9047
9048           return info->fixed_y;
9049         }
9050       else
9051         return 0;
9052     }
9053   else
9054     return priv->allocation.y1;
9055 }
9056
9057 /**
9058  * clutter_actor_set_scale:
9059  * @self: A #ClutterActor
9060  * @scale_x: double factor to scale actor by horizontally.
9061  * @scale_y: double factor to scale actor by vertically.
9062  *
9063  * Scales an actor with the given factors. The scaling is relative to
9064  * the scale center and the anchor point. The scale center is
9065  * unchanged by this function and defaults to 0,0.
9066  *
9067  * Since: 0.2
9068  */
9069 void
9070 clutter_actor_set_scale (ClutterActor *self,
9071                          gdouble       scale_x,
9072                          gdouble       scale_y)
9073 {
9074   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9075
9076   g_object_freeze_notify (G_OBJECT (self));
9077
9078   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9079   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9080
9081   g_object_thaw_notify (G_OBJECT (self));
9082 }
9083
9084 /**
9085  * clutter_actor_set_scale_full:
9086  * @self: A #ClutterActor
9087  * @scale_x: double factor to scale actor by horizontally.
9088  * @scale_y: double factor to scale actor by vertically.
9089  * @center_x: X coordinate of the center of the scale.
9090  * @center_y: Y coordinate of the center of the scale
9091  *
9092  * Scales an actor with the given factors around the given center
9093  * point. The center point is specified in pixels relative to the
9094  * anchor point (usually the top left corner of the actor).
9095  *
9096  * Since: 1.0
9097  */
9098 void
9099 clutter_actor_set_scale_full (ClutterActor *self,
9100                               gdouble       scale_x,
9101                               gdouble       scale_y,
9102                               gfloat        center_x,
9103                               gfloat        center_y)
9104 {
9105   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9106
9107   g_object_freeze_notify (G_OBJECT (self));
9108
9109   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9110   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9111   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9112   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9113
9114   g_object_thaw_notify (G_OBJECT (self));
9115 }
9116
9117 /**
9118  * clutter_actor_set_scale_with_gravity:
9119  * @self: A #ClutterActor
9120  * @scale_x: double factor to scale actor by horizontally.
9121  * @scale_y: double factor to scale actor by vertically.
9122  * @gravity: the location of the scale center expressed as a compass
9123  * direction.
9124  *
9125  * Scales an actor with the given factors around the given
9126  * center point. The center point is specified as one of the compass
9127  * directions in #ClutterGravity. For example, setting it to north
9128  * will cause the top of the actor to remain unchanged and the rest of
9129  * the actor to expand left, right and downwards.
9130  *
9131  * Since: 1.0
9132  */
9133 void
9134 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9135                                       gdouble         scale_x,
9136                                       gdouble         scale_y,
9137                                       ClutterGravity  gravity)
9138 {
9139   ClutterTransformInfo *info;
9140   GObject *obj;
9141
9142   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9143
9144   obj = G_OBJECT (self);
9145
9146   g_object_freeze_notify (obj);
9147
9148   info = _clutter_actor_get_transform_info (self);
9149   info->scale_x = scale_x;
9150   info->scale_y = scale_y;
9151
9152   if (gravity == CLUTTER_GRAVITY_NONE)
9153     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9154   else
9155     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9156
9157   self->priv->transform_valid = FALSE;
9158
9159   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9160   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9161   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9162   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9163   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9164
9165   clutter_actor_queue_redraw (self);
9166
9167   g_object_thaw_notify (obj);
9168 }
9169
9170 /**
9171  * clutter_actor_get_scale:
9172  * @self: A #ClutterActor
9173  * @scale_x: (out) (allow-none): Location to store horizonal
9174  *   scale factor, or %NULL.
9175  * @scale_y: (out) (allow-none): Location to store vertical
9176  *   scale factor, or %NULL.
9177  *
9178  * Retrieves an actors scale factors.
9179  *
9180  * Since: 0.2
9181  */
9182 void
9183 clutter_actor_get_scale (ClutterActor *self,
9184                          gdouble      *scale_x,
9185                          gdouble      *scale_y)
9186 {
9187   const ClutterTransformInfo *info;
9188
9189   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9190
9191   info = _clutter_actor_get_transform_info_or_defaults (self);
9192
9193   if (scale_x)
9194     *scale_x = info->scale_x;
9195
9196   if (scale_y)
9197     *scale_y = info->scale_y;
9198 }
9199
9200 /**
9201  * clutter_actor_get_scale_center:
9202  * @self: A #ClutterActor
9203  * @center_x: (out) (allow-none): Location to store the X position
9204  *   of the scale center, or %NULL.
9205  * @center_y: (out) (allow-none): Location to store the Y position
9206  *   of the scale center, or %NULL.
9207  *
9208  * Retrieves the scale center coordinate in pixels relative to the top
9209  * left corner of the actor. If the scale center was specified using a
9210  * #ClutterGravity this will calculate the pixel offset using the
9211  * current size of the actor.
9212  *
9213  * Since: 1.0
9214  */
9215 void
9216 clutter_actor_get_scale_center (ClutterActor *self,
9217                                 gfloat       *center_x,
9218                                 gfloat       *center_y)
9219 {
9220   const ClutterTransformInfo *info;
9221
9222   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9223
9224   info = _clutter_actor_get_transform_info_or_defaults (self);
9225
9226   clutter_anchor_coord_get_units (self, &info->scale_center,
9227                                   center_x,
9228                                   center_y,
9229                                   NULL);
9230 }
9231
9232 /**
9233  * clutter_actor_get_scale_gravity:
9234  * @self: A #ClutterActor
9235  *
9236  * Retrieves the scale center as a compass direction. If the scale
9237  * center was specified in pixels or units this will return
9238  * %CLUTTER_GRAVITY_NONE.
9239  *
9240  * Return value: the scale gravity
9241  *
9242  * Since: 1.0
9243  */
9244 ClutterGravity
9245 clutter_actor_get_scale_gravity (ClutterActor *self)
9246 {
9247   const ClutterTransformInfo *info;
9248
9249   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9250
9251   info = _clutter_actor_get_transform_info_or_defaults (self);
9252
9253   return clutter_anchor_coord_get_gravity (&info->scale_center);
9254 }
9255
9256 /**
9257  * clutter_actor_set_opacity:
9258  * @self: A #ClutterActor
9259  * @opacity: New opacity value for the actor.
9260  *
9261  * Sets the actor's opacity, with zero being completely transparent and
9262  * 255 (0xff) being fully opaque.
9263  */
9264 void
9265 clutter_actor_set_opacity (ClutterActor *self,
9266                            guint8        opacity)
9267 {
9268   ClutterActorPrivate *priv;
9269
9270   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9271
9272   priv = self->priv;
9273
9274   if (priv->opacity != opacity)
9275     {
9276       priv->opacity = opacity;
9277
9278       /* Queue a redraw from the flatten effect so that it can use
9279          its cached image if available instead of having to redraw the
9280          actual actor. If it doesn't end up using the FBO then the
9281          effect is still able to continue the paint anyway. If there
9282          is no flatten effect yet then this is equivalent to queueing
9283          a full redraw */
9284       _clutter_actor_queue_redraw_full (self,
9285                                         0, /* flags */
9286                                         NULL, /* clip */
9287                                         priv->flatten_effect);
9288
9289       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9290     }
9291 }
9292
9293 /*
9294  * clutter_actor_get_paint_opacity_internal:
9295  * @self: a #ClutterActor
9296  *
9297  * Retrieves the absolute opacity of the actor, as it appears on the stage
9298  *
9299  * This function does not do type checks
9300  *
9301  * Return value: the absolute opacity of the actor
9302  */
9303 static guint8
9304 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9305 {
9306   ClutterActorPrivate *priv = self->priv;
9307   ClutterActor *parent;
9308
9309   /* override the top-level opacity to always be 255; even in
9310    * case of ClutterStage:use-alpha being TRUE we want the rest
9311    * of the scene to be painted
9312    */
9313   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9314     return 255;
9315
9316   if (priv->opacity_override >= 0)
9317     return priv->opacity_override;
9318
9319   parent = priv->parent;
9320
9321   /* Factor in the actual actors opacity with parents */
9322   if (parent != NULL)
9323     {
9324       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9325
9326       if (opacity != 0xff)
9327         return (opacity * priv->opacity) / 0xff;
9328     }
9329
9330   return priv->opacity;
9331
9332 }
9333
9334 /**
9335  * clutter_actor_get_paint_opacity:
9336  * @self: A #ClutterActor
9337  *
9338  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9339  *
9340  * This function traverses the hierarchy chain and composites the opacity of
9341  * the actor with that of its parents.
9342  *
9343  * This function is intended for subclasses to use in the paint virtual
9344  * function, to paint themselves with the correct opacity.
9345  *
9346  * Return value: The actor opacity value.
9347  *
9348  * Since: 0.8
9349  */
9350 guint8
9351 clutter_actor_get_paint_opacity (ClutterActor *self)
9352 {
9353   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9354
9355   return clutter_actor_get_paint_opacity_internal (self);
9356 }
9357
9358 /**
9359  * clutter_actor_get_opacity:
9360  * @self: a #ClutterActor
9361  *
9362  * Retrieves the opacity value of an actor, as set by
9363  * clutter_actor_set_opacity().
9364  *
9365  * For retrieving the absolute opacity of the actor inside a paint
9366  * virtual function, see clutter_actor_get_paint_opacity().
9367  *
9368  * Return value: the opacity of the actor
9369  */
9370 guint8
9371 clutter_actor_get_opacity (ClutterActor *self)
9372 {
9373   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9374
9375   return self->priv->opacity;
9376 }
9377
9378 /**
9379  * clutter_actor_set_offscreen_redirect:
9380  * @self: A #ClutterActor
9381  * @redirect: New offscreen redirect flags for the actor.
9382  *
9383  * Defines the circumstances where the actor should be redirected into
9384  * an offscreen image. The offscreen image is used to flatten the
9385  * actor into a single image while painting for two main reasons.
9386  * Firstly, when the actor is painted a second time without any of its
9387  * contents changing it can simply repaint the cached image without
9388  * descending further down the actor hierarchy. Secondly, it will make
9389  * the opacity look correct even if there are overlapping primitives
9390  * in the actor.
9391  *
9392  * Caching the actor could in some cases be a performance win and in
9393  * some cases be a performance lose so it is important to determine
9394  * which value is right for an actor before modifying this value. For
9395  * example, there is never any reason to flatten an actor that is just
9396  * a single texture (such as a #ClutterTexture) because it is
9397  * effectively already cached in an image so the offscreen would be
9398  * redundant. Also if the actor contains primitives that are far apart
9399  * with a large transparent area in the middle (such as a large
9400  * CluterGroup with a small actor in the top left and a small actor in
9401  * the bottom right) then the cached image will contain the entire
9402  * image of the large area and the paint will waste time blending all
9403  * of the transparent pixels in the middle.
9404  *
9405  * The default method of implementing opacity on a container simply
9406  * forwards on the opacity to all of the children. If the children are
9407  * overlapping then it will appear as if they are two separate glassy
9408  * objects and there will be a break in the color where they
9409  * overlap. By redirecting to an offscreen buffer it will be as if the
9410  * two opaque objects are combined into one and then made transparent
9411  * which is usually what is expected.
9412  *
9413  * The image below demonstrates the difference between redirecting and
9414  * not. The image shows two Clutter groups, each containing a red and
9415  * a green rectangle which overlap. The opacity on the group is set to
9416  * 128 (which is 50%). When the offscreen redirect is not used, the
9417  * red rectangle can be seen through the blue rectangle as if the two
9418  * rectangles were separately transparent. When the redirect is used
9419  * the group as a whole is transparent instead so the red rectangle is
9420  * not visible where they overlap.
9421  *
9422  * <figure id="offscreen-redirect">
9423  *   <title>Sample of using an offscreen redirect for transparency</title>
9424  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9425  * </figure>
9426  *
9427  * The default value for this property is 0, so we effectively will
9428  * never redirect an actor offscreen by default. This means that there
9429  * are times that transparent actors may look glassy as described
9430  * above. The reason this is the default is because there is a
9431  * performance trade off between quality and performance here. In many
9432  * cases the default form of glassy opacity looks good enough, but if
9433  * it's not you will need to set the
9434  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9435  * redirection for opacity.
9436  *
9437  * Custom actors that don't contain any overlapping primitives are
9438  * recommended to override the has_overlaps() virtual to return %FALSE
9439  * for maximum efficiency.
9440  *
9441  * Since: 1.8
9442  */
9443 void
9444 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9445                                       ClutterOffscreenRedirect redirect)
9446 {
9447   ClutterActorPrivate *priv;
9448
9449   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9450
9451   priv = self->priv;
9452
9453   if (priv->offscreen_redirect != redirect)
9454     {
9455       priv->offscreen_redirect = redirect;
9456
9457       /* Queue a redraw from the effect so that it can use its cached
9458          image if available instead of having to redraw the actual
9459          actor. If it doesn't end up using the FBO then the effect is
9460          still able to continue the paint anyway. If there is no
9461          effect then this is equivalent to queuing a full redraw */
9462       _clutter_actor_queue_redraw_full (self,
9463                                         0, /* flags */
9464                                         NULL, /* clip */
9465                                         priv->flatten_effect);
9466
9467       g_object_notify_by_pspec (G_OBJECT (self),
9468                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9469     }
9470 }
9471
9472 /**
9473  * clutter_actor_get_offscreen_redirect:
9474  * @self: a #ClutterActor
9475  *
9476  * Retrieves whether to redirect the actor to an offscreen buffer, as
9477  * set by clutter_actor_set_offscreen_redirect().
9478  *
9479  * Return value: the value of the offscreen-redirect property of the actor
9480  *
9481  * Since: 1.8
9482  */
9483 ClutterOffscreenRedirect
9484 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9485 {
9486   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9487
9488   return self->priv->offscreen_redirect;
9489 }
9490
9491 /**
9492  * clutter_actor_set_name:
9493  * @self: A #ClutterActor
9494  * @name: Textual tag to apply to actor
9495  *
9496  * Sets the given name to @self. The name can be used to identify
9497  * a #ClutterActor.
9498  */
9499 void
9500 clutter_actor_set_name (ClutterActor *self,
9501                         const gchar  *name)
9502 {
9503   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9504
9505   g_free (self->priv->name);
9506   self->priv->name = g_strdup (name);
9507
9508   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9509 }
9510
9511 /**
9512  * clutter_actor_get_name:
9513  * @self: A #ClutterActor
9514  *
9515  * Retrieves the name of @self.
9516  *
9517  * Return value: the name of the actor, or %NULL. The returned string is
9518  *   owned by the actor and should not be modified or freed.
9519  */
9520 const gchar *
9521 clutter_actor_get_name (ClutterActor *self)
9522 {
9523   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9524
9525   return self->priv->name;
9526 }
9527
9528 /**
9529  * clutter_actor_get_gid:
9530  * @self: A #ClutterActor
9531  *
9532  * Retrieves the unique id for @self.
9533  *
9534  * Return value: Globally unique value for this object instance.
9535  *
9536  * Since: 0.6
9537  *
9538  * Deprecated: 1.8: The id is not used any longer.
9539  */
9540 guint32
9541 clutter_actor_get_gid (ClutterActor *self)
9542 {
9543   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9544
9545   return self->priv->id;
9546 }
9547
9548 /**
9549  * clutter_actor_set_depth:
9550  * @self: a #ClutterActor
9551  * @depth: Z co-ord
9552  *
9553  * Sets the Z coordinate of @self to @depth.
9554  *
9555  * The unit used by @depth is dependant on the perspective setup. See
9556  * also clutter_stage_set_perspective().
9557  */
9558 void
9559 clutter_actor_set_depth (ClutterActor *self,
9560                          gfloat        depth)
9561 {
9562   ClutterActorPrivate *priv;
9563
9564   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9565
9566   priv = self->priv;
9567
9568   if (priv->z != depth)
9569     {
9570       /* Sets Z value - XXX 2.0: should we invert? */
9571       priv->z = depth;
9572
9573       priv->transform_valid = FALSE;
9574
9575       /* FIXME - remove this crap; sadly, there are still containers
9576        * in Clutter that depend on this utter brain damage
9577        */
9578       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9579
9580       clutter_actor_queue_redraw (self);
9581
9582       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9583     }
9584 }
9585
9586 /**
9587  * clutter_actor_get_depth:
9588  * @self: a #ClutterActor
9589  *
9590  * Retrieves the depth of @self.
9591  *
9592  * Return value: the depth of the actor
9593  */
9594 gfloat
9595 clutter_actor_get_depth (ClutterActor *self)
9596 {
9597   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
9598
9599   return self->priv->z;
9600 }
9601
9602 /**
9603  * clutter_actor_set_rotation:
9604  * @self: a #ClutterActor
9605  * @axis: the axis of rotation
9606  * @angle: the angle of rotation
9607  * @x: X coordinate of the rotation center
9608  * @y: Y coordinate of the rotation center
9609  * @z: Z coordinate of the rotation center
9610  *
9611  * Sets the rotation angle of @self around the given axis.
9612  *
9613  * The rotation center coordinates used depend on the value of @axis:
9614  * <itemizedlist>
9615  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
9616  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
9617  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
9618  * </itemizedlist>
9619  *
9620  * The rotation coordinates are relative to the anchor point of the
9621  * actor, set using clutter_actor_set_anchor_point(). If no anchor
9622  * point is set, the upper left corner is assumed as the origin.
9623  *
9624  * Since: 0.8
9625  */
9626 void
9627 clutter_actor_set_rotation (ClutterActor      *self,
9628                             ClutterRotateAxis  axis,
9629                             gdouble            angle,
9630                             gfloat             x,
9631                             gfloat             y,
9632                             gfloat             z)
9633 {
9634   ClutterVertex v;
9635
9636   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9637
9638   v.x = x;
9639   v.y = y;
9640   v.z = z;
9641
9642   g_object_freeze_notify (G_OBJECT (self));
9643
9644   clutter_actor_set_rotation_angle_internal (self, axis, angle);
9645   clutter_actor_set_rotation_center_internal (self, axis, &v);
9646
9647   g_object_thaw_notify (G_OBJECT (self));
9648 }
9649
9650 /**
9651  * clutter_actor_set_z_rotation_from_gravity:
9652  * @self: a #ClutterActor
9653  * @angle: the angle of rotation
9654  * @gravity: the center point of the rotation
9655  *
9656  * Sets the rotation angle of @self around the Z axis using the center
9657  * point specified as a compass point. For example to rotate such that
9658  * the center of the actor remains static you can use
9659  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
9660  * will move accordingly.
9661  *
9662  * Since: 1.0
9663  */
9664 void
9665 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
9666                                            gdouble         angle,
9667                                            ClutterGravity  gravity)
9668 {
9669   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9670
9671   if (gravity == CLUTTER_GRAVITY_NONE)
9672     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
9673   else
9674     {
9675       GObject *obj = G_OBJECT (self);
9676       ClutterTransformInfo *info;
9677
9678       info = _clutter_actor_get_transform_info (self);
9679
9680       g_object_freeze_notify (obj);
9681
9682       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
9683
9684       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
9685       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
9686       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
9687
9688       g_object_thaw_notify (obj);
9689     }
9690 }
9691
9692 /**
9693  * clutter_actor_get_rotation:
9694  * @self: a #ClutterActor
9695  * @axis: the axis of rotation
9696  * @x: (out): return value for the X coordinate of the center of rotation
9697  * @y: (out): return value for the Y coordinate of the center of rotation
9698  * @z: (out): return value for the Z coordinate of the center of rotation
9699  *
9700  * Retrieves the angle and center of rotation on the given axis,
9701  * set using clutter_actor_set_rotation().
9702  *
9703  * Return value: the angle of rotation
9704  *
9705  * Since: 0.8
9706  */
9707 gdouble
9708 clutter_actor_get_rotation (ClutterActor      *self,
9709                             ClutterRotateAxis  axis,
9710                             gfloat            *x,
9711                             gfloat            *y,
9712                             gfloat            *z)
9713 {
9714   const ClutterTransformInfo *info;
9715   const AnchorCoord *anchor_coord;
9716   gdouble retval = 0;
9717
9718   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9719
9720   info = _clutter_actor_get_transform_info_or_defaults (self);
9721
9722   switch (axis)
9723     {
9724     case CLUTTER_X_AXIS:
9725       anchor_coord = &info->rx_center;
9726       retval = info->rx_angle;
9727       break;
9728
9729     case CLUTTER_Y_AXIS:
9730       anchor_coord = &info->ry_center;
9731       retval = info->ry_angle;
9732       break;
9733
9734     case CLUTTER_Z_AXIS:
9735       anchor_coord = &info->rz_center;
9736       retval = info->rz_angle;
9737       break;
9738
9739     default:
9740       anchor_coord = NULL;
9741       retval = 0.0;
9742       break;
9743     }
9744
9745   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
9746
9747   return retval;
9748 }
9749
9750 /**
9751  * clutter_actor_get_z_rotation_gravity:
9752  * @self: A #ClutterActor
9753  *
9754  * Retrieves the center for the rotation around the Z axis as a
9755  * compass direction. If the center was specified in pixels or units
9756  * this will return %CLUTTER_GRAVITY_NONE.
9757  *
9758  * Return value: the Z rotation center
9759  *
9760  * Since: 1.0
9761  */
9762 ClutterGravity
9763 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
9764 {
9765   const ClutterTransformInfo *info;
9766
9767   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9768
9769   info = _clutter_actor_get_transform_info_or_defaults (self);
9770
9771   return clutter_anchor_coord_get_gravity (&info->rz_center);
9772 }
9773
9774 /**
9775  * clutter_actor_set_clip:
9776  * @self: A #ClutterActor
9777  * @xoff: X offset of the clip rectangle
9778  * @yoff: Y offset of the clip rectangle
9779  * @width: Width of the clip rectangle
9780  * @height: Height of the clip rectangle
9781  *
9782  * Sets clip area for @self. The clip area is always computed from the
9783  * upper left corner of the actor, even if the anchor point is set
9784  * otherwise.
9785  *
9786  * Since: 0.6
9787  */
9788 void
9789 clutter_actor_set_clip (ClutterActor *self,
9790                         gfloat        xoff,
9791                         gfloat        yoff,
9792                         gfloat        width,
9793                         gfloat        height)
9794 {
9795   ClutterActorPrivate *priv;
9796
9797   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9798
9799   priv = self->priv;
9800
9801   if (priv->has_clip &&
9802       priv->clip.x == xoff &&
9803       priv->clip.y == yoff &&
9804       priv->clip.width == width &&
9805       priv->clip.height == height)
9806     return;
9807
9808   priv->clip.x = xoff;
9809   priv->clip.y = yoff;
9810   priv->clip.width = width;
9811   priv->clip.height = height;
9812
9813   priv->has_clip = TRUE;
9814
9815   clutter_actor_queue_redraw (self);
9816
9817   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9818   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
9819 }
9820
9821 /**
9822  * clutter_actor_remove_clip:
9823  * @self: A #ClutterActor
9824  *
9825  * Removes clip area from @self.
9826  */
9827 void
9828 clutter_actor_remove_clip (ClutterActor *self)
9829 {
9830   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9831
9832   if (!self->priv->has_clip)
9833     return;
9834
9835   self->priv->has_clip = FALSE;
9836
9837   clutter_actor_queue_redraw (self);
9838
9839   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9840 }
9841
9842 /**
9843  * clutter_actor_has_clip:
9844  * @self: a #ClutterActor
9845  *
9846  * Determines whether the actor has a clip area set or not.
9847  *
9848  * Return value: %TRUE if the actor has a clip area set.
9849  *
9850  * Since: 0.1.1
9851  */
9852 gboolean
9853 clutter_actor_has_clip (ClutterActor *self)
9854 {
9855   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9856
9857   return self->priv->has_clip;
9858 }
9859
9860 /**
9861  * clutter_actor_get_clip:
9862  * @self: a #ClutterActor
9863  * @xoff: (out) (allow-none): return location for the X offset of
9864  *   the clip rectangle, or %NULL
9865  * @yoff: (out) (allow-none): return location for the Y offset of
9866  *   the clip rectangle, or %NULL
9867  * @width: (out) (allow-none): return location for the width of
9868  *   the clip rectangle, or %NULL
9869  * @height: (out) (allow-none): return location for the height of
9870  *   the clip rectangle, or %NULL
9871  *
9872  * Gets the clip area for @self, if any is set
9873  *
9874  * Since: 0.6
9875  */
9876 void
9877 clutter_actor_get_clip (ClutterActor *self,
9878                         gfloat       *xoff,
9879                         gfloat       *yoff,
9880                         gfloat       *width,
9881                         gfloat       *height)
9882 {
9883   ClutterActorPrivate *priv;
9884
9885   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9886
9887   priv = self->priv;
9888
9889   if (!priv->has_clip)
9890     return;
9891
9892   if (xoff != NULL)
9893     *xoff = priv->clip.x;
9894
9895   if (yoff != NULL)
9896     *yoff = priv->clip.y;
9897
9898   if (width != NULL)
9899     *width = priv->clip.width;
9900
9901   if (height != NULL)
9902     *height = priv->clip.height;
9903 }
9904
9905 /**
9906  * clutter_actor_get_children:
9907  * @self: a #ClutterActor
9908  *
9909  * Retrieves the list of children of @self.
9910  *
9911  * Return value: (transfer container) (element-type ClutterActor): A newly
9912  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
9913  *   done.
9914  *
9915  * Since: 1.10
9916  */
9917 GList *
9918 clutter_actor_get_children (ClutterActor *self)
9919 {
9920   ClutterActor *iter;
9921   GList *res;
9922
9923   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9924
9925   /* we walk the list backward so that we can use prepend(),
9926    * which is O(1)
9927    */
9928   for (iter = self->priv->last_child, res = NULL;
9929        iter != NULL;
9930        iter = iter->priv->prev_sibling)
9931     {
9932       res = g_list_prepend (res, iter);
9933     }
9934
9935   return res;
9936 }
9937
9938 /*< private >
9939  * insert_child_at_depth:
9940  * @self: a #ClutterActor
9941  * @child: a #ClutterActor
9942  *
9943  * Inserts @child inside the list of children held by @self, using
9944  * the depth as the insertion criteria.
9945  *
9946  * This sadly makes the insertion not O(1), but we can keep the
9947  * list sorted so that the painters algorithm we use for painting
9948  * the children will work correctly.
9949  */
9950 static void
9951 insert_child_at_depth (ClutterActor *self,
9952                        ClutterActor *child,
9953                        gpointer      dummy G_GNUC_UNUSED)
9954 {
9955   ClutterActor *iter;
9956
9957   child->priv->parent = self;
9958
9959   /* special-case the first child */
9960   if (self->priv->n_children == 0)
9961     {
9962       self->priv->first_child = child;
9963       self->priv->last_child = child;
9964
9965       child->priv->next_sibling = NULL;
9966       child->priv->prev_sibling = NULL;
9967
9968       return;
9969     }
9970
9971   /* Find the right place to insert the child so that it will still be
9972      sorted and the child will be after all of the actors at the same
9973      dept */
9974   for (iter = self->priv->first_child;
9975        iter != NULL;
9976        iter = iter->priv->next_sibling)
9977     {
9978       if (iter->priv->z > child->priv->z)
9979         break;
9980     }
9981
9982   if (iter != NULL)
9983     {
9984       ClutterActor *tmp = iter->priv->prev_sibling;
9985
9986       if (tmp != NULL)
9987         tmp->priv->next_sibling = child;
9988
9989       /* Insert the node before the found one */
9990       child->priv->prev_sibling = iter->priv->prev_sibling;
9991       child->priv->next_sibling = iter;
9992       iter->priv->prev_sibling = child;
9993     }
9994   else
9995     {
9996       ClutterActor *tmp = self->priv->last_child;
9997
9998       if (tmp != NULL)
9999         tmp->priv->next_sibling = child;
10000
10001       /* insert the node at the end of the list */
10002       child->priv->prev_sibling = self->priv->last_child;
10003       child->priv->next_sibling = NULL;
10004     }
10005
10006   if (child->priv->prev_sibling == NULL)
10007     self->priv->first_child = child;
10008
10009   if (child->priv->next_sibling == NULL)
10010     self->priv->last_child = child;
10011 }
10012
10013 static void
10014 insert_child_at_index (ClutterActor *self,
10015                        ClutterActor *child,
10016                        gpointer      data_)
10017 {
10018   gint index_ = GPOINTER_TO_INT (data_);
10019
10020   child->priv->parent = self;
10021
10022   if (index_ == 0)
10023     {
10024       ClutterActor *tmp = self->priv->first_child;
10025
10026       if (tmp != NULL)
10027         tmp->priv->prev_sibling = child;
10028
10029       child->priv->prev_sibling = NULL;
10030       child->priv->next_sibling = tmp;
10031     }
10032   else if (index_ < 0 || index_ >= self->priv->n_children)
10033     {
10034       ClutterActor *tmp = self->priv->last_child;
10035
10036       if (tmp != NULL)
10037         tmp->priv->next_sibling = child;
10038
10039       child->priv->prev_sibling = tmp;
10040       child->priv->next_sibling = NULL;
10041     }
10042   else
10043     {
10044       ClutterActor *iter;
10045       int i;
10046
10047       for (iter = self->priv->first_child, i = 0;
10048            iter != NULL;
10049            iter = iter->priv->next_sibling, i += 1)
10050         {
10051           if (index_ == i)
10052             {
10053               ClutterActor *tmp = iter->priv->prev_sibling;
10054
10055               child->priv->prev_sibling = tmp;
10056               child->priv->next_sibling = iter;
10057
10058               iter->priv->prev_sibling = child;
10059
10060               if (tmp != NULL)
10061                 tmp->priv->next_sibling = child;
10062
10063               break;
10064             }
10065         }
10066     }
10067
10068   if (child->priv->prev_sibling == NULL)
10069     self->priv->first_child = child;
10070
10071   if (child->priv->next_sibling == NULL)
10072     self->priv->last_child = child;
10073 }
10074
10075 static void
10076 insert_child_above (ClutterActor *self,
10077                     ClutterActor *child,
10078                     gpointer      data)
10079 {
10080   ClutterActor *sibling = data;
10081
10082   child->priv->parent = self;
10083
10084   if (sibling == NULL)
10085     sibling = self->priv->last_child;
10086
10087   child->priv->prev_sibling = sibling;
10088
10089   if (sibling != NULL)
10090     {
10091       ClutterActor *tmp = sibling->priv->next_sibling;
10092
10093       child->priv->next_sibling = tmp;
10094
10095       if (tmp != NULL)
10096         tmp->priv->prev_sibling = child;
10097
10098       sibling->priv->next_sibling = child;
10099     }
10100   else
10101     child->priv->next_sibling = NULL;
10102
10103   if (child->priv->prev_sibling == NULL)
10104     self->priv->first_child = child;
10105
10106   if (child->priv->next_sibling == NULL)
10107     self->priv->last_child = child;
10108 }
10109
10110 static void
10111 insert_child_below (ClutterActor *self,
10112                     ClutterActor *child,
10113                     gpointer      data)
10114 {
10115   ClutterActor *sibling = data;
10116
10117   child->priv->parent = self;
10118
10119   if (sibling == NULL)
10120     sibling = self->priv->first_child;
10121
10122   child->priv->next_sibling = sibling;
10123
10124   if (sibling != NULL)
10125     {
10126       ClutterActor *tmp = sibling->priv->prev_sibling;
10127
10128       child->priv->prev_sibling = tmp;
10129
10130       if (tmp != NULL)
10131         tmp->priv->next_sibling = child;
10132
10133       sibling->priv->prev_sibling = child;
10134     }
10135   else
10136     child->priv->prev_sibling = NULL;
10137
10138   if (child->priv->prev_sibling == NULL)
10139     self->priv->first_child = child;
10140
10141   if (child->priv->next_sibling == NULL)
10142     self->priv->last_child = child;
10143 }
10144
10145 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10146                                            ClutterActor *child,
10147                                            gpointer      data);
10148
10149 typedef enum {
10150   ADD_CHILD_CREATE_META       = 1 << 0,
10151   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10152   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10153   ADD_CHILD_CHECK_STATE       = 1 << 3,
10154   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10155
10156   /* default flags for public API */
10157   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10158                                ADD_CHILD_EMIT_PARENT_SET |
10159                                ADD_CHILD_EMIT_ACTOR_ADDED |
10160                                ADD_CHILD_CHECK_STATE |
10161                                ADD_CHILD_NOTIFY_FIRST_LAST,
10162
10163   /* flags for legacy/deprecated API */
10164   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10165                                ADD_CHILD_CHECK_STATE |
10166                                ADD_CHILD_NOTIFY_FIRST_LAST
10167 } ClutterActorAddChildFlags;
10168
10169 /*< private >
10170  * clutter_actor_add_child_internal:
10171  * @self: a #ClutterActor
10172  * @child: a #ClutterActor
10173  * @flags: control flags for actions
10174  * @add_func: delegate function
10175  * @data: (closure): data to pass to @add_func
10176  *
10177  * Adds @child to the list of children of @self.
10178  *
10179  * The actual insertion inside the list is delegated to @add_func: this
10180  * function will just set up the state, perform basic checks, and emit
10181  * signals.
10182  *
10183  * The @flags argument is used to perform additional operations.
10184  */
10185 static inline void
10186 clutter_actor_add_child_internal (ClutterActor              *self,
10187                                   ClutterActor              *child,
10188                                   ClutterActorAddChildFlags  flags,
10189                                   ClutterActorAddChildFunc   add_func,
10190                                   gpointer                   data)
10191 {
10192   ClutterTextDirection text_dir;
10193   gboolean create_meta;
10194   gboolean emit_parent_set, emit_actor_added;
10195   gboolean check_state;
10196   gboolean notify_first_last;
10197   ClutterActor *old_first_child, *old_last_child;
10198
10199   if (child->priv->parent != NULL)
10200     {
10201       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10202                  "use clutter_actor_remove_child() first.",
10203                  _clutter_actor_get_debug_name (child),
10204                  _clutter_actor_get_debug_name (child->priv->parent));
10205       return;
10206     }
10207
10208   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10209     {
10210       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10211                  "a child of another actor.",
10212                  _clutter_actor_get_debug_name (child));
10213       return;
10214     }
10215
10216 #if 0
10217   /* XXX - this check disallows calling methods that change the stacking
10218    * order within the destruction sequence, by triggering a critical
10219    * warning first, and leaving the actor in an undefined state, which
10220    * then ends up being caught by an assertion.
10221    *
10222    * the reproducible sequence is:
10223    *
10224    *   - actor gets destroyed;
10225    *   - another actor, linked to the first, will try to change the
10226    *     stacking order of the first actor;
10227    *   - changing the stacking order is a composite operation composed
10228    *     by the following steps:
10229    *     1. ref() the child;
10230    *     2. remove_child_internal(), which removes the reference;
10231    *     3. add_child_internal(), which adds a reference;
10232    *   - the state of the actor is not changed between (2) and (3), as
10233    *     it could be an expensive recomputation;
10234    *   - if (3) bails out, then the actor is in an undefined state, but
10235    *     still alive;
10236    *   - the destruction sequence terminates, but the actor is unparented
10237    *     while its state indicates being parented instead.
10238    *   - assertion failure.
10239    *
10240    * the obvious fix would be to decompose each set_child_*_sibling()
10241    * method into proper remove_child()/add_child(), with state validation;
10242    * this may cause excessive work, though, and trigger a cascade of other
10243    * bugs in code that assumes that a change in the stacking order is an
10244    * atomic operation.
10245    *
10246    * another potential fix is to just remove this check here, and let
10247    * code doing stacking order changes inside the destruction sequence
10248    * of an actor continue doing the work.
10249    *
10250    * the third fix is to silently bail out early from every
10251    * set_child_*_sibling() and set_child_at_index() method, and avoid
10252    * doing work.
10253    *
10254    * I have a preference for the second solution, since it involves the
10255    * least amount of work, and the least amount of code duplication.
10256    *
10257    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10258    */
10259   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10260     {
10261       g_warning ("The actor '%s' is currently being destroyed, and "
10262                  "cannot be added as a child of another actor.",
10263                  _clutter_actor_get_debug_name (child));
10264       return;
10265     }
10266 #endif
10267
10268   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10269   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10270   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10271   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10272   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10273
10274   old_first_child = self->priv->first_child;
10275   old_last_child = self->priv->last_child;
10276
10277   g_object_freeze_notify (G_OBJECT (self));
10278
10279   if (create_meta)
10280     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10281
10282   g_object_ref_sink (child);
10283   child->priv->parent = NULL;
10284   child->priv->next_sibling = NULL;
10285   child->priv->prev_sibling = NULL;
10286
10287   /* delegate the actual insertion */
10288   add_func (self, child, data);
10289
10290   g_assert (child->priv->parent == self);
10291
10292   self->priv->n_children += 1;
10293
10294   self->priv->age += 1;
10295
10296   /* if push_internal() has been called then we automatically set
10297    * the flag on the actor
10298    */
10299   if (self->priv->internal_child)
10300     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10301
10302   /* clutter_actor_reparent() will emit ::parent-set for us */
10303   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10304     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10305
10306   if (check_state)
10307     {
10308       /* If parent is mapped or realized, we need to also be mapped or
10309        * realized once we're inside the parent.
10310        */
10311       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10312
10313       /* propagate the parent's text direction to the child */
10314       text_dir = clutter_actor_get_text_direction (self);
10315       clutter_actor_set_text_direction (child, text_dir);
10316     }
10317
10318   if (child->priv->show_on_set_parent)
10319     clutter_actor_show (child);
10320
10321   if (CLUTTER_ACTOR_IS_MAPPED (child))
10322     clutter_actor_queue_redraw (child);
10323
10324   /* maintain the invariant that if an actor needs layout,
10325    * its parents do as well
10326    */
10327   if (child->priv->needs_width_request ||
10328       child->priv->needs_height_request ||
10329       child->priv->needs_allocation)
10330     {
10331       /* we work around the short-circuiting we do
10332        * in clutter_actor_queue_relayout() since we
10333        * want to force a relayout
10334        */
10335       child->priv->needs_width_request = TRUE;
10336       child->priv->needs_height_request = TRUE;
10337       child->priv->needs_allocation = TRUE;
10338
10339       clutter_actor_queue_relayout (child->priv->parent);
10340     }
10341
10342   if (emit_actor_added)
10343     g_signal_emit_by_name (self, "actor-added", child);
10344
10345   if (notify_first_last)
10346     {
10347       if (old_first_child != self->priv->first_child)
10348         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10349
10350       if (old_last_child != self->priv->last_child)
10351         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10352     }
10353
10354   g_object_thaw_notify (G_OBJECT (self));
10355 }
10356
10357 /**
10358  * clutter_actor_add_child:
10359  * @self: a #ClutterActor
10360  * @child: a #ClutterActor
10361  *
10362  * Adds @child to the children of @self.
10363  *
10364  * This function will acquire a reference on @child that will only
10365  * be released when calling clutter_actor_remove_child().
10366  *
10367  * This function will take into consideration the #ClutterActor:depth
10368  * of @child, and will keep the list of children sorted.
10369  *
10370  * This function will emit the #ClutterContainer::actor-added signal
10371  * on @self.
10372  *
10373  * Since: 1.10
10374  */
10375 void
10376 clutter_actor_add_child (ClutterActor *self,
10377                          ClutterActor *child)
10378 {
10379   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10380   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10381   g_return_if_fail (self != child);
10382   g_return_if_fail (child->priv->parent == NULL);
10383
10384   clutter_actor_add_child_internal (self, child,
10385                                     ADD_CHILD_DEFAULT_FLAGS,
10386                                     insert_child_at_depth,
10387                                     NULL);
10388 }
10389
10390 /**
10391  * clutter_actor_insert_child_at_index:
10392  * @self: a #ClutterActor
10393  * @child: a #ClutterActor
10394  * @index_: the index
10395  *
10396  * Inserts @child into the list of children of @self, using the
10397  * given @index_. If @index_ is greater than the number of children
10398  * in @self, or is less than 0, then the new child is added at the end.
10399  *
10400  * This function will acquire a reference on @child that will only
10401  * be released when calling clutter_actor_remove_child().
10402  *
10403  * This function will not take into consideration the #ClutterActor:depth
10404  * of @child.
10405  *
10406  * This function will emit the #ClutterContainer::actor-added signal
10407  * on @self.
10408  *
10409  * Since: 1.10
10410  */
10411 void
10412 clutter_actor_insert_child_at_index (ClutterActor *self,
10413                                      ClutterActor *child,
10414                                      gint          index_)
10415 {
10416   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10417   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10418   g_return_if_fail (self != child);
10419   g_return_if_fail (child->priv->parent == NULL);
10420
10421   clutter_actor_add_child_internal (self, child,
10422                                     ADD_CHILD_DEFAULT_FLAGS,
10423                                     insert_child_at_index,
10424                                     GINT_TO_POINTER (index_));
10425 }
10426
10427 /**
10428  * clutter_actor_insert_child_above:
10429  * @self: a #ClutterActor
10430  * @child: a #ClutterActor
10431  * @sibling: (allow-none): a child of @self, or %NULL
10432  *
10433  * Inserts @child into the list of children of @self, above another
10434  * child of @self or, if @sibling is %NULL, above all the children
10435  * of @self.
10436  *
10437  * This function will acquire a reference on @child that will only
10438  * be released when calling clutter_actor_remove_child().
10439  *
10440  * This function will not take into consideration the #ClutterActor:depth
10441  * of @child.
10442  *
10443  * This function will emit the #ClutterContainer::actor-added signal
10444  * on @self.
10445  *
10446  * Since: 1.10
10447  */
10448 void
10449 clutter_actor_insert_child_above (ClutterActor *self,
10450                                   ClutterActor *child,
10451                                   ClutterActor *sibling)
10452 {
10453   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10454   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10455   g_return_if_fail (self != child);
10456   g_return_if_fail (child != sibling);
10457   g_return_if_fail (child->priv->parent == NULL);
10458   g_return_if_fail (sibling == NULL ||
10459                     (CLUTTER_IS_ACTOR (sibling) &&
10460                      sibling->priv->parent == self));
10461
10462   clutter_actor_add_child_internal (self, child,
10463                                     ADD_CHILD_DEFAULT_FLAGS,
10464                                     insert_child_above,
10465                                     sibling);
10466 }
10467
10468 /**
10469  * clutter_actor_insert_child_below:
10470  * @self: a #ClutterActor
10471  * @child: a #ClutterActor
10472  * @sibling: (allow-none): a child of @self, or %NULL
10473  *
10474  * Inserts @child into the list of children of @self, below another
10475  * child of @self or, if @sibling is %NULL, below all the children
10476  * of @self.
10477  *
10478  * This function will acquire a reference on @child that will only
10479  * be released when calling clutter_actor_remove_child().
10480  *
10481  * This function will not take into consideration the #ClutterActor:depth
10482  * of @child.
10483  *
10484  * This function will emit the #ClutterContainer::actor-added signal
10485  * on @self.
10486  *
10487  * Since: 1.10
10488  */
10489 void
10490 clutter_actor_insert_child_below (ClutterActor *self,
10491                                   ClutterActor *child,
10492                                   ClutterActor *sibling)
10493 {
10494   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10495   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10496   g_return_if_fail (self != child);
10497   g_return_if_fail (child != sibling);
10498   g_return_if_fail (child->priv->parent == NULL);
10499   g_return_if_fail (sibling == NULL ||
10500                     (CLUTTER_IS_ACTOR (sibling) &&
10501                      sibling->priv->parent == self));
10502
10503   clutter_actor_add_child_internal (self, child,
10504                                     ADD_CHILD_DEFAULT_FLAGS,
10505                                     insert_child_below,
10506                                     sibling);
10507 }
10508
10509 /**
10510  * clutter_actor_set_parent:
10511  * @self: A #ClutterActor
10512  * @parent: A new #ClutterActor parent
10513  *
10514  * Sets the parent of @self to @parent.
10515  *
10516  * This function will result in @parent acquiring a reference on @self,
10517  * eventually by sinking its floating reference first. The reference
10518  * will be released by clutter_actor_unparent().
10519  *
10520  * This function should only be called by legacy #ClutterActor<!-- -->s
10521  * implementing the #ClutterContainer interface.
10522  *
10523  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10524  */
10525 void
10526 clutter_actor_set_parent (ClutterActor *self,
10527                           ClutterActor *parent)
10528 {
10529   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10530   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10531   g_return_if_fail (self != parent);
10532   g_return_if_fail (self->priv->parent == NULL);
10533
10534   /* as this function will be called inside ClutterContainer::add
10535    * implementations or when building up a composite actor, we have
10536    * to preserve the old behaviour, and not create child meta or
10537    * emit the ::actor-added signal, to avoid recursion or double
10538    * emissions
10539    */
10540   clutter_actor_add_child_internal (parent, self,
10541                                     ADD_CHILD_LEGACY_FLAGS,
10542                                     insert_child_at_depth,
10543                                     NULL);
10544 }
10545
10546 /**
10547  * clutter_actor_get_parent:
10548  * @self: A #ClutterActor
10549  *
10550  * Retrieves the parent of @self.
10551  *
10552  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10553  *  if no parent is set
10554  */
10555 ClutterActor *
10556 clutter_actor_get_parent (ClutterActor *self)
10557 {
10558   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10559
10560   return self->priv->parent;
10561 }
10562
10563 /**
10564  * clutter_actor_get_paint_visibility:
10565  * @self: A #ClutterActor
10566  *
10567  * Retrieves the 'paint' visibility of an actor recursively checking for non
10568  * visible parents.
10569  *
10570  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10571  *
10572  * Return Value: %TRUE if the actor is visibile and will be painted.
10573  *
10574  * Since: 0.8.4
10575  */
10576 gboolean
10577 clutter_actor_get_paint_visibility (ClutterActor *actor)
10578 {
10579   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10580
10581   return CLUTTER_ACTOR_IS_MAPPED (actor);
10582 }
10583
10584 /**
10585  * clutter_actor_remove_child:
10586  * @self: a #ClutterActor
10587  * @child: a #ClutterActor
10588  *
10589  * Removes @child from the children of @self.
10590  *
10591  * This function will release the reference added by
10592  * clutter_actor_add_child(), so if you want to keep using @child
10593  * you will have to acquire a referenced on it before calling this
10594  * function.
10595  *
10596  * This function will emit the #ClutterContainer::actor-removed
10597  * signal on @self.
10598  *
10599  * Since: 1.10
10600  */
10601 void
10602 clutter_actor_remove_child (ClutterActor *self,
10603                             ClutterActor *child)
10604 {
10605   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10606   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10607   g_return_if_fail (self != child);
10608   g_return_if_fail (child->priv->parent != NULL);
10609   g_return_if_fail (child->priv->parent == self);
10610
10611   clutter_actor_remove_child_internal (self, child,
10612                                        REMOVE_CHILD_DEFAULT_FLAGS);
10613 }
10614
10615 /**
10616  * clutter_actor_remove_all_children:
10617  * @self: a #ClutterActor
10618  *
10619  * Removes all children of @self.
10620  *
10621  * This function releases the reference added by inserting a child actor
10622  * in the list of children of @self.
10623  *
10624  * If the reference count of a child drops to zero, the child will be
10625  * destroyed. If you want to ensure the destruction of all the children
10626  * of @self, use clutter_actor_destroy_all_children().
10627  *
10628  * Since: 1.10
10629  */
10630 void
10631 clutter_actor_remove_all_children (ClutterActor *self)
10632 {
10633   ClutterActorIter iter;
10634
10635   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10636
10637   if (self->priv->n_children == 0)
10638     return;
10639
10640   g_object_freeze_notify (G_OBJECT (self));
10641
10642   clutter_actor_iter_init (&iter, self);
10643   while (clutter_actor_iter_next (&iter, NULL))
10644     clutter_actor_iter_remove (&iter);
10645
10646   g_object_thaw_notify (G_OBJECT (self));
10647
10648   /* sanity check */
10649   g_assert (self->priv->first_child == NULL);
10650   g_assert (self->priv->last_child == NULL);
10651   g_assert (self->priv->n_children == 0);
10652 }
10653
10654 /**
10655  * clutter_actor_destroy_all_children:
10656  * @self: a #ClutterActor
10657  *
10658  * Destroys all children of @self.
10659  *
10660  * This function releases the reference added by inserting a child
10661  * actor in the list of children of @self, and ensures that the
10662  * #ClutterActor::destroy signal is emitted on each child of the
10663  * actor.
10664  *
10665  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
10666  * when its reference count drops to 0; the default handler of the
10667  * #ClutterActor::destroy signal will destroy all the children of an
10668  * actor. This function ensures that all children are destroyed, instead
10669  * of just removed from @self, unlike clutter_actor_remove_all_children()
10670  * which will merely release the reference and remove each child.
10671  *
10672  * Unless you acquired an additional reference on each child of @self
10673  * prior to calling clutter_actor_remove_all_children() and want to reuse
10674  * the actors, you should use clutter_actor_destroy_all_children() in
10675  * order to make sure that children are destroyed and signal handlers
10676  * are disconnected even in cases where circular references prevent this
10677  * from automatically happening through reference counting alone.
10678  *
10679  * Since: 1.10
10680  */
10681 void
10682 clutter_actor_destroy_all_children (ClutterActor *self)
10683 {
10684   ClutterActorIter iter;
10685
10686   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10687
10688   if (self->priv->n_children == 0)
10689     return;
10690
10691   g_object_freeze_notify (G_OBJECT (self));
10692
10693   clutter_actor_iter_init (&iter, self);
10694   while (clutter_actor_iter_next (&iter, NULL))
10695     clutter_actor_iter_destroy (&iter);
10696
10697   g_object_thaw_notify (G_OBJECT (self));
10698
10699   /* sanity check */
10700   g_assert (self->priv->first_child == NULL);
10701   g_assert (self->priv->last_child == NULL);
10702   g_assert (self->priv->n_children == 0);
10703 }
10704
10705 typedef struct _InsertBetweenData {
10706   ClutterActor *prev_sibling;
10707   ClutterActor *next_sibling;
10708 } InsertBetweenData;
10709
10710 static void
10711 insert_child_between (ClutterActor *self,
10712                       ClutterActor *child,
10713                       gpointer      data_)
10714 {
10715   InsertBetweenData *data = data_;
10716   ClutterActor *prev_sibling = data->prev_sibling;
10717   ClutterActor *next_sibling = data->next_sibling;
10718
10719   child->priv->parent = self;
10720   child->priv->prev_sibling = prev_sibling;
10721   child->priv->next_sibling = next_sibling;
10722
10723   if (prev_sibling != NULL)
10724     prev_sibling->priv->next_sibling = child;
10725
10726   if (next_sibling != NULL)
10727     next_sibling->priv->prev_sibling = child;
10728
10729   if (child->priv->prev_sibling == NULL)
10730     self->priv->first_child = child;
10731
10732   if (child->priv->next_sibling == NULL)
10733     self->priv->last_child = child;
10734 }
10735
10736 /**
10737  * clutter_actor_replace_child:
10738  * @self: a #ClutterActor
10739  * @old_child: the child of @self to replace
10740  * @new_child: the #ClutterActor to replace @old_child
10741  *
10742  * Replaces @old_child with @new_child in the list of children of @self.
10743  *
10744  * Since: 1.10
10745  */
10746 void
10747 clutter_actor_replace_child (ClutterActor *self,
10748                              ClutterActor *old_child,
10749                              ClutterActor *new_child)
10750 {
10751   ClutterActor *prev_sibling, *next_sibling;
10752   InsertBetweenData clos;
10753
10754   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10755   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
10756   g_return_if_fail (old_child->priv->parent == self);
10757   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
10758   g_return_if_fail (old_child != new_child);
10759   g_return_if_fail (new_child != self);
10760   g_return_if_fail (new_child->priv->parent == NULL);
10761
10762   prev_sibling = old_child->priv->prev_sibling;
10763   next_sibling = old_child->priv->next_sibling;
10764   clutter_actor_remove_child_internal (self, old_child,
10765                                        REMOVE_CHILD_DEFAULT_FLAGS);
10766
10767   clos.prev_sibling = prev_sibling;
10768   clos.next_sibling = next_sibling;
10769   clutter_actor_add_child_internal (self, new_child,
10770                                     ADD_CHILD_DEFAULT_FLAGS,
10771                                     insert_child_between,
10772                                     &clos);
10773 }
10774
10775 /**
10776  * clutter_actor_unparent:
10777  * @self: a #ClutterActor
10778  *
10779  * Removes the parent of @self.
10780  *
10781  * This will cause the parent of @self to release the reference
10782  * acquired when calling clutter_actor_set_parent(), so if you
10783  * want to keep @self you will have to acquire a reference of
10784  * your own, through g_object_ref().
10785  *
10786  * This function should only be called by legacy #ClutterActor<!-- -->s
10787  * implementing the #ClutterContainer interface.
10788  *
10789  * Since: 0.1.1
10790  *
10791  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
10792  */
10793 void
10794 clutter_actor_unparent (ClutterActor *self)
10795 {
10796   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10797
10798   if (self->priv->parent == NULL)
10799     return;
10800
10801   clutter_actor_remove_child_internal (self->priv->parent, self,
10802                                        REMOVE_CHILD_LEGACY_FLAGS);
10803 }
10804
10805 /**
10806  * clutter_actor_reparent:
10807  * @self: a #ClutterActor
10808  * @new_parent: the new #ClutterActor parent
10809  *
10810  * Resets the parent actor of @self.
10811  *
10812  * This function is logically equivalent to calling clutter_actor_unparent()
10813  * and clutter_actor_set_parent(), but more efficiently implemented, as it
10814  * ensures the child is not finalized when unparented, and emits the
10815  * #ClutterActor::parent-set signal only once.
10816  *
10817  * In reality, calling this function is less useful than it sounds, as some
10818  * application code may rely on changes in the intermediate state between
10819  * removal and addition of the actor from its old parent to the @new_parent.
10820  * Thus, it is strongly encouraged to avoid using this function in application
10821  * code.
10822  *
10823  * Since: 0.2
10824  *
10825  * Deprecated: 1.10: Use clutter_actor_remove_child() and
10826  *   clutter_actor_add_child() instead; remember to take a reference on
10827  *   the actor being removed before calling clutter_actor_remove_child()
10828  *   to avoid the reference count dropping to zero and the actor being
10829  *   destroyed.
10830  */
10831 void
10832 clutter_actor_reparent (ClutterActor *self,
10833                         ClutterActor *new_parent)
10834 {
10835   ClutterActorPrivate *priv;
10836
10837   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10838   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
10839   g_return_if_fail (self != new_parent);
10840
10841   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10842     {
10843       g_warning ("Cannot set a parent on a toplevel actor");
10844       return;
10845     }
10846
10847   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
10848     {
10849       g_warning ("Cannot set a parent currently being destroyed");
10850       return;
10851     }
10852
10853   priv = self->priv;
10854
10855   if (priv->parent != new_parent)
10856     {
10857       ClutterActor *old_parent;
10858
10859       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10860
10861       old_parent = priv->parent;
10862
10863       g_object_ref (self);
10864
10865       if (old_parent != NULL)
10866         {
10867          /* go through the Container implementation if this is a regular
10868           * child and not an internal one
10869           */
10870          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10871            {
10872              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
10873
10874              /* this will have to call unparent() */
10875              clutter_container_remove_actor (parent, self);
10876            }
10877          else
10878            clutter_actor_remove_child_internal (old_parent, self,
10879                                                 REMOVE_CHILD_LEGACY_FLAGS);
10880         }
10881
10882       /* Note, will call set_parent() */
10883       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10884         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
10885       else
10886         clutter_actor_add_child_internal (new_parent, self,
10887                                           ADD_CHILD_LEGACY_FLAGS,
10888                                           insert_child_at_depth,
10889                                           NULL);
10890
10891       /* we emit the ::parent-set signal once */
10892       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
10893
10894       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10895
10896       /* the IN_REPARENT flag suspends state updates */
10897       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
10898
10899       g_object_unref (self);
10900    }
10901 }
10902
10903 /**
10904  * clutter_actor_contains:
10905  * @self: A #ClutterActor
10906  * @descendant: A #ClutterActor, possibly contained in @self
10907  *
10908  * Determines if @descendant is contained inside @self (either as an
10909  * immediate child, or as a deeper descendant). If @self and
10910  * @descendant point to the same actor then it will also return %TRUE.
10911  *
10912  * Return value: whether @descendent is contained within @self
10913  *
10914  * Since: 1.4
10915  */
10916 gboolean
10917 clutter_actor_contains (ClutterActor *self,
10918                         ClutterActor *descendant)
10919 {
10920   ClutterActor *actor;
10921
10922   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10923   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
10924
10925   for (actor = descendant; actor; actor = actor->priv->parent)
10926     if (actor == self)
10927       return TRUE;
10928
10929   return FALSE;
10930 }
10931
10932 /**
10933  * clutter_actor_set_child_above_sibling:
10934  * @self: a #ClutterActor
10935  * @child: a #ClutterActor child of @self
10936  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10937  *
10938  * Sets @child to be above @sibling in the list of children of @self.
10939  *
10940  * If @sibling is %NULL, @child will be the new last child of @self.
10941  *
10942  * This function is logically equivalent to removing @child and using
10943  * clutter_actor_insert_child_above(), but it will not emit signals
10944  * or change state on @child.
10945  *
10946  * Since: 1.10
10947  */
10948 void
10949 clutter_actor_set_child_above_sibling (ClutterActor *self,
10950                                        ClutterActor *child,
10951                                        ClutterActor *sibling)
10952 {
10953   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10954   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10955   g_return_if_fail (child->priv->parent == self);
10956   g_return_if_fail (child != sibling);
10957   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10958
10959   if (sibling != NULL)
10960     g_return_if_fail (sibling->priv->parent == self);
10961
10962   /* we don't want to change the state of child, or emit signals, or
10963    * regenerate ChildMeta instances here, but we still want to follow
10964    * the correct sequence of steps encoded in remove_child() and
10965    * add_child(), so that correctness is ensured, and we only go
10966    * through one known code path.
10967    */
10968   g_object_ref (child);
10969   clutter_actor_remove_child_internal (self, child, 0);
10970   clutter_actor_add_child_internal (self, child,
10971                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10972                                     insert_child_above,
10973                                     sibling);
10974
10975   clutter_actor_queue_relayout (self);
10976 }
10977
10978 /**
10979  * clutter_actor_set_child_below_sibling:
10980  * @self: a #ClutterActor
10981  * @child: a #ClutterActor child of @self
10982  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10983  *
10984  * Sets @child to be below @sibling in the list of children of @self.
10985  *
10986  * If @sibling is %NULL, @child will be the new first child of @self.
10987  *
10988  * This function is logically equivalent to removing @self and using
10989  * clutter_actor_insert_child_below(), but it will not emit signals
10990  * or change state on @child.
10991  *
10992  * Since: 1.10
10993  */
10994 void
10995 clutter_actor_set_child_below_sibling (ClutterActor *self,
10996                                        ClutterActor *child,
10997                                        ClutterActor *sibling)
10998 {
10999   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11000   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11001   g_return_if_fail (child->priv->parent == self);
11002   g_return_if_fail (child != sibling);
11003   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11004
11005   if (sibling != NULL)
11006     g_return_if_fail (sibling->priv->parent == self);
11007
11008   /* see the comment in set_child_above_sibling() */
11009   g_object_ref (child);
11010   clutter_actor_remove_child_internal (self, child, 0);
11011   clutter_actor_add_child_internal (self, child,
11012                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11013                                     insert_child_below,
11014                                     sibling);
11015
11016   clutter_actor_queue_relayout (self);
11017 }
11018
11019 /**
11020  * clutter_actor_set_child_at_index:
11021  * @self: a #ClutterActor
11022  * @child: a #ClutterActor child of @self
11023  * @index_: the new index for @child
11024  *
11025  * Changes the index of @child in the list of children of @self.
11026  *
11027  * This function is logically equivalent to removing @child and
11028  * calling clutter_actor_insert_child_at_index(), but it will not
11029  * emit signals or change state on @child.
11030  *
11031  * Since: 1.10
11032  */
11033 void
11034 clutter_actor_set_child_at_index (ClutterActor *self,
11035                                   ClutterActor *child,
11036                                   gint          index_)
11037 {
11038   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11039   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11040   g_return_if_fail (child->priv->parent == self);
11041   g_return_if_fail (index_ <= self->priv->n_children);
11042
11043   g_object_ref (child);
11044   clutter_actor_remove_child_internal (self, child, 0);
11045   clutter_actor_add_child_internal (self, child,
11046                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11047                                     insert_child_at_index,
11048                                     GINT_TO_POINTER (index_));
11049
11050   clutter_actor_queue_relayout (self);
11051 }
11052
11053 /**
11054  * clutter_actor_raise:
11055  * @self: A #ClutterActor
11056  * @below: (allow-none): A #ClutterActor to raise above.
11057  *
11058  * Puts @self above @below.
11059  *
11060  * Both actors must have the same parent, and the parent must implement
11061  * the #ClutterContainer interface
11062  *
11063  * This function calls clutter_container_raise_child() internally.
11064  *
11065  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11066  */
11067 void
11068 clutter_actor_raise (ClutterActor *self,
11069                      ClutterActor *below)
11070 {
11071   ClutterActor *parent;
11072
11073   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11074
11075   parent = clutter_actor_get_parent (self);
11076   if (parent == NULL)
11077     {
11078       g_warning ("%s: Actor '%s' is not inside a container",
11079                  G_STRFUNC,
11080                  _clutter_actor_get_debug_name (self));
11081       return;
11082     }
11083
11084   if (below != NULL)
11085     {
11086       if (parent != clutter_actor_get_parent (below))
11087         {
11088           g_warning ("%s Actor '%s' is not in the same container as "
11089                      "actor '%s'",
11090                      G_STRFUNC,
11091                      _clutter_actor_get_debug_name (self),
11092                      _clutter_actor_get_debug_name (below));
11093           return;
11094         }
11095     }
11096
11097   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11098 }
11099
11100 /**
11101  * clutter_actor_lower:
11102  * @self: A #ClutterActor
11103  * @above: (allow-none): A #ClutterActor to lower below
11104  *
11105  * Puts @self below @above.
11106  *
11107  * Both actors must have the same parent, and the parent must implement
11108  * the #ClutterContainer interface.
11109  *
11110  * This function calls clutter_container_lower_child() internally.
11111  *
11112  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11113  */
11114 void
11115 clutter_actor_lower (ClutterActor *self,
11116                      ClutterActor *above)
11117 {
11118   ClutterActor *parent;
11119
11120   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11121
11122   parent = clutter_actor_get_parent (self);
11123   if (parent == NULL)
11124     {
11125       g_warning ("%s: Actor of type %s is not inside a container",
11126                  G_STRFUNC,
11127                  _clutter_actor_get_debug_name (self));
11128       return;
11129     }
11130
11131   if (above)
11132     {
11133       if (parent != clutter_actor_get_parent (above))
11134         {
11135           g_warning ("%s: Actor '%s' is not in the same container as "
11136                      "actor '%s'",
11137                      G_STRFUNC,
11138                      _clutter_actor_get_debug_name (self),
11139                      _clutter_actor_get_debug_name (above));
11140           return;
11141         }
11142     }
11143
11144   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11145 }
11146
11147 /**
11148  * clutter_actor_raise_top:
11149  * @self: A #ClutterActor
11150  *
11151  * Raises @self to the top.
11152  *
11153  * This function calls clutter_actor_raise() internally.
11154  *
11155  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11156  *   a %NULL sibling, instead.
11157  */
11158 void
11159 clutter_actor_raise_top (ClutterActor *self)
11160 {
11161   clutter_actor_raise (self, NULL);
11162 }
11163
11164 /**
11165  * clutter_actor_lower_bottom:
11166  * @self: A #ClutterActor
11167  *
11168  * Lowers @self to the bottom.
11169  *
11170  * This function calls clutter_actor_lower() internally.
11171  *
11172  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11173  *   a %NULL sibling, instead.
11174  */
11175 void
11176 clutter_actor_lower_bottom (ClutterActor *self)
11177 {
11178   clutter_actor_lower (self, NULL);
11179 }
11180
11181 /*
11182  * Event handling
11183  */
11184
11185 /**
11186  * clutter_actor_event:
11187  * @actor: a #ClutterActor
11188  * @event: a #ClutterEvent
11189  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11190  *
11191  * This function is used to emit an event on the main stage.
11192  * You should rarely need to use this function, except for
11193  * synthetising events.
11194  *
11195  * Return value: the return value from the signal emission: %TRUE
11196  *   if the actor handled the event, or %FALSE if the event was
11197  *   not handled
11198  *
11199  * Since: 0.6
11200  */
11201 gboolean
11202 clutter_actor_event (ClutterActor *actor,
11203                      ClutterEvent *event,
11204                      gboolean      capture)
11205 {
11206   gboolean retval = FALSE;
11207   gint signal_num = -1;
11208
11209   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11210   g_return_val_if_fail (event != NULL, FALSE);
11211
11212   g_object_ref (actor);
11213
11214   if (capture)
11215     {
11216       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11217                      event,
11218                      &retval);
11219       goto out;
11220     }
11221
11222   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11223
11224   if (!retval)
11225     {
11226       switch (event->type)
11227         {
11228         case CLUTTER_NOTHING:
11229           break;
11230         case CLUTTER_BUTTON_PRESS:
11231           signal_num = BUTTON_PRESS_EVENT;
11232           break;
11233         case CLUTTER_BUTTON_RELEASE:
11234           signal_num = BUTTON_RELEASE_EVENT;
11235           break;
11236         case CLUTTER_SCROLL:
11237           signal_num = SCROLL_EVENT;
11238           break;
11239         case CLUTTER_KEY_PRESS:
11240           signal_num = KEY_PRESS_EVENT;
11241           break;
11242         case CLUTTER_KEY_RELEASE:
11243           signal_num = KEY_RELEASE_EVENT;
11244           break;
11245         case CLUTTER_MOTION:
11246           signal_num = MOTION_EVENT;
11247           break;
11248         case CLUTTER_ENTER:
11249           signal_num = ENTER_EVENT;
11250           break;
11251         case CLUTTER_LEAVE:
11252           signal_num = LEAVE_EVENT;
11253           break;
11254         case CLUTTER_DELETE:
11255         case CLUTTER_DESTROY_NOTIFY:
11256         case CLUTTER_CLIENT_MESSAGE:
11257         default:
11258           signal_num = -1;
11259           break;
11260         }
11261
11262       if (signal_num != -1)
11263         g_signal_emit (actor, actor_signals[signal_num], 0,
11264                        event, &retval);
11265     }
11266
11267 out:
11268   g_object_unref (actor);
11269
11270   return retval;
11271 }
11272
11273 /**
11274  * clutter_actor_set_reactive:
11275  * @actor: a #ClutterActor
11276  * @reactive: whether the actor should be reactive to events
11277  *
11278  * Sets @actor as reactive. Reactive actors will receive events.
11279  *
11280  * Since: 0.6
11281  */
11282 void
11283 clutter_actor_set_reactive (ClutterActor *actor,
11284                             gboolean      reactive)
11285 {
11286   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11287
11288   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11289     return;
11290
11291   if (reactive)
11292     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11293   else
11294     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11295
11296   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11297 }
11298
11299 /**
11300  * clutter_actor_get_reactive:
11301  * @actor: a #ClutterActor
11302  *
11303  * Checks whether @actor is marked as reactive.
11304  *
11305  * Return value: %TRUE if the actor is reactive
11306  *
11307  * Since: 0.6
11308  */
11309 gboolean
11310 clutter_actor_get_reactive (ClutterActor *actor)
11311 {
11312   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11313
11314   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11315 }
11316
11317 /**
11318  * clutter_actor_get_anchor_point:
11319  * @self: a #ClutterActor
11320  * @anchor_x: (out): return location for the X coordinate of the anchor point
11321  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11322  *
11323  * Gets the current anchor point of the @actor in pixels.
11324  *
11325  * Since: 0.6
11326  */
11327 void
11328 clutter_actor_get_anchor_point (ClutterActor *self,
11329                                 gfloat       *anchor_x,
11330                                 gfloat       *anchor_y)
11331 {
11332   const ClutterTransformInfo *info;
11333
11334   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11335
11336   info = _clutter_actor_get_transform_info_or_defaults (self);
11337   clutter_anchor_coord_get_units (self, &info->anchor,
11338                                   anchor_x,
11339                                   anchor_y,
11340                                   NULL);
11341 }
11342
11343 /**
11344  * clutter_actor_set_anchor_point:
11345  * @self: a #ClutterActor
11346  * @anchor_x: X coordinate of the anchor point
11347  * @anchor_y: Y coordinate of the anchor point
11348  *
11349  * Sets an anchor point for @self. The anchor point is a point in the
11350  * coordinate space of an actor to which the actor position within its
11351  * parent is relative; the default is (0, 0), i.e. the top-left corner
11352  * of the actor.
11353  *
11354  * Since: 0.6
11355  */
11356 void
11357 clutter_actor_set_anchor_point (ClutterActor *self,
11358                                 gfloat        anchor_x,
11359                                 gfloat        anchor_y)
11360 {
11361   ClutterTransformInfo *info;
11362   ClutterActorPrivate *priv;
11363   gboolean changed = FALSE;
11364   gfloat old_anchor_x, old_anchor_y;
11365   GObject *obj;
11366
11367   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11368
11369   obj = G_OBJECT (self);
11370   priv = self->priv;
11371   info = _clutter_actor_get_transform_info (self);
11372
11373   g_object_freeze_notify (obj);
11374
11375   clutter_anchor_coord_get_units (self, &info->anchor,
11376                                   &old_anchor_x,
11377                                   &old_anchor_y,
11378                                   NULL);
11379
11380   if (info->anchor.is_fractional)
11381     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11382
11383   if (old_anchor_x != anchor_x)
11384     {
11385       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11386       changed = TRUE;
11387     }
11388
11389   if (old_anchor_y != anchor_y)
11390     {
11391       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11392       changed = TRUE;
11393     }
11394
11395   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11396
11397   if (changed)
11398     {
11399       priv->transform_valid = FALSE;
11400       clutter_actor_queue_redraw (self);
11401     }
11402
11403   g_object_thaw_notify (obj);
11404 }
11405
11406 /**
11407  * clutter_actor_get_anchor_point_gravity:
11408  * @self: a #ClutterActor
11409  *
11410  * Retrieves the anchor position expressed as a #ClutterGravity. If
11411  * the anchor point was specified using pixels or units this will
11412  * return %CLUTTER_GRAVITY_NONE.
11413  *
11414  * Return value: the #ClutterGravity used by the anchor point
11415  *
11416  * Since: 1.0
11417  */
11418 ClutterGravity
11419 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11420 {
11421   const ClutterTransformInfo *info;
11422
11423   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11424
11425   info = _clutter_actor_get_transform_info_or_defaults (self);
11426
11427   return clutter_anchor_coord_get_gravity (&info->anchor);
11428 }
11429
11430 /**
11431  * clutter_actor_move_anchor_point:
11432  * @self: a #ClutterActor
11433  * @anchor_x: X coordinate of the anchor point
11434  * @anchor_y: Y coordinate of the anchor point
11435  *
11436  * Sets an anchor point for the actor, and adjusts the actor postion so that
11437  * the relative position of the actor toward its parent remains the same.
11438  *
11439  * Since: 0.6
11440  */
11441 void
11442 clutter_actor_move_anchor_point (ClutterActor *self,
11443                                  gfloat        anchor_x,
11444                                  gfloat        anchor_y)
11445 {
11446   gfloat old_anchor_x, old_anchor_y;
11447   const ClutterTransformInfo *info;
11448
11449   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11450
11451   info = _clutter_actor_get_transform_info (self);
11452   clutter_anchor_coord_get_units (self, &info->anchor,
11453                                   &old_anchor_x,
11454                                   &old_anchor_y,
11455                                   NULL);
11456
11457   g_object_freeze_notify (G_OBJECT (self));
11458
11459   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11460
11461   if (self->priv->position_set)
11462     clutter_actor_move_by (self,
11463                            anchor_x - old_anchor_x,
11464                            anchor_y - old_anchor_y);
11465
11466   g_object_thaw_notify (G_OBJECT (self));
11467 }
11468
11469 /**
11470  * clutter_actor_move_anchor_point_from_gravity:
11471  * @self: a #ClutterActor
11472  * @gravity: #ClutterGravity.
11473  *
11474  * Sets an anchor point on the actor based on the given gravity, adjusting the
11475  * actor postion so that its relative position within its parent remains
11476  * unchanged.
11477  *
11478  * Since version 1.0 the anchor point will be stored as a gravity so
11479  * that if the actor changes size then the anchor point will move. For
11480  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11481  * and later double the size of the actor, the anchor point will move
11482  * to the bottom right.
11483  *
11484  * Since: 0.6
11485  */
11486 void
11487 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11488                                               ClutterGravity  gravity)
11489 {
11490   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11491   const ClutterTransformInfo *info;
11492   ClutterActorPrivate *priv;
11493
11494   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11495
11496   priv = self->priv;
11497   info = _clutter_actor_get_transform_info (self);
11498
11499   g_object_freeze_notify (G_OBJECT (self));
11500
11501   clutter_anchor_coord_get_units (self, &info->anchor,
11502                                   &old_anchor_x,
11503                                   &old_anchor_y,
11504                                   NULL);
11505   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11506   clutter_anchor_coord_get_units (self, &info->anchor,
11507                                   &new_anchor_x,
11508                                   &new_anchor_y,
11509                                   NULL);
11510
11511   if (priv->position_set)
11512     clutter_actor_move_by (self,
11513                            new_anchor_x - old_anchor_x,
11514                            new_anchor_y - old_anchor_y);
11515
11516   g_object_thaw_notify (G_OBJECT (self));
11517 }
11518
11519 /**
11520  * clutter_actor_set_anchor_point_from_gravity:
11521  * @self: a #ClutterActor
11522  * @gravity: #ClutterGravity.
11523  *
11524  * Sets an anchor point on the actor, based on the given gravity (this is a
11525  * convenience function wrapping clutter_actor_set_anchor_point()).
11526  *
11527  * Since version 1.0 the anchor point will be stored as a gravity so
11528  * that if the actor changes size then the anchor point will move. For
11529  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11530  * and later double the size of the actor, the anchor point will move
11531  * to the bottom right.
11532  *
11533  * Since: 0.6
11534  */
11535 void
11536 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11537                                              ClutterGravity  gravity)
11538 {
11539   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11540
11541   if (gravity == CLUTTER_GRAVITY_NONE)
11542     clutter_actor_set_anchor_point (self, 0, 0);
11543   else
11544     {
11545       GObject *obj = G_OBJECT (self);
11546       ClutterTransformInfo *info;
11547
11548       g_object_freeze_notify (obj);
11549
11550       info = _clutter_actor_get_transform_info (self);
11551       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11552
11553       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11554       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11555       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11556
11557       self->priv->transform_valid = FALSE;
11558
11559       clutter_actor_queue_redraw (self);
11560
11561       g_object_thaw_notify (obj);
11562     }
11563 }
11564
11565 static void
11566 clutter_container_iface_init (ClutterContainerIface *iface)
11567 {
11568   /* we don't override anything, as ClutterContainer already has a default
11569    * implementation that we can use, and which calls into our own API.
11570    */
11571 }
11572
11573 typedef enum
11574 {
11575   PARSE_X,
11576   PARSE_Y,
11577   PARSE_WIDTH,
11578   PARSE_HEIGHT,
11579   PARSE_ANCHOR_X,
11580   PARSE_ANCHOR_Y
11581 } ParseDimension;
11582
11583 static gfloat
11584 parse_units (ClutterActor   *self,
11585              ParseDimension  dimension,
11586              JsonNode       *node)
11587 {
11588   GValue value = { 0, };
11589   gfloat retval = 0;
11590
11591   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11592     return 0;
11593
11594   json_node_get_value (node, &value);
11595
11596   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11597     {
11598       retval = (gfloat) g_value_get_int64 (&value);
11599     }
11600   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
11601     {
11602       retval = g_value_get_double (&value);
11603     }
11604   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
11605     {
11606       ClutterUnits units;
11607       gboolean res;
11608
11609       res = clutter_units_from_string (&units, g_value_get_string (&value));
11610       if (res)
11611         retval = clutter_units_to_pixels (&units);
11612       else
11613         {
11614           g_warning ("Invalid value '%s': integers, strings or floating point "
11615                      "values can be used for the x, y, width and height "
11616                      "properties. Valid modifiers for strings are 'px', 'mm', "
11617                      "'pt' and 'em'.",
11618                      g_value_get_string (&value));
11619           retval = 0;
11620         }
11621     }
11622   else
11623     {
11624       g_warning ("Invalid value of type '%s': integers, strings of floating "
11625                  "point values can be used for the x, y, width, height "
11626                  "anchor-x and anchor-y properties.",
11627                  g_type_name (G_VALUE_TYPE (&value)));
11628     }
11629
11630   g_value_unset (&value);
11631
11632   return retval;
11633 }
11634
11635 typedef struct {
11636   ClutterRotateAxis axis;
11637
11638   gdouble angle;
11639
11640   gfloat center_x;
11641   gfloat center_y;
11642   gfloat center_z;
11643 } RotationInfo;
11644
11645 static inline gboolean
11646 parse_rotation_array (ClutterActor *actor,
11647                       JsonArray    *array,
11648                       RotationInfo *info)
11649 {
11650   JsonNode *element;
11651
11652   if (json_array_get_length (array) != 2)
11653     return FALSE;
11654
11655   /* angle */
11656   element = json_array_get_element (array, 0);
11657   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
11658     info->angle = json_node_get_double (element);
11659   else
11660     return FALSE;
11661
11662   /* center */
11663   element = json_array_get_element (array, 1);
11664   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
11665     {
11666       JsonArray *center = json_node_get_array (element);
11667
11668       if (json_array_get_length (center) != 2)
11669         return FALSE;
11670
11671       switch (info->axis)
11672         {
11673         case CLUTTER_X_AXIS:
11674           info->center_y = parse_units (actor, PARSE_Y,
11675                                         json_array_get_element (center, 0));
11676           info->center_z = parse_units (actor, PARSE_Y,
11677                                         json_array_get_element (center, 1));
11678           return TRUE;
11679
11680         case CLUTTER_Y_AXIS:
11681           info->center_x = parse_units (actor, PARSE_X,
11682                                         json_array_get_element (center, 0));
11683           info->center_z = parse_units (actor, PARSE_X,
11684                                         json_array_get_element (center, 1));
11685           return TRUE;
11686
11687         case CLUTTER_Z_AXIS:
11688           info->center_x = parse_units (actor, PARSE_X,
11689                                         json_array_get_element (center, 0));
11690           info->center_y = parse_units (actor, PARSE_Y,
11691                                         json_array_get_element (center, 1));
11692           return TRUE;
11693         }
11694     }
11695
11696   return FALSE;
11697 }
11698
11699 static gboolean
11700 parse_rotation (ClutterActor *actor,
11701                 JsonNode     *node,
11702                 RotationInfo *info)
11703 {
11704   JsonArray *array;
11705   guint len, i;
11706   gboolean retval = FALSE;
11707
11708   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
11709     {
11710       g_warning ("Invalid node of type '%s' found, expecting an array",
11711                  json_node_type_name (node));
11712       return FALSE;
11713     }
11714
11715   array = json_node_get_array (node);
11716   len = json_array_get_length (array);
11717
11718   for (i = 0; i < len; i++)
11719     {
11720       JsonNode *element = json_array_get_element (array, i);
11721       JsonObject *object;
11722       JsonNode *member;
11723
11724       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
11725         {
11726           g_warning ("Invalid node of type '%s' found, expecting an object",
11727                      json_node_type_name (element));
11728           return FALSE;
11729         }
11730
11731       object = json_node_get_object (element);
11732
11733       if (json_object_has_member (object, "x-axis"))
11734         {
11735           member = json_object_get_member (object, "x-axis");
11736
11737           info->axis = CLUTTER_X_AXIS;
11738
11739           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11740             {
11741               info->angle = json_node_get_double (member);
11742               retval = TRUE;
11743             }
11744           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11745             retval = parse_rotation_array (actor,
11746                                            json_node_get_array (member),
11747                                            info);
11748           else
11749             retval = FALSE;
11750         }
11751       else if (json_object_has_member (object, "y-axis"))
11752         {
11753           member = json_object_get_member (object, "y-axis");
11754
11755           info->axis = CLUTTER_Y_AXIS;
11756
11757           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11758             {
11759               info->angle = json_node_get_double (member);
11760               retval = TRUE;
11761             }
11762           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11763             retval = parse_rotation_array (actor,
11764                                            json_node_get_array (member),
11765                                            info);
11766           else
11767             retval = FALSE;
11768         }
11769       else if (json_object_has_member (object, "z-axis"))
11770         {
11771           member = json_object_get_member (object, "z-axis");
11772
11773           info->axis = CLUTTER_Z_AXIS;
11774
11775           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11776             {
11777               info->angle = json_node_get_double (member);
11778               retval = TRUE;
11779             }
11780           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11781             retval = parse_rotation_array (actor,
11782                                            json_node_get_array (member),
11783                                            info);
11784           else
11785             retval = FALSE;
11786         }
11787     }
11788
11789   return retval;
11790 }
11791
11792 static GSList *
11793 parse_actor_metas (ClutterScript *script,
11794                    ClutterActor  *actor,
11795                    JsonNode      *node)
11796 {
11797   GList *elements, *l;
11798   GSList *retval = NULL;
11799
11800   if (!JSON_NODE_HOLDS_ARRAY (node))
11801     return NULL;
11802
11803   elements = json_array_get_elements (json_node_get_array (node));
11804
11805   for (l = elements; l != NULL; l = l->next)
11806     {
11807       JsonNode *element = l->data;
11808       const gchar *id_ = _clutter_script_get_id_from_node (element);
11809       GObject *meta;
11810
11811       if (id_ == NULL || *id_ == '\0')
11812         continue;
11813
11814       meta = clutter_script_get_object (script, id_);
11815       if (meta == NULL)
11816         continue;
11817
11818       retval = g_slist_prepend (retval, meta);
11819     }
11820
11821   g_list_free (elements);
11822
11823   return g_slist_reverse (retval);
11824 }
11825
11826 static GSList *
11827 parse_behaviours (ClutterScript *script,
11828                   ClutterActor  *actor,
11829                   JsonNode      *node)
11830 {
11831   GList *elements, *l;
11832   GSList *retval = NULL;
11833
11834   if (!JSON_NODE_HOLDS_ARRAY (node))
11835     return NULL;
11836
11837   elements = json_array_get_elements (json_node_get_array (node));
11838
11839   for (l = elements; l != NULL; l = l->next)
11840     {
11841       JsonNode *element = l->data;
11842       const gchar *id_ = _clutter_script_get_id_from_node (element);
11843       GObject *behaviour;
11844
11845       if (id_ == NULL || *id_ == '\0')
11846         continue;
11847
11848       behaviour = clutter_script_get_object (script, id_);
11849       if (behaviour == NULL)
11850         continue;
11851
11852       retval = g_slist_prepend (retval, behaviour);
11853     }
11854
11855   g_list_free (elements);
11856
11857   return g_slist_reverse (retval);
11858 }
11859
11860 static gboolean
11861 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
11862                                  ClutterScript     *script,
11863                                  GValue            *value,
11864                                  const gchar       *name,
11865                                  JsonNode          *node)
11866 {
11867   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11868   gboolean retval = FALSE;
11869
11870   if ((name[0] == 'x' && name[1] == '\0') ||
11871       (name[0] == 'y' && name[1] == '\0') ||
11872       (strcmp (name, "width") == 0) ||
11873       (strcmp (name, "height") == 0) ||
11874       (strcmp (name, "anchor_x") == 0) ||
11875       (strcmp (name, "anchor_y") == 0))
11876     {
11877       ParseDimension dimension;
11878       gfloat units;
11879
11880       if (name[0] == 'x')
11881         dimension = PARSE_X;
11882       else if (name[0] == 'y')
11883         dimension = PARSE_Y;
11884       else if (name[0] == 'w')
11885         dimension = PARSE_WIDTH;
11886       else if (name[0] == 'h')
11887         dimension = PARSE_HEIGHT;
11888       else if (name[0] == 'a' && name[7] == 'x')
11889         dimension = PARSE_ANCHOR_X;
11890       else if (name[0] == 'a' && name[7] == 'y')
11891         dimension = PARSE_ANCHOR_Y;
11892       else
11893         return FALSE;
11894
11895       units = parse_units (actor, dimension, node);
11896
11897       /* convert back to pixels: all properties are pixel-based */
11898       g_value_init (value, G_TYPE_FLOAT);
11899       g_value_set_float (value, units);
11900
11901       retval = TRUE;
11902     }
11903   else if (strcmp (name, "rotation") == 0)
11904     {
11905       RotationInfo *info;
11906
11907       info = g_slice_new0 (RotationInfo);
11908       retval = parse_rotation (actor, node, info);
11909
11910       if (retval)
11911         {
11912           g_value_init (value, G_TYPE_POINTER);
11913           g_value_set_pointer (value, info);
11914         }
11915       else
11916         g_slice_free (RotationInfo, info);
11917     }
11918   else if (strcmp (name, "behaviours") == 0)
11919     {
11920       GSList *l;
11921
11922 #ifdef CLUTTER_ENABLE_DEBUG
11923       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
11924         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
11925                                      "and it should not be used in newly "
11926                                      "written ClutterScript definitions.");
11927 #endif
11928
11929       l = parse_behaviours (script, actor, node);
11930
11931       g_value_init (value, G_TYPE_POINTER);
11932       g_value_set_pointer (value, l);
11933
11934       retval = TRUE;
11935     }
11936   else if (strcmp (name, "actions") == 0 ||
11937            strcmp (name, "constraints") == 0 ||
11938            strcmp (name, "effects") == 0)
11939     {
11940       GSList *l;
11941
11942       l = parse_actor_metas (script, actor, node);
11943
11944       g_value_init (value, G_TYPE_POINTER);
11945       g_value_set_pointer (value, l);
11946
11947       retval = TRUE;
11948     }
11949
11950   return retval;
11951 }
11952
11953 static void
11954 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
11955                                    ClutterScript     *script,
11956                                    const gchar       *name,
11957                                    const GValue      *value)
11958 {
11959   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11960
11961 #ifdef CLUTTER_ENABLE_DEBUG
11962   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
11963     {
11964       gchar *tmp = g_strdup_value_contents (value);
11965
11966       CLUTTER_NOTE (SCRIPT,
11967                     "in ClutterActor::set_custom_property('%s') = %s",
11968                     name,
11969                     tmp);
11970
11971       g_free (tmp);
11972     }
11973 #endif /* CLUTTER_ENABLE_DEBUG */
11974
11975   if (strcmp (name, "rotation") == 0)
11976     {
11977       RotationInfo *info;
11978
11979       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11980         return;
11981
11982       info = g_value_get_pointer (value);
11983
11984       clutter_actor_set_rotation (actor,
11985                                   info->axis, info->angle,
11986                                   info->center_x,
11987                                   info->center_y,
11988                                   info->center_z);
11989
11990       g_slice_free (RotationInfo, info);
11991
11992       return;
11993     }
11994
11995   if (strcmp (name, "behaviours") == 0)
11996     {
11997       GSList *behaviours, *l;
11998
11999       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12000         return;
12001
12002       behaviours = g_value_get_pointer (value);
12003       for (l = behaviours; l != NULL; l = l->next)
12004         {
12005           ClutterBehaviour *behaviour = l->data;
12006
12007           clutter_behaviour_apply (behaviour, actor);
12008         }
12009
12010       g_slist_free (behaviours);
12011
12012       return;
12013     }
12014
12015   if (strcmp (name, "actions") == 0 ||
12016       strcmp (name, "constraints") == 0 ||
12017       strcmp (name, "effects") == 0)
12018     {
12019       GSList *metas, *l;
12020
12021       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12022         return;
12023
12024       metas = g_value_get_pointer (value);
12025       for (l = metas; l != NULL; l = l->next)
12026         {
12027           if (name[0] == 'a')
12028             clutter_actor_add_action (actor, l->data);
12029
12030           if (name[0] == 'c')
12031             clutter_actor_add_constraint (actor, l->data);
12032
12033           if (name[0] == 'e')
12034             clutter_actor_add_effect (actor, l->data);
12035         }
12036
12037       g_slist_free (metas);
12038
12039       return;
12040     }
12041
12042   g_object_set_property (G_OBJECT (scriptable), name, value);
12043 }
12044
12045 static void
12046 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12047 {
12048   iface->parse_custom_node = clutter_actor_parse_custom_node;
12049   iface->set_custom_property = clutter_actor_set_custom_property;
12050 }
12051
12052 static ClutterActorMeta *
12053 get_meta_from_animation_property (ClutterActor  *actor,
12054                                   const gchar   *name,
12055                                   gchar        **name_p)
12056 {
12057   ClutterActorPrivate *priv = actor->priv;
12058   ClutterActorMeta *meta = NULL;
12059   gchar **tokens;
12060
12061   /* if this is not a special property, fall through */
12062   if (name[0] != '@')
12063     return NULL;
12064
12065   /* detect the properties named using the following spec:
12066    *
12067    *   @<section>.<meta-name>.<property-name>
12068    *
12069    * where <section> can be one of the following:
12070    *
12071    *   - actions
12072    *   - constraints
12073    *   - effects
12074    *
12075    * and <meta-name> is the name set on a specific ActorMeta
12076    */
12077
12078   tokens = g_strsplit (name + 1, ".", -1);
12079   if (tokens == NULL || g_strv_length (tokens) != 3)
12080     {
12081       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12082                     name + 1);
12083       g_strfreev (tokens);
12084       return NULL;
12085     }
12086
12087   if (strcmp (tokens[0], "actions") == 0)
12088     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12089
12090   if (strcmp (tokens[0], "constraints") == 0)
12091     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12092
12093   if (strcmp (tokens[0], "effects") == 0)
12094     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12095
12096   if (name_p != NULL)
12097     *name_p = g_strdup (tokens[2]);
12098
12099   CLUTTER_NOTE (ANIMATION,
12100                 "Looking for property '%s' of object '%s' in section '%s'",
12101                 tokens[2],
12102                 tokens[1],
12103                 tokens[0]);
12104
12105   g_strfreev (tokens);
12106
12107   return meta;
12108 }
12109
12110 static GParamSpec *
12111 clutter_actor_find_property (ClutterAnimatable *animatable,
12112                              const gchar       *property_name)
12113 {
12114   ClutterActorMeta *meta = NULL;
12115   GObjectClass *klass = NULL;
12116   GParamSpec *pspec = NULL;
12117   gchar *p_name = NULL;
12118
12119   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12120                                            property_name,
12121                                            &p_name);
12122
12123   if (meta != NULL)
12124     {
12125       klass = G_OBJECT_GET_CLASS (meta);
12126
12127       pspec = g_object_class_find_property (klass, p_name);
12128     }
12129   else
12130     {
12131       klass = G_OBJECT_GET_CLASS (animatable);
12132
12133       pspec = g_object_class_find_property (klass, property_name);
12134     }
12135
12136   g_free (p_name);
12137
12138   return pspec;
12139 }
12140
12141 static void
12142 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12143                                  const gchar       *property_name,
12144                                  GValue            *initial)
12145 {
12146   ClutterActorMeta *meta = NULL;
12147   gchar *p_name = NULL;
12148
12149   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12150                                            property_name,
12151                                            &p_name);
12152
12153   if (meta != NULL)
12154     g_object_get_property (G_OBJECT (meta), p_name, initial);
12155   else
12156     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12157
12158   g_free (p_name);
12159 }
12160
12161 static void
12162 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12163                                const gchar       *property_name,
12164                                const GValue      *final)
12165 {
12166   ClutterActorMeta *meta = NULL;
12167   gchar *p_name = NULL;
12168
12169   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12170                                            property_name,
12171                                            &p_name);
12172   if (meta != NULL)
12173     g_object_set_property (G_OBJECT (meta), p_name, final);
12174   else
12175     g_object_set_property (G_OBJECT (animatable), property_name, final);
12176
12177   g_free (p_name);
12178 }
12179
12180 static void
12181 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12182 {
12183   iface->find_property = clutter_actor_find_property;
12184   iface->get_initial_state = clutter_actor_get_initial_state;
12185   iface->set_final_state = clutter_actor_set_final_state;
12186 }
12187
12188 /**
12189  * clutter_actor_transform_stage_point:
12190  * @self: A #ClutterActor
12191  * @x: (in): x screen coordinate of the point to unproject
12192  * @y: (in): y screen coordinate of the point to unproject
12193  * @x_out: (out): return location for the unprojected x coordinance
12194  * @y_out: (out): return location for the unprojected y coordinance
12195  *
12196  * This function translates screen coordinates (@x, @y) to
12197  * coordinates relative to the actor. For example, it can be used to translate
12198  * screen events from global screen coordinates into actor-local coordinates.
12199  *
12200  * The conversion can fail, notably if the transform stack results in the
12201  * actor being projected on the screen as a mere line.
12202  *
12203  * The conversion should not be expected to be pixel-perfect due to the
12204  * nature of the operation. In general the error grows when the skewing
12205  * of the actor rectangle on screen increases.
12206  *
12207  * <note><para>This function can be computationally intensive.</para></note>
12208  *
12209  * <note><para>This function only works when the allocation is up-to-date,
12210  * i.e. inside of paint().</para></note>
12211  *
12212  * Return value: %TRUE if conversion was successful.
12213  *
12214  * Since: 0.6
12215  */
12216 gboolean
12217 clutter_actor_transform_stage_point (ClutterActor *self,
12218                                      gfloat        x,
12219                                      gfloat        y,
12220                                      gfloat       *x_out,
12221                                      gfloat       *y_out)
12222 {
12223   ClutterVertex v[4];
12224   float ST[3][3];
12225   float RQ[3][3];
12226   int du, dv, xi, yi;
12227   float px, py;
12228   float xf, yf, wf, det;
12229   ClutterActorPrivate *priv;
12230
12231   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12232
12233   priv = self->priv;
12234
12235   /* This implementation is based on the quad -> quad projection algorithm
12236    * described by Paul Heckbert in:
12237    *
12238    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12239    *
12240    * and the sample implementation at:
12241    *
12242    *   http://www.cs.cmu.edu/~ph/src/texfund/
12243    *
12244    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12245    * quad to rectangle only, which significantly simplifies things; the
12246    * function calls have been unrolled, and most of the math is done in fixed
12247    * point.
12248    */
12249
12250   clutter_actor_get_abs_allocation_vertices (self, v);
12251
12252   /* Keeping these as ints simplifies the multiplication (no significant
12253    * loss of precision here).
12254    */
12255   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12256   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12257
12258   if (!du || !dv)
12259     return FALSE;
12260
12261 #define UX2FP(x)        (x)
12262 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12263
12264   /* First, find mapping from unit uv square to xy quadrilateral; this
12265    * equivalent to the pmap_square_quad() functions in the sample
12266    * implementation, which we can simplify, since our target is always
12267    * a rectangle.
12268    */
12269   px = v[0].x - v[1].x + v[3].x - v[2].x;
12270   py = v[0].y - v[1].y + v[3].y - v[2].y;
12271
12272   if (!px && !py)
12273     {
12274       /* affine transform */
12275       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12276       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12277       RQ[2][0] = UX2FP (v[0].x);
12278       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12279       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12280       RQ[2][1] = UX2FP (v[0].y);
12281       RQ[0][2] = 0;
12282       RQ[1][2] = 0;
12283       RQ[2][2] = 1.0;
12284     }
12285   else
12286     {
12287       /* projective transform */
12288       double dx1, dx2, dy1, dy2, del;
12289
12290       dx1 = UX2FP (v[1].x - v[3].x);
12291       dx2 = UX2FP (v[2].x - v[3].x);
12292       dy1 = UX2FP (v[1].y - v[3].y);
12293       dy2 = UX2FP (v[2].y - v[3].y);
12294
12295       del = DET2FP (dx1, dx2, dy1, dy2);
12296       if (!del)
12297         return FALSE;
12298
12299       /*
12300        * The division here needs to be done in floating point for
12301        * precisions reasons.
12302        */
12303       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12304       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12305       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12306       RQ[2][2] = 1.0;
12307       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12308       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12309       RQ[2][0] = UX2FP (v[0].x);
12310       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12311       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12312       RQ[2][1] = UX2FP (v[0].y);
12313     }
12314
12315   /*
12316    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12317    * square. Since our rectangle is based at 0,0 we only need to scale.
12318    */
12319   RQ[0][0] /= du;
12320   RQ[1][0] /= dv;
12321   RQ[0][1] /= du;
12322   RQ[1][1] /= dv;
12323   RQ[0][2] /= du;
12324   RQ[1][2] /= dv;
12325
12326   /*
12327    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12328    * inverse of that.
12329    */
12330   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12331   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12332   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12333   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12334   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12335   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12336   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12337   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12338   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12339
12340   /*
12341    * Check the resulting matrix is OK.
12342    */
12343   det = (RQ[0][0] * ST[0][0])
12344       + (RQ[0][1] * ST[0][1])
12345       + (RQ[0][2] * ST[0][2]);
12346   if (!det)
12347     return FALSE;
12348
12349   /*
12350    * Now transform our point with the ST matrix; the notional w
12351    * coordinate is 1, hence the last part is simply added.
12352    */
12353   xi = (int) x;
12354   yi = (int) y;
12355
12356   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12357   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12358   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12359
12360   if (x_out)
12361     *x_out = xf / wf;
12362
12363   if (y_out)
12364     *y_out = yf / wf;
12365
12366 #undef UX2FP
12367 #undef DET2FP
12368
12369   return TRUE;
12370 }
12371
12372 /*
12373  * ClutterGeometry
12374  */
12375
12376 static ClutterGeometry*
12377 clutter_geometry_copy (const ClutterGeometry *geometry)
12378 {
12379   return g_slice_dup (ClutterGeometry, geometry);
12380 }
12381
12382 static void
12383 clutter_geometry_free (ClutterGeometry *geometry)
12384 {
12385   if (G_LIKELY (geometry != NULL))
12386     g_slice_free (ClutterGeometry, geometry);
12387 }
12388
12389 /**
12390  * clutter_geometry_union:
12391  * @geometry_a: a #ClutterGeometry
12392  * @geometry_b: another #ClutterGeometry
12393  * @result: (out): location to store the result
12394  *
12395  * Find the union of two rectangles represented as #ClutterGeometry.
12396  *
12397  * Since: 1.4
12398  */
12399 void
12400 clutter_geometry_union (const ClutterGeometry *geometry_a,
12401                         const ClutterGeometry *geometry_b,
12402                         ClutterGeometry       *result)
12403 {
12404   /* We don't try to handle rectangles that can't be represented
12405    * as a signed integer box */
12406   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12407   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12408   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12409                   geometry_b->x + (gint)geometry_b->width);
12410   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12411                   geometry_b->y + (gint)geometry_b->height);
12412   result->x = x_1;
12413   result->y = y_1;
12414   result->width = x_2 - x_1;
12415   result->height = y_2 - y_1;
12416 }
12417
12418 /**
12419  * clutter_geometry_intersects:
12420  * @geometry0: The first geometry to test
12421  * @geometry1: The second geometry to test
12422  *
12423  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12424  * they do else %FALSE.
12425  *
12426  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12427  * %FALSE.
12428  *
12429  * Since: 1.4
12430  */
12431 gboolean
12432 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12433                              const ClutterGeometry *geometry1)
12434 {
12435   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12436       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12437       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12438       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12439     return FALSE;
12440   else
12441     return TRUE;
12442 }
12443
12444 static gboolean
12445 clutter_geometry_progress (const GValue *a,
12446                            const GValue *b,
12447                            gdouble       progress,
12448                            GValue       *retval)
12449 {
12450   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12451   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12452   ClutterGeometry res = { 0, };
12453   gint a_width = a_geom->width;
12454   gint b_width = b_geom->width;
12455   gint a_height = a_geom->height;
12456   gint b_height = b_geom->height;
12457
12458   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12459   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12460
12461   res.width = a_width + (b_width - a_width) * progress;
12462   res.height = a_height + (b_height - a_height) * progress;
12463
12464   g_value_set_boxed (retval, &res);
12465
12466   return TRUE;
12467 }
12468
12469 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12470                                clutter_geometry_copy,
12471                                clutter_geometry_free,
12472                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12473
12474 /*
12475  * ClutterVertices
12476  */
12477
12478 /**
12479  * clutter_vertex_new:
12480  * @x: X coordinate
12481  * @y: Y coordinate
12482  * @z: Z coordinate
12483  *
12484  * Creates a new #ClutterVertex for the point in 3D space
12485  * identified by the 3 coordinates @x, @y, @z
12486  *
12487  * Return value: the newly allocate #ClutterVertex. Use
12488  *   clutter_vertex_free() to free the resources
12489  *
12490  * Since: 1.0
12491  */
12492 ClutterVertex *
12493 clutter_vertex_new (gfloat x,
12494                     gfloat y,
12495                     gfloat z)
12496 {
12497   ClutterVertex *vertex;
12498
12499   vertex = g_slice_new (ClutterVertex);
12500   vertex->x = x;
12501   vertex->y = y;
12502   vertex->z = z;
12503
12504   return vertex;
12505 }
12506
12507 /**
12508  * clutter_vertex_copy:
12509  * @vertex: a #ClutterVertex
12510  *
12511  * Copies @vertex
12512  *
12513  * Return value: a newly allocated copy of #ClutterVertex. Use
12514  *   clutter_vertex_free() to free the allocated resources
12515  *
12516  * Since: 1.0
12517  */
12518 ClutterVertex *
12519 clutter_vertex_copy (const ClutterVertex *vertex)
12520 {
12521   if (G_LIKELY (vertex != NULL))
12522     return g_slice_dup (ClutterVertex, vertex);
12523
12524   return NULL;
12525 }
12526
12527 /**
12528  * clutter_vertex_free:
12529  * @vertex: a #ClutterVertex
12530  *
12531  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
12532  *
12533  * Since: 1.0
12534  */
12535 void
12536 clutter_vertex_free (ClutterVertex *vertex)
12537 {
12538   if (G_UNLIKELY (vertex != NULL))
12539     g_slice_free (ClutterVertex, vertex);
12540 }
12541
12542 /**
12543  * clutter_vertex_equal:
12544  * @vertex_a: a #ClutterVertex
12545  * @vertex_b: a #ClutterVertex
12546  *
12547  * Compares @vertex_a and @vertex_b for equality
12548  *
12549  * Return value: %TRUE if the passed #ClutterVertex are equal
12550  *
12551  * Since: 1.0
12552  */
12553 gboolean
12554 clutter_vertex_equal (const ClutterVertex *vertex_a,
12555                       const ClutterVertex *vertex_b)
12556 {
12557   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
12558
12559   if (vertex_a == vertex_b)
12560     return TRUE;
12561
12562   return vertex_a->x == vertex_b->x &&
12563          vertex_a->y == vertex_b->y &&
12564          vertex_a->z == vertex_b->z;
12565 }
12566
12567 static gboolean
12568 clutter_vertex_progress (const GValue *a,
12569                          const GValue *b,
12570                          gdouble       progress,
12571                          GValue       *retval)
12572 {
12573   const ClutterVertex *av = g_value_get_boxed (a);
12574   const ClutterVertex *bv = g_value_get_boxed (b);
12575   ClutterVertex res = { 0, };
12576
12577   res.x = av->x + (bv->x - av->x) * progress;
12578   res.y = av->y + (bv->y - av->y) * progress;
12579   res.z = av->z + (bv->z - av->z) * progress;
12580
12581   g_value_set_boxed (retval, &res);
12582
12583   return TRUE;
12584 }
12585
12586 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
12587                                clutter_vertex_copy,
12588                                clutter_vertex_free,
12589                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
12590
12591 /**
12592  * clutter_actor_is_rotated:
12593  * @self: a #ClutterActor
12594  *
12595  * Checks whether any rotation is applied to the actor.
12596  *
12597  * Return value: %TRUE if the actor is rotated.
12598  *
12599  * Since: 0.6
12600  */
12601 gboolean
12602 clutter_actor_is_rotated (ClutterActor *self)
12603 {
12604   const ClutterTransformInfo *info;
12605
12606   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12607
12608   info = _clutter_actor_get_transform_info_or_defaults (self);
12609
12610   if (info->rx_angle || info->ry_angle || info->rz_angle)
12611     return TRUE;
12612
12613   return FALSE;
12614 }
12615
12616 /**
12617  * clutter_actor_is_scaled:
12618  * @self: a #ClutterActor
12619  *
12620  * Checks whether the actor is scaled in either dimension.
12621  *
12622  * Return value: %TRUE if the actor is scaled.
12623  *
12624  * Since: 0.6
12625  */
12626 gboolean
12627 clutter_actor_is_scaled (ClutterActor *self)
12628 {
12629   const ClutterTransformInfo *info;
12630
12631   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12632
12633   info = _clutter_actor_get_transform_info_or_defaults (self);
12634
12635   if (info->scale_x != 1.0 || info->scale_y != 1.0)
12636     return TRUE;
12637
12638   return FALSE;
12639 }
12640
12641 ClutterActor *
12642 _clutter_actor_get_stage_internal (ClutterActor *actor)
12643 {
12644   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
12645     actor = actor->priv->parent;
12646
12647   return actor;
12648 }
12649
12650 /**
12651  * clutter_actor_get_stage:
12652  * @actor: a #ClutterActor
12653  *
12654  * Retrieves the #ClutterStage where @actor is contained.
12655  *
12656  * Return value: (transfer none) (type Clutter.Stage): the stage
12657  *   containing the actor, or %NULL
12658  *
12659  * Since: 0.8
12660  */
12661 ClutterActor *
12662 clutter_actor_get_stage (ClutterActor *actor)
12663 {
12664   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
12665
12666   return _clutter_actor_get_stage_internal (actor);
12667 }
12668
12669 /**
12670  * clutter_actor_allocate_available_size:
12671  * @self: a #ClutterActor
12672  * @x: the actor's X coordinate
12673  * @y: the actor's Y coordinate
12674  * @available_width: the maximum available width, or -1 to use the
12675  *   actor's natural width
12676  * @available_height: the maximum available height, or -1 to use the
12677  *   actor's natural height
12678  * @flags: flags controlling the allocation
12679  *
12680  * Allocates @self taking into account the #ClutterActor<!-- -->'s
12681  * preferred size, but limiting it to the maximum available width
12682  * and height provided.
12683  *
12684  * This function will do the right thing when dealing with the
12685  * actor's request mode.
12686  *
12687  * The implementation of this function is equivalent to:
12688  *
12689  * |[
12690  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12691  *     {
12692  *       clutter_actor_get_preferred_width (self, available_height,
12693  *                                          &amp;min_width,
12694  *                                          &amp;natural_width);
12695  *       width = CLAMP (natural_width, min_width, available_width);
12696  *
12697  *       clutter_actor_get_preferred_height (self, width,
12698  *                                           &amp;min_height,
12699  *                                           &amp;natural_height);
12700  *       height = CLAMP (natural_height, min_height, available_height);
12701  *     }
12702  *   else
12703  *     {
12704  *       clutter_actor_get_preferred_height (self, available_width,
12705  *                                           &amp;min_height,
12706  *                                           &amp;natural_height);
12707  *       height = CLAMP (natural_height, min_height, available_height);
12708  *
12709  *       clutter_actor_get_preferred_width (self, height,
12710  *                                          &amp;min_width,
12711  *                                          &amp;natural_width);
12712  *       width = CLAMP (natural_width, min_width, available_width);
12713  *     }
12714  *
12715  *   box.x1 = x; box.y1 = y;
12716  *   box.x2 = box.x1 + available_width;
12717  *   box.y2 = box.y1 + available_height;
12718  *   clutter_actor_allocate (self, &amp;box, flags);
12719  * ]|
12720  *
12721  * This function can be used by fluid layout managers to allocate
12722  * an actor's preferred size without making it bigger than the area
12723  * available for the container.
12724  *
12725  * Since: 1.0
12726  */
12727 void
12728 clutter_actor_allocate_available_size (ClutterActor           *self,
12729                                        gfloat                  x,
12730                                        gfloat                  y,
12731                                        gfloat                  available_width,
12732                                        gfloat                  available_height,
12733                                        ClutterAllocationFlags  flags)
12734 {
12735   ClutterActorPrivate *priv;
12736   gfloat width, height;
12737   gfloat min_width, min_height;
12738   gfloat natural_width, natural_height;
12739   ClutterActorBox box;
12740
12741   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12742
12743   priv = self->priv;
12744
12745   width = height = 0.0;
12746
12747   switch (priv->request_mode)
12748     {
12749     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
12750       clutter_actor_get_preferred_width (self, available_height,
12751                                          &min_width,
12752                                          &natural_width);
12753       width  = CLAMP (natural_width, min_width, available_width);
12754
12755       clutter_actor_get_preferred_height (self, width,
12756                                           &min_height,
12757                                           &natural_height);
12758       height = CLAMP (natural_height, min_height, available_height);
12759       break;
12760
12761     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
12762       clutter_actor_get_preferred_height (self, available_width,
12763                                           &min_height,
12764                                           &natural_height);
12765       height = CLAMP (natural_height, min_height, available_height);
12766
12767       clutter_actor_get_preferred_width (self, height,
12768                                          &min_width,
12769                                          &natural_width);
12770       width  = CLAMP (natural_width, min_width, available_width);
12771       break;
12772     }
12773
12774
12775   box.x1 = x;
12776   box.y1 = y;
12777   box.x2 = box.x1 + width;
12778   box.y2 = box.y1 + height;
12779   clutter_actor_allocate (self, &box, flags);
12780 }
12781
12782 /**
12783  * clutter_actor_allocate_preferred_size:
12784  * @self: a #ClutterActor
12785  * @flags: flags controlling the allocation
12786  *
12787  * Allocates the natural size of @self.
12788  *
12789  * This function is a utility call for #ClutterActor implementations
12790  * that allocates the actor's preferred natural size. It can be used
12791  * by fixed layout managers (like #ClutterGroup or so called
12792  * 'composite actors') inside the ClutterActor::allocate
12793  * implementation to give each child exactly how much space it
12794  * requires.
12795  *
12796  * This function is not meant to be used by applications. It is also
12797  * not meant to be used outside the implementation of the
12798  * ClutterActor::allocate virtual function.
12799  *
12800  * Since: 0.8
12801  */
12802 void
12803 clutter_actor_allocate_preferred_size (ClutterActor           *self,
12804                                        ClutterAllocationFlags  flags)
12805 {
12806   gfloat actor_x, actor_y;
12807   gfloat natural_width, natural_height;
12808   ClutterActorBox actor_box;
12809
12810   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12811
12812   actor_x = clutter_actor_get_x (self);
12813   actor_y = clutter_actor_get_y (self);
12814
12815   clutter_actor_get_preferred_size (self,
12816                                     NULL, NULL,
12817                                     &natural_width,
12818                                     &natural_height);
12819
12820   actor_box.x1 = actor_x;
12821   actor_box.y1 = actor_y;
12822   actor_box.x2 = actor_box.x1 + natural_width;
12823   actor_box.y2 = actor_box.y1 + natural_height;
12824
12825   clutter_actor_allocate (self, &actor_box, flags);
12826 }
12827
12828 /**
12829  * clutter_actor_allocate_align_fill:
12830  * @self: a #ClutterActor
12831  * @box: a #ClutterActorBox, containing the available width and height
12832  * @x_align: the horizontal alignment, between 0 and 1
12833  * @y_align: the vertical alignment, between 0 and 1
12834  * @x_fill: whether the actor should fill horizontally
12835  * @y_fill: whether the actor should fill vertically
12836  * @flags: allocation flags to be passed to clutter_actor_allocate()
12837  *
12838  * Allocates @self by taking into consideration the available allocation
12839  * area; an alignment factor on either axis; and whether the actor should
12840  * fill the allocation on either axis.
12841  *
12842  * The @box should contain the available allocation width and height;
12843  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
12844  * allocation will be offset by their value.
12845  *
12846  * This function takes into consideration the geometry request specified by
12847  * the #ClutterActor:request-mode property, and the text direction.
12848  *
12849  * This function is useful for fluid layout managers, like #ClutterBinLayout
12850  * or #ClutterTableLayout
12851  *
12852  * Since: 1.4
12853  */
12854 void
12855 clutter_actor_allocate_align_fill (ClutterActor           *self,
12856                                    const ClutterActorBox  *box,
12857                                    gdouble                 x_align,
12858                                    gdouble                 y_align,
12859                                    gboolean                x_fill,
12860                                    gboolean                y_fill,
12861                                    ClutterAllocationFlags  flags)
12862 {
12863   ClutterActorPrivate *priv;
12864   ClutterActorBox allocation = { 0, };
12865   gfloat x_offset, y_offset;
12866   gfloat available_width, available_height;
12867   gfloat child_width, child_height;
12868
12869   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12870   g_return_if_fail (box != NULL);
12871   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
12872   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
12873
12874   priv = self->priv;
12875
12876   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
12877   clutter_actor_box_get_size (box, &available_width, &available_height);
12878
12879   if (available_width < 0)
12880     available_width = 0;
12881
12882   if (available_height < 0)
12883     available_height = 0;
12884
12885   if (x_fill)
12886     {
12887       allocation.x1 = x_offset;
12888       allocation.x2 = allocation.x1 + available_width;
12889     }
12890
12891   if (y_fill)
12892     {
12893       allocation.y1 = y_offset;
12894       allocation.y2 = allocation.y1 + available_height;
12895     }
12896
12897   /* if we are filling horizontally and vertically then we're done */
12898   if (x_fill && y_fill)
12899     goto out;
12900
12901   child_width = child_height = 0.0f;
12902
12903   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12904     {
12905       gfloat min_width, natural_width;
12906       gfloat min_height, natural_height;
12907
12908       clutter_actor_get_preferred_width (self, available_height,
12909                                          &min_width,
12910                                          &natural_width);
12911
12912       child_width = CLAMP (natural_width, min_width, available_width);
12913
12914       if (!y_fill)
12915         {
12916           clutter_actor_get_preferred_height (self, child_width,
12917                                               &min_height,
12918                                               &natural_height);
12919
12920           child_height = CLAMP (natural_height, min_height, available_height);
12921         }
12922     }
12923   else
12924     {
12925       gfloat min_width, natural_width;
12926       gfloat min_height, natural_height;
12927
12928       clutter_actor_get_preferred_height (self, available_width,
12929                                           &min_height,
12930                                           &natural_height);
12931
12932       child_height = CLAMP (natural_height, min_height, available_height);
12933
12934       if (!x_fill)
12935         {
12936           clutter_actor_get_preferred_width (self, child_height,
12937                                              &min_width,
12938                                              &natural_width);
12939
12940           child_width = CLAMP (natural_width, min_width, available_width);
12941         }
12942     }
12943
12944   /* invert the horizontal alignment for RTL languages */
12945   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
12946     x_align = 1.0 - x_align;
12947
12948   if (!x_fill)
12949     {
12950       allocation.x1 = x_offset
12951                     + ((available_width - child_width) * x_align);
12952       allocation.x2 = allocation.x1 + child_width;
12953     }
12954
12955   if (!y_fill)
12956     {
12957       allocation.y1 = y_offset
12958                     + ((available_height - child_height) * y_align);
12959       allocation.y2 = allocation.y1 + child_height;
12960     }
12961
12962 out:
12963   clutter_actor_box_clamp_to_pixel (&allocation);
12964   clutter_actor_allocate (self, &allocation, flags);
12965 }
12966
12967 /**
12968  * clutter_actor_grab_key_focus:
12969  * @self: a #ClutterActor
12970  *
12971  * Sets the key focus of the #ClutterStage including @self
12972  * to this #ClutterActor.
12973  *
12974  * Since: 1.0
12975  */
12976 void
12977 clutter_actor_grab_key_focus (ClutterActor *self)
12978 {
12979   ClutterActor *stage;
12980
12981   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12982
12983   stage = _clutter_actor_get_stage_internal (self);
12984   if (stage != NULL)
12985     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
12986 }
12987
12988 /**
12989  * clutter_actor_get_pango_context:
12990  * @self: a #ClutterActor
12991  *
12992  * Retrieves the #PangoContext for @self. The actor's #PangoContext
12993  * is already configured using the appropriate font map, resolution
12994  * and font options.
12995  *
12996  * Unlike clutter_actor_create_pango_context(), this context is owend
12997  * by the #ClutterActor and it will be updated each time the options
12998  * stored by the #ClutterBackend change.
12999  *
13000  * You can use the returned #PangoContext to create a #PangoLayout
13001  * and render text using cogl_pango_render_layout() to reuse the
13002  * glyphs cache also used by Clutter.
13003  *
13004  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13005  *   The returned #PangoContext is owned by the actor and should not be
13006  *   unreferenced by the application code
13007  *
13008  * Since: 1.0
13009  */
13010 PangoContext *
13011 clutter_actor_get_pango_context (ClutterActor *self)
13012 {
13013   ClutterActorPrivate *priv;
13014
13015   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13016
13017   priv = self->priv;
13018
13019   if (priv->pango_context != NULL)
13020     return priv->pango_context;
13021
13022   priv->pango_context = _clutter_context_get_pango_context ();
13023   g_object_ref (priv->pango_context);
13024
13025   return priv->pango_context;
13026 }
13027
13028 /**
13029  * clutter_actor_create_pango_context:
13030  * @self: a #ClutterActor
13031  *
13032  * Creates a #PangoContext for the given actor. The #PangoContext
13033  * is already configured using the appropriate font map, resolution
13034  * and font options.
13035  *
13036  * See also clutter_actor_get_pango_context().
13037  *
13038  * Return value: (transfer full): the newly created #PangoContext.
13039  *   Use g_object_unref() on the returned value to deallocate its
13040  *   resources
13041  *
13042  * Since: 1.0
13043  */
13044 PangoContext *
13045 clutter_actor_create_pango_context (ClutterActor *self)
13046 {
13047   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13048
13049   return _clutter_context_create_pango_context ();
13050 }
13051
13052 /**
13053  * clutter_actor_create_pango_layout:
13054  * @self: a #ClutterActor
13055  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13056  *
13057  * Creates a new #PangoLayout from the same #PangoContext used
13058  * by the #ClutterActor. The #PangoLayout is already configured
13059  * with the font map, resolution and font options, and the
13060  * given @text.
13061  *
13062  * If you want to keep around a #PangoLayout created by this
13063  * function you will have to connect to the #ClutterBackend::font-changed
13064  * and #ClutterBackend::resolution-changed signals, and call
13065  * pango_layout_context_changed() in response to them.
13066  *
13067  * Return value: (transfer full): the newly created #PangoLayout.
13068  *   Use g_object_unref() when done
13069  *
13070  * Since: 1.0
13071  */
13072 PangoLayout *
13073 clutter_actor_create_pango_layout (ClutterActor *self,
13074                                    const gchar  *text)
13075 {
13076   PangoContext *context;
13077   PangoLayout *layout;
13078
13079   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13080
13081   context = clutter_actor_get_pango_context (self);
13082   layout = pango_layout_new (context);
13083
13084   if (text)
13085     pango_layout_set_text (layout, text, -1);
13086
13087   return layout;
13088 }
13089
13090 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13091  * ClutterOffscreenEffect.
13092  */
13093 void
13094 _clutter_actor_set_opacity_override (ClutterActor *self,
13095                                      gint          opacity)
13096 {
13097   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13098
13099   self->priv->opacity_override = opacity;
13100 }
13101
13102 gint
13103 _clutter_actor_get_opacity_override (ClutterActor *self)
13104 {
13105   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13106
13107   return self->priv->opacity_override;
13108 }
13109
13110 /* Allows you to disable applying the actors model view transform during
13111  * a paint. Used by ClutterClone. */
13112 void
13113 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13114                                                 gboolean      enable)
13115 {
13116   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13117
13118   self->priv->enable_model_view_transform = enable;
13119 }
13120
13121 void
13122 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13123                                           gboolean      enable)
13124 {
13125   ClutterActorPrivate *priv;
13126
13127   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13128
13129   priv = self->priv;
13130
13131   priv->enable_paint_unmapped = enable;
13132
13133   if (priv->enable_paint_unmapped)
13134     {
13135       /* Make sure that the parents of the widget are realized first;
13136        * otherwise checks in clutter_actor_update_map_state() will
13137        * fail.
13138        */
13139       clutter_actor_realize (self);
13140
13141       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13142     }
13143   else
13144     {
13145       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13146     }
13147 }
13148
13149 static void
13150 clutter_anchor_coord_get_units (ClutterActor      *self,
13151                                 const AnchorCoord *coord,
13152                                 gfloat            *x,
13153                                 gfloat            *y,
13154                                 gfloat            *z)
13155 {
13156   if (coord->is_fractional)
13157     {
13158       gfloat actor_width, actor_height;
13159
13160       clutter_actor_get_size (self, &actor_width, &actor_height);
13161
13162       if (x)
13163         *x = actor_width * coord->v.fraction.x;
13164
13165       if (y)
13166         *y = actor_height * coord->v.fraction.y;
13167
13168       if (z)
13169         *z = 0;
13170     }
13171   else
13172     {
13173       if (x)
13174         *x = coord->v.units.x;
13175
13176       if (y)
13177         *y = coord->v.units.y;
13178
13179       if (z)
13180         *z = coord->v.units.z;
13181     }
13182 }
13183
13184 static void
13185 clutter_anchor_coord_set_units (AnchorCoord *coord,
13186                                 gfloat       x,
13187                                 gfloat       y,
13188                                 gfloat       z)
13189 {
13190   coord->is_fractional = FALSE;
13191   coord->v.units.x = x;
13192   coord->v.units.y = y;
13193   coord->v.units.z = z;
13194 }
13195
13196 static ClutterGravity
13197 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13198 {
13199   if (coord->is_fractional)
13200     {
13201       if (coord->v.fraction.x == 0.0)
13202         {
13203           if (coord->v.fraction.y == 0.0)
13204             return CLUTTER_GRAVITY_NORTH_WEST;
13205           else if (coord->v.fraction.y == 0.5)
13206             return CLUTTER_GRAVITY_WEST;
13207           else if (coord->v.fraction.y == 1.0)
13208             return CLUTTER_GRAVITY_SOUTH_WEST;
13209           else
13210             return CLUTTER_GRAVITY_NONE;
13211         }
13212       else if (coord->v.fraction.x == 0.5)
13213         {
13214           if (coord->v.fraction.y == 0.0)
13215             return CLUTTER_GRAVITY_NORTH;
13216           else if (coord->v.fraction.y == 0.5)
13217             return CLUTTER_GRAVITY_CENTER;
13218           else if (coord->v.fraction.y == 1.0)
13219             return CLUTTER_GRAVITY_SOUTH;
13220           else
13221             return CLUTTER_GRAVITY_NONE;
13222         }
13223       else if (coord->v.fraction.x == 1.0)
13224         {
13225           if (coord->v.fraction.y == 0.0)
13226             return CLUTTER_GRAVITY_NORTH_EAST;
13227           else if (coord->v.fraction.y == 0.5)
13228             return CLUTTER_GRAVITY_EAST;
13229           else if (coord->v.fraction.y == 1.0)
13230             return CLUTTER_GRAVITY_SOUTH_EAST;
13231           else
13232             return CLUTTER_GRAVITY_NONE;
13233         }
13234       else
13235         return CLUTTER_GRAVITY_NONE;
13236     }
13237   else
13238     return CLUTTER_GRAVITY_NONE;
13239 }
13240
13241 static void
13242 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13243                                   ClutterGravity  gravity)
13244 {
13245   switch (gravity)
13246     {
13247     case CLUTTER_GRAVITY_NORTH:
13248       coord->v.fraction.x = 0.5;
13249       coord->v.fraction.y = 0.0;
13250       break;
13251
13252     case CLUTTER_GRAVITY_NORTH_EAST:
13253       coord->v.fraction.x = 1.0;
13254       coord->v.fraction.y = 0.0;
13255       break;
13256
13257     case CLUTTER_GRAVITY_EAST:
13258       coord->v.fraction.x = 1.0;
13259       coord->v.fraction.y = 0.5;
13260       break;
13261
13262     case CLUTTER_GRAVITY_SOUTH_EAST:
13263       coord->v.fraction.x = 1.0;
13264       coord->v.fraction.y = 1.0;
13265       break;
13266
13267     case CLUTTER_GRAVITY_SOUTH:
13268       coord->v.fraction.x = 0.5;
13269       coord->v.fraction.y = 1.0;
13270       break;
13271
13272     case CLUTTER_GRAVITY_SOUTH_WEST:
13273       coord->v.fraction.x = 0.0;
13274       coord->v.fraction.y = 1.0;
13275       break;
13276
13277     case CLUTTER_GRAVITY_WEST:
13278       coord->v.fraction.x = 0.0;
13279       coord->v.fraction.y = 0.5;
13280       break;
13281
13282     case CLUTTER_GRAVITY_NORTH_WEST:
13283       coord->v.fraction.x = 0.0;
13284       coord->v.fraction.y = 0.0;
13285       break;
13286
13287     case CLUTTER_GRAVITY_CENTER:
13288       coord->v.fraction.x = 0.5;
13289       coord->v.fraction.y = 0.5;
13290       break;
13291
13292     default:
13293       coord->v.fraction.x = 0.0;
13294       coord->v.fraction.y = 0.0;
13295       break;
13296     }
13297
13298   coord->is_fractional = TRUE;
13299 }
13300
13301 static gboolean
13302 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13303 {
13304   if (coord->is_fractional)
13305     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13306   else
13307     return (coord->v.units.x == 0.0
13308             && coord->v.units.y == 0.0
13309             && coord->v.units.z == 0.0);
13310 }
13311
13312 /**
13313  * clutter_actor_get_flags:
13314  * @self: a #ClutterActor
13315  *
13316  * Retrieves the flags set on @self
13317  *
13318  * Return value: a bitwise or of #ClutterActorFlags or 0
13319  *
13320  * Since: 1.0
13321  */
13322 ClutterActorFlags
13323 clutter_actor_get_flags (ClutterActor *self)
13324 {
13325   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13326
13327   return self->flags;
13328 }
13329
13330 /**
13331  * clutter_actor_set_flags:
13332  * @self: a #ClutterActor
13333  * @flags: the flags to set
13334  *
13335  * Sets @flags on @self
13336  *
13337  * This function will emit notifications for the changed properties
13338  *
13339  * Since: 1.0
13340  */
13341 void
13342 clutter_actor_set_flags (ClutterActor      *self,
13343                          ClutterActorFlags  flags)
13344 {
13345   ClutterActorFlags old_flags;
13346   GObject *obj;
13347   gboolean was_reactive_set, reactive_set;
13348   gboolean was_realized_set, realized_set;
13349   gboolean was_mapped_set, mapped_set;
13350   gboolean was_visible_set, visible_set;
13351
13352   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13353
13354   if (self->flags == flags)
13355     return;
13356
13357   obj = G_OBJECT (self);
13358   g_object_ref (obj);
13359   g_object_freeze_notify (obj);
13360
13361   old_flags = self->flags;
13362
13363   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13364   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13365   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13366   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13367
13368   self->flags |= flags;
13369
13370   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13371   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13372   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13373   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13374
13375   if (reactive_set != was_reactive_set)
13376     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13377
13378   if (realized_set != was_realized_set)
13379     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13380
13381   if (mapped_set != was_mapped_set)
13382     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13383
13384   if (visible_set != was_visible_set)
13385     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13386
13387   g_object_thaw_notify (obj);
13388   g_object_unref (obj);
13389 }
13390
13391 /**
13392  * clutter_actor_unset_flags:
13393  * @self: a #ClutterActor
13394  * @flags: the flags to unset
13395  *
13396  * Unsets @flags on @self
13397  *
13398  * This function will emit notifications for the changed properties
13399  *
13400  * Since: 1.0
13401  */
13402 void
13403 clutter_actor_unset_flags (ClutterActor      *self,
13404                            ClutterActorFlags  flags)
13405 {
13406   ClutterActorFlags old_flags;
13407   GObject *obj;
13408   gboolean was_reactive_set, reactive_set;
13409   gboolean was_realized_set, realized_set;
13410   gboolean was_mapped_set, mapped_set;
13411   gboolean was_visible_set, visible_set;
13412
13413   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13414
13415   obj = G_OBJECT (self);
13416   g_object_freeze_notify (obj);
13417
13418   old_flags = self->flags;
13419
13420   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13421   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13422   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13423   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13424
13425   self->flags &= ~flags;
13426
13427   if (self->flags == old_flags)
13428     return;
13429
13430   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13431   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13432   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13433   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13434
13435   if (reactive_set != was_reactive_set)
13436     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13437
13438   if (realized_set != was_realized_set)
13439     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13440
13441   if (mapped_set != was_mapped_set)
13442     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13443
13444   if (visible_set != was_visible_set)
13445     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13446
13447   g_object_thaw_notify (obj);
13448 }
13449
13450 /**
13451  * clutter_actor_get_transformation_matrix:
13452  * @self: a #ClutterActor
13453  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13454  *
13455  * Retrieves the transformations applied to @self relative to its
13456  * parent.
13457  *
13458  * Since: 1.0
13459  */
13460 void
13461 clutter_actor_get_transformation_matrix (ClutterActor *self,
13462                                          CoglMatrix   *matrix)
13463 {
13464   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13465
13466   cogl_matrix_init_identity (matrix);
13467
13468   _clutter_actor_apply_modelview_transform (self, matrix);
13469 }
13470
13471 void
13472 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13473                                    gboolean      is_in_clone_paint)
13474 {
13475   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13476   self->priv->in_clone_paint = is_in_clone_paint;
13477 }
13478
13479 /**
13480  * clutter_actor_is_in_clone_paint:
13481  * @self: a #ClutterActor
13482  *
13483  * Checks whether @self is being currently painted by a #ClutterClone
13484  *
13485  * This function is useful only inside the ::paint virtual function
13486  * implementations or within handlers for the #ClutterActor::paint
13487  * signal
13488  *
13489  * This function should not be used by applications
13490  *
13491  * Return value: %TRUE if the #ClutterActor is currently being painted
13492  *   by a #ClutterClone, and %FALSE otherwise
13493  *
13494  * Since: 1.0
13495  */
13496 gboolean
13497 clutter_actor_is_in_clone_paint (ClutterActor *self)
13498 {
13499   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13500
13501   return self->priv->in_clone_paint;
13502 }
13503
13504 static gboolean
13505 set_direction_recursive (ClutterActor *actor,
13506                          gpointer      user_data)
13507 {
13508   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
13509
13510   clutter_actor_set_text_direction (actor, text_dir);
13511
13512   return TRUE;
13513 }
13514
13515 /**
13516  * clutter_actor_set_text_direction:
13517  * @self: a #ClutterActor
13518  * @text_dir: the text direction for @self
13519  *
13520  * Sets the #ClutterTextDirection for an actor
13521  *
13522  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
13523  *
13524  * If @self implements #ClutterContainer then this function will recurse
13525  * inside all the children of @self (including the internal ones).
13526  *
13527  * Composite actors not implementing #ClutterContainer, or actors requiring
13528  * special handling when the text direction changes, should connect to
13529  * the #GObject::notify signal for the #ClutterActor:text-direction property
13530  *
13531  * Since: 1.2
13532  */
13533 void
13534 clutter_actor_set_text_direction (ClutterActor         *self,
13535                                   ClutterTextDirection  text_dir)
13536 {
13537   ClutterActorPrivate *priv;
13538
13539   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13540   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
13541
13542   priv = self->priv;
13543
13544   if (priv->text_direction != text_dir)
13545     {
13546       priv->text_direction = text_dir;
13547
13548       /* we need to emit the notify::text-direction first, so that
13549        * the sub-classes can catch that and do specific handling of
13550        * the text direction; see clutter_text_direction_changed_cb()
13551        * inside clutter-text.c
13552        */
13553       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
13554
13555       _clutter_actor_foreach_child (self, set_direction_recursive,
13556                                     GINT_TO_POINTER (text_dir));
13557
13558       clutter_actor_queue_relayout (self);
13559     }
13560 }
13561
13562 void
13563 _clutter_actor_set_has_pointer (ClutterActor *self,
13564                                 gboolean      has_pointer)
13565 {
13566   ClutterActorPrivate *priv = self->priv;
13567
13568   if (priv->has_pointer != has_pointer)
13569     {
13570       priv->has_pointer = has_pointer;
13571
13572       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
13573     }
13574 }
13575
13576 /**
13577  * clutter_actor_get_text_direction:
13578  * @self: a #ClutterActor
13579  *
13580  * Retrieves the value set using clutter_actor_set_text_direction()
13581  *
13582  * If no text direction has been previously set, the default text
13583  * direction, as returned by clutter_get_default_text_direction(), will
13584  * be returned instead
13585  *
13586  * Return value: the #ClutterTextDirection for the actor
13587  *
13588  * Since: 1.2
13589  */
13590 ClutterTextDirection
13591 clutter_actor_get_text_direction (ClutterActor *self)
13592 {
13593   ClutterActorPrivate *priv;
13594
13595   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
13596                         CLUTTER_TEXT_DIRECTION_LTR);
13597
13598   priv = self->priv;
13599
13600   /* if no direction has been set yet use the default */
13601   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
13602     priv->text_direction = clutter_get_default_text_direction ();
13603
13604   return priv->text_direction;
13605 }
13606
13607 /**
13608  * clutter_actor_push_internal:
13609  * @self: a #ClutterActor
13610  *
13611  * Should be used by actors implementing the #ClutterContainer and with
13612  * internal children added through clutter_actor_set_parent(), for instance:
13613  *
13614  * |[
13615  *   static void
13616  *   my_actor_init (MyActor *self)
13617  *   {
13618  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
13619  *
13620  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
13621  *
13622  *     /&ast; calling clutter_actor_set_parent() now will result in
13623  *      &ast; the internal flag being set on a child of MyActor
13624  *      &ast;/
13625  *
13626  *     /&ast; internal child - a background texture &ast;/
13627  *     self->priv->background_tex = clutter_texture_new ();
13628  *     clutter_actor_set_parent (self->priv->background_tex,
13629  *                               CLUTTER_ACTOR (self));
13630  *
13631  *     /&ast; internal child - a label &ast;/
13632  *     self->priv->label = clutter_text_new ();
13633  *     clutter_actor_set_parent (self->priv->label,
13634  *                               CLUTTER_ACTOR (self));
13635  *
13636  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
13637  *
13638  *     /&ast; calling clutter_actor_set_parent() now will not result in
13639  *      &ast; the internal flag being set on a child of MyActor
13640  *      &ast;/
13641  *   }
13642  * ]|
13643  *
13644  * This function will be used by Clutter to toggle an "internal child"
13645  * flag whenever clutter_actor_set_parent() is called; internal children
13646  * are handled differently by Clutter, specifically when destroying their
13647  * parent.
13648  *
13649  * Call clutter_actor_pop_internal() when you finished adding internal
13650  * children.
13651  *
13652  * Nested calls to clutter_actor_push_internal() are allowed, but each
13653  * one must by followed by a clutter_actor_pop_internal() call.
13654  *
13655  * Since: 1.2
13656  *
13657  * Deprecated: 1.10: All children of an actor are accessible through
13658  *   the #ClutterActor API, and #ClutterActor implements the
13659  *   #ClutterContainer interface, so this function is only useful
13660  *   for legacy containers overriding the default implementation.
13661  */
13662 void
13663 clutter_actor_push_internal (ClutterActor *self)
13664 {
13665   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13666
13667   self->priv->internal_child += 1;
13668 }
13669
13670 /**
13671  * clutter_actor_pop_internal:
13672  * @self: a #ClutterActor
13673  *
13674  * Disables the effects of clutter_actor_push_internal().
13675  *
13676  * Since: 1.2
13677  *
13678  * Deprecated: 1.10: All children of an actor are accessible through
13679  *   the #ClutterActor API. This function is only useful for legacy
13680  *   containers overriding the default implementation of the
13681  *   #ClutterContainer interface.
13682  */
13683 void
13684 clutter_actor_pop_internal (ClutterActor *self)
13685 {
13686   ClutterActorPrivate *priv;
13687
13688   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13689
13690   priv = self->priv;
13691
13692   if (priv->internal_child == 0)
13693     {
13694       g_warning ("Mismatched %s: you need to call "
13695                  "clutter_actor_push_composite() at least once before "
13696                  "calling this function", G_STRFUNC);
13697       return;
13698     }
13699
13700   priv->internal_child -= 1;
13701 }
13702
13703 /**
13704  * clutter_actor_has_pointer:
13705  * @self: a #ClutterActor
13706  *
13707  * Checks whether an actor contains the pointer of a
13708  * #ClutterInputDevice
13709  *
13710  * Return value: %TRUE if the actor contains the pointer, and
13711  *   %FALSE otherwise
13712  *
13713  * Since: 1.2
13714  */
13715 gboolean
13716 clutter_actor_has_pointer (ClutterActor *self)
13717 {
13718   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13719
13720   return self->priv->has_pointer;
13721 }
13722
13723 /* XXX: This is a workaround for not being able to break the ABI of
13724  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
13725  * clutter_actor_queue_clipped_redraw() for details.
13726  */
13727 ClutterPaintVolume *
13728 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
13729 {
13730   return g_object_get_data (G_OBJECT (self),
13731                             "-clutter-actor-queue-redraw-clip");
13732 }
13733
13734 void
13735 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
13736                                       ClutterPaintVolume *clip)
13737 {
13738   g_object_set_data (G_OBJECT (self),
13739                      "-clutter-actor-queue-redraw-clip",
13740                      clip);
13741 }
13742
13743 /**
13744  * clutter_actor_has_allocation:
13745  * @self: a #ClutterActor
13746  *
13747  * Checks if the actor has an up-to-date allocation assigned to
13748  * it. This means that the actor should have an allocation: it's
13749  * visible and has a parent. It also means that there is no
13750  * outstanding relayout request in progress for the actor or its
13751  * children (There might be other outstanding layout requests in
13752  * progress that will cause the actor to get a new allocation
13753  * when the stage is laid out, however).
13754  *
13755  * If this function returns %FALSE, then the actor will normally
13756  * be allocated before it is next drawn on the screen.
13757  *
13758  * Return value: %TRUE if the actor has an up-to-date allocation
13759  *
13760  * Since: 1.4
13761  */
13762 gboolean
13763 clutter_actor_has_allocation (ClutterActor *self)
13764 {
13765   ClutterActorPrivate *priv;
13766
13767   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13768
13769   priv = self->priv;
13770
13771   return priv->parent != NULL &&
13772          CLUTTER_ACTOR_IS_VISIBLE (self) &&
13773          !priv->needs_allocation;
13774 }
13775
13776 /**
13777  * clutter_actor_add_action:
13778  * @self: a #ClutterActor
13779  * @action: a #ClutterAction
13780  *
13781  * Adds @action to the list of actions applied to @self
13782  *
13783  * A #ClutterAction can only belong to one actor at a time
13784  *
13785  * The #ClutterActor will hold a reference on @action until either
13786  * clutter_actor_remove_action() or clutter_actor_clear_actions()
13787  * is called
13788  *
13789  * Since: 1.4
13790  */
13791 void
13792 clutter_actor_add_action (ClutterActor  *self,
13793                           ClutterAction *action)
13794 {
13795   ClutterActorPrivate *priv;
13796
13797   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13798   g_return_if_fail (CLUTTER_IS_ACTION (action));
13799
13800   priv = self->priv;
13801
13802   if (priv->actions == NULL)
13803     {
13804       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13805       priv->actions->actor = self;
13806     }
13807
13808   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
13809
13810   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13811 }
13812
13813 /**
13814  * clutter_actor_add_action_with_name:
13815  * @self: a #ClutterActor
13816  * @name: the name to set on the action
13817  * @action: a #ClutterAction
13818  *
13819  * A convenience function for setting the name of a #ClutterAction
13820  * while adding it to the list of actions applied to @self
13821  *
13822  * This function is the logical equivalent of:
13823  *
13824  * |[
13825  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13826  *   clutter_actor_add_action (self, action);
13827  * ]|
13828  *
13829  * Since: 1.4
13830  */
13831 void
13832 clutter_actor_add_action_with_name (ClutterActor  *self,
13833                                     const gchar   *name,
13834                                     ClutterAction *action)
13835 {
13836   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13837   g_return_if_fail (name != NULL);
13838   g_return_if_fail (CLUTTER_IS_ACTION (action));
13839
13840   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13841   clutter_actor_add_action (self, action);
13842 }
13843
13844 /**
13845  * clutter_actor_remove_action:
13846  * @self: a #ClutterActor
13847  * @action: a #ClutterAction
13848  *
13849  * Removes @action from the list of actions applied to @self
13850  *
13851  * The reference held by @self on the #ClutterAction will be released
13852  *
13853  * Since: 1.4
13854  */
13855 void
13856 clutter_actor_remove_action (ClutterActor  *self,
13857                              ClutterAction *action)
13858 {
13859   ClutterActorPrivate *priv;
13860
13861   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13862   g_return_if_fail (CLUTTER_IS_ACTION (action));
13863
13864   priv = self->priv;
13865
13866   if (priv->actions == NULL)
13867     return;
13868
13869   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
13870
13871   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13872 }
13873
13874 /**
13875  * clutter_actor_remove_action_by_name:
13876  * @self: a #ClutterActor
13877  * @name: the name of the action to remove
13878  *
13879  * Removes the #ClutterAction with the given name from the list
13880  * of actions applied to @self
13881  *
13882  * Since: 1.4
13883  */
13884 void
13885 clutter_actor_remove_action_by_name (ClutterActor *self,
13886                                      const gchar  *name)
13887 {
13888   ClutterActorPrivate *priv;
13889   ClutterActorMeta *meta;
13890
13891   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13892   g_return_if_fail (name != NULL);
13893
13894   priv = self->priv;
13895
13896   if (priv->actions == NULL)
13897     return;
13898
13899   meta = _clutter_meta_group_get_meta (priv->actions, name);
13900   if (meta == NULL)
13901     return;
13902
13903   _clutter_meta_group_remove_meta (priv->actions, meta);
13904
13905   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13906 }
13907
13908 /**
13909  * clutter_actor_get_actions:
13910  * @self: a #ClutterActor
13911  *
13912  * Retrieves the list of actions applied to @self
13913  *
13914  * Return value: (transfer container) (element-type Clutter.Action): a copy
13915  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
13916  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13917  *   allocated by the returned #GList
13918  *
13919  * Since: 1.4
13920  */
13921 GList *
13922 clutter_actor_get_actions (ClutterActor *self)
13923 {
13924   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13925
13926   if (self->priv->actions == NULL)
13927     return NULL;
13928
13929   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
13930 }
13931
13932 /**
13933  * clutter_actor_get_action:
13934  * @self: a #ClutterActor
13935  * @name: the name of the action to retrieve
13936  *
13937  * Retrieves the #ClutterAction with the given name in the list
13938  * of actions applied to @self
13939  *
13940  * Return value: (transfer none): a #ClutterAction for the given
13941  *   name, or %NULL. The returned #ClutterAction is owned by the
13942  *   actor and it should not be unreferenced directly
13943  *
13944  * Since: 1.4
13945  */
13946 ClutterAction *
13947 clutter_actor_get_action (ClutterActor *self,
13948                           const gchar  *name)
13949 {
13950   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13951   g_return_val_if_fail (name != NULL, NULL);
13952
13953   if (self->priv->actions == NULL)
13954     return NULL;
13955
13956   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
13957 }
13958
13959 /**
13960  * clutter_actor_clear_actions:
13961  * @self: a #ClutterActor
13962  *
13963  * Clears the list of actions applied to @self
13964  *
13965  * Since: 1.4
13966  */
13967 void
13968 clutter_actor_clear_actions (ClutterActor *self)
13969 {
13970   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13971
13972   if (self->priv->actions == NULL)
13973     return;
13974
13975   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
13976 }
13977
13978 /**
13979  * clutter_actor_add_constraint:
13980  * @self: a #ClutterActor
13981  * @constraint: a #ClutterConstraint
13982  *
13983  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
13984  * to @self
13985  *
13986  * The #ClutterActor will hold a reference on the @constraint until
13987  * either clutter_actor_remove_constraint() or
13988  * clutter_actor_clear_constraints() is called.
13989  *
13990  * Since: 1.4
13991  */
13992 void
13993 clutter_actor_add_constraint (ClutterActor      *self,
13994                               ClutterConstraint *constraint)
13995 {
13996   ClutterActorPrivate *priv;
13997
13998   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13999   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14000
14001   priv = self->priv;
14002
14003   if (priv->constraints == NULL)
14004     {
14005       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14006       priv->constraints->actor = self;
14007     }
14008
14009   _clutter_meta_group_add_meta (priv->constraints,
14010                                 CLUTTER_ACTOR_META (constraint));
14011   clutter_actor_queue_relayout (self);
14012
14013   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14014 }
14015
14016 /**
14017  * clutter_actor_add_constraint_with_name:
14018  * @self: a #ClutterActor
14019  * @name: the name to set on the constraint
14020  * @constraint: a #ClutterConstraint
14021  *
14022  * A convenience function for setting the name of a #ClutterConstraint
14023  * while adding it to the list of constraints applied to @self
14024  *
14025  * This function is the logical equivalent of:
14026  *
14027  * |[
14028  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14029  *   clutter_actor_add_constraint (self, constraint);
14030  * ]|
14031  *
14032  * Since: 1.4
14033  */
14034 void
14035 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14036                                         const gchar       *name,
14037                                         ClutterConstraint *constraint)
14038 {
14039   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14040   g_return_if_fail (name != NULL);
14041   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14042
14043   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14044   clutter_actor_add_constraint (self, constraint);
14045 }
14046
14047 /**
14048  * clutter_actor_remove_constraint:
14049  * @self: a #ClutterActor
14050  * @constraint: a #ClutterConstraint
14051  *
14052  * Removes @constraint from the list of constraints applied to @self
14053  *
14054  * The reference held by @self on the #ClutterConstraint will be released
14055  *
14056  * Since: 1.4
14057  */
14058 void
14059 clutter_actor_remove_constraint (ClutterActor      *self,
14060                                  ClutterConstraint *constraint)
14061 {
14062   ClutterActorPrivate *priv;
14063
14064   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14065   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14066
14067   priv = self->priv;
14068
14069   if (priv->constraints == NULL)
14070     return;
14071
14072   _clutter_meta_group_remove_meta (priv->constraints,
14073                                    CLUTTER_ACTOR_META (constraint));
14074   clutter_actor_queue_relayout (self);
14075
14076   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14077 }
14078
14079 /**
14080  * clutter_actor_remove_constraint_by_name:
14081  * @self: a #ClutterActor
14082  * @name: the name of the constraint to remove
14083  *
14084  * Removes the #ClutterConstraint with the given name from the list
14085  * of constraints applied to @self
14086  *
14087  * Since: 1.4
14088  */
14089 void
14090 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14091                                          const gchar  *name)
14092 {
14093   ClutterActorPrivate *priv;
14094   ClutterActorMeta *meta;
14095
14096   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14097   g_return_if_fail (name != NULL);
14098
14099   priv = self->priv;
14100
14101   if (priv->constraints == NULL)
14102     return;
14103
14104   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14105   if (meta == NULL)
14106     return;
14107
14108   _clutter_meta_group_remove_meta (priv->constraints, meta);
14109   clutter_actor_queue_relayout (self);
14110 }
14111
14112 /**
14113  * clutter_actor_get_constraints:
14114  * @self: a #ClutterActor
14115  *
14116  * Retrieves the list of constraints applied to @self
14117  *
14118  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14119  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14120  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14121  *   allocated by the returned #GList
14122  *
14123  * Since: 1.4
14124  */
14125 GList *
14126 clutter_actor_get_constraints (ClutterActor *self)
14127 {
14128   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14129
14130   if (self->priv->constraints == NULL)
14131     return NULL;
14132
14133   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14134 }
14135
14136 /**
14137  * clutter_actor_get_constraint:
14138  * @self: a #ClutterActor
14139  * @name: the name of the constraint to retrieve
14140  *
14141  * Retrieves the #ClutterConstraint with the given name in the list
14142  * of constraints applied to @self
14143  *
14144  * Return value: (transfer none): a #ClutterConstraint for the given
14145  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14146  *   actor and it should not be unreferenced directly
14147  *
14148  * Since: 1.4
14149  */
14150 ClutterConstraint *
14151 clutter_actor_get_constraint (ClutterActor *self,
14152                               const gchar  *name)
14153 {
14154   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14155   g_return_val_if_fail (name != NULL, NULL);
14156
14157   if (self->priv->constraints == NULL)
14158     return NULL;
14159
14160   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14161 }
14162
14163 /**
14164  * clutter_actor_clear_constraints:
14165  * @self: a #ClutterActor
14166  *
14167  * Clears the list of constraints applied to @self
14168  *
14169  * Since: 1.4
14170  */
14171 void
14172 clutter_actor_clear_constraints (ClutterActor *self)
14173 {
14174   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14175
14176   if (self->priv->constraints == NULL)
14177     return;
14178
14179   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14180
14181   clutter_actor_queue_relayout (self);
14182 }
14183
14184 /**
14185  * clutter_actor_set_clip_to_allocation:
14186  * @self: a #ClutterActor
14187  * @clip_set: %TRUE to apply a clip tracking the allocation
14188  *
14189  * Sets whether @self should be clipped to the same size as its
14190  * allocation
14191  *
14192  * Since: 1.4
14193  */
14194 void
14195 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14196                                       gboolean      clip_set)
14197 {
14198   ClutterActorPrivate *priv;
14199
14200   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14201
14202   clip_set = !!clip_set;
14203
14204   priv = self->priv;
14205
14206   if (priv->clip_to_allocation != clip_set)
14207     {
14208       priv->clip_to_allocation = clip_set;
14209
14210       clutter_actor_queue_redraw (self);
14211
14212       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14213     }
14214 }
14215
14216 /**
14217  * clutter_actor_get_clip_to_allocation:
14218  * @self: a #ClutterActor
14219  *
14220  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14221  *
14222  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14223  *
14224  * Since: 1.4
14225  */
14226 gboolean
14227 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14228 {
14229   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14230
14231   return self->priv->clip_to_allocation;
14232 }
14233
14234 /**
14235  * clutter_actor_add_effect:
14236  * @self: a #ClutterActor
14237  * @effect: a #ClutterEffect
14238  *
14239  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14240  *
14241  * The #ClutterActor will hold a reference on the @effect until either
14242  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14243  * called.
14244  *
14245  * Since: 1.4
14246  */
14247 void
14248 clutter_actor_add_effect (ClutterActor  *self,
14249                           ClutterEffect *effect)
14250 {
14251   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14252   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14253
14254   _clutter_actor_add_effect_internal (self, effect);
14255
14256   clutter_actor_queue_redraw (self);
14257
14258   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14259 }
14260
14261 /**
14262  * clutter_actor_add_effect_with_name:
14263  * @self: a #ClutterActor
14264  * @name: the name to set on the effect
14265  * @effect: a #ClutterEffect
14266  *
14267  * A convenience function for setting the name of a #ClutterEffect
14268  * while adding it to the list of effectss applied to @self
14269  *
14270  * This function is the logical equivalent of:
14271  *
14272  * |[
14273  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14274  *   clutter_actor_add_effect (self, effect);
14275  * ]|
14276  *
14277  * Since: 1.4
14278  */
14279 void
14280 clutter_actor_add_effect_with_name (ClutterActor  *self,
14281                                     const gchar   *name,
14282                                     ClutterEffect *effect)
14283 {
14284   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14285   g_return_if_fail (name != NULL);
14286   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14287
14288   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14289   clutter_actor_add_effect (self, effect);
14290 }
14291
14292 /**
14293  * clutter_actor_remove_effect:
14294  * @self: a #ClutterActor
14295  * @effect: a #ClutterEffect
14296  *
14297  * Removes @effect from the list of effects applied to @self
14298  *
14299  * The reference held by @self on the #ClutterEffect will be released
14300  *
14301  * Since: 1.4
14302  */
14303 void
14304 clutter_actor_remove_effect (ClutterActor  *self,
14305                              ClutterEffect *effect)
14306 {
14307   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14308   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14309
14310   _clutter_actor_remove_effect_internal (self, effect);
14311
14312   clutter_actor_queue_redraw (self);
14313
14314   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14315 }
14316
14317 /**
14318  * clutter_actor_remove_effect_by_name:
14319  * @self: a #ClutterActor
14320  * @name: the name of the effect to remove
14321  *
14322  * Removes the #ClutterEffect with the given name from the list
14323  * of effects applied to @self
14324  *
14325  * Since: 1.4
14326  */
14327 void
14328 clutter_actor_remove_effect_by_name (ClutterActor *self,
14329                                      const gchar  *name)
14330 {
14331   ClutterActorPrivate *priv;
14332   ClutterActorMeta *meta;
14333
14334   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14335   g_return_if_fail (name != NULL);
14336
14337   priv = self->priv;
14338
14339   if (priv->effects == NULL)
14340     return;
14341
14342   meta = _clutter_meta_group_get_meta (priv->effects, name);
14343   if (meta == NULL)
14344     return;
14345
14346   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14347 }
14348
14349 /**
14350  * clutter_actor_get_effects:
14351  * @self: a #ClutterActor
14352  *
14353  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14354  *
14355  * Return value: (transfer container) (element-type Clutter.Effect): a list
14356  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14357  *   list are owned by Clutter and they should not be freed. You should
14358  *   free the returned list using g_list_free() when done
14359  *
14360  * Since: 1.4
14361  */
14362 GList *
14363 clutter_actor_get_effects (ClutterActor *self)
14364 {
14365   ClutterActorPrivate *priv;
14366
14367   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14368
14369   priv = self->priv;
14370
14371   if (priv->effects == NULL)
14372     return NULL;
14373
14374   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14375 }
14376
14377 /**
14378  * clutter_actor_get_effect:
14379  * @self: a #ClutterActor
14380  * @name: the name of the effect to retrieve
14381  *
14382  * Retrieves the #ClutterEffect with the given name in the list
14383  * of effects applied to @self
14384  *
14385  * Return value: (transfer none): a #ClutterEffect for the given
14386  *   name, or %NULL. The returned #ClutterEffect is owned by the
14387  *   actor and it should not be unreferenced directly
14388  *
14389  * Since: 1.4
14390  */
14391 ClutterEffect *
14392 clutter_actor_get_effect (ClutterActor *self,
14393                           const gchar  *name)
14394 {
14395   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14396   g_return_val_if_fail (name != NULL, NULL);
14397
14398   if (self->priv->effects == NULL)
14399     return NULL;
14400
14401   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14402 }
14403
14404 /**
14405  * clutter_actor_clear_effects:
14406  * @self: a #ClutterActor
14407  *
14408  * Clears the list of effects applied to @self
14409  *
14410  * Since: 1.4
14411  */
14412 void
14413 clutter_actor_clear_effects (ClutterActor *self)
14414 {
14415   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14416
14417   if (self->priv->effects == NULL)
14418     return;
14419
14420   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14421
14422   clutter_actor_queue_redraw (self);
14423 }
14424
14425 /**
14426  * clutter_actor_has_key_focus:
14427  * @self: a #ClutterActor
14428  *
14429  * Checks whether @self is the #ClutterActor that has key focus
14430  *
14431  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14432  *
14433  * Since: 1.4
14434  */
14435 gboolean
14436 clutter_actor_has_key_focus (ClutterActor *self)
14437 {
14438   ClutterActor *stage;
14439
14440   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14441
14442   stage = _clutter_actor_get_stage_internal (self);
14443   if (stage == NULL)
14444     return FALSE;
14445
14446   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14447 }
14448
14449 static gboolean
14450 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14451                                       ClutterPaintVolume *pv)
14452 {
14453   ClutterActorPrivate *priv = self->priv;
14454
14455   /* Actors are only expected to report a valid paint volume
14456    * while they have a valid allocation. */
14457   if (G_UNLIKELY (priv->needs_allocation))
14458     {
14459       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14460                     "Actor needs allocation",
14461                     _clutter_actor_get_debug_name (self));
14462       return FALSE;
14463     }
14464
14465   /* Check if there are any handlers connected to the paint
14466    * signal. If there are then all bets are off for what the paint
14467    * volume for this actor might possibly be!
14468    *
14469    * XXX: It's expected that this is going to end up being quite a
14470    * costly check to have to do here, but we haven't come up with
14471    * another solution that can reliably catch paint signal handlers at
14472    * the right time to either avoid artefacts due to invalid stage
14473    * clipping or due to incorrect culling.
14474    *
14475    * Previously we checked in clutter_actor_paint(), but at that time
14476    * we may already be using a stage clip that could be derived from
14477    * an invalid paint-volume. We used to try and handle that by
14478    * queuing a follow up, unclipped, redraw but still the previous
14479    * checking wasn't enough to catch invalid volumes involved in
14480    * culling (considering that containers may derive their volume from
14481    * children that haven't yet been painted)
14482    *
14483    * Longer term, improved solutions could be:
14484    * - Disallow painting in the paint signal, only allow using it
14485    *   for tracking when paints happen. We can add another API that
14486    *   allows monkey patching the paint of arbitrary actors but in a
14487    *   more controlled way and that also supports modifying the
14488    *   paint-volume.
14489    * - If we could be notified somehow when signal handlers are
14490    *   connected we wouldn't have to poll for handlers like this.
14491    */
14492   if (g_signal_has_handler_pending (self,
14493                                     actor_signals[PAINT],
14494                                     0,
14495                                     TRUE))
14496     {
14497       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14498                     "Actor has \"paint\" signal handlers",
14499                     _clutter_actor_get_debug_name (self));
14500       return FALSE;
14501     }
14502
14503   _clutter_paint_volume_init_static (pv, self);
14504
14505   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
14506     {
14507       clutter_paint_volume_free (pv);
14508       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14509                     "Actor failed to report a volume",
14510                     _clutter_actor_get_debug_name (self));
14511       return FALSE;
14512     }
14513
14514   /* since effects can modify the paint volume, we allow them to actually
14515    * do this by making get_paint_volume() "context sensitive"
14516    */
14517   if (priv->effects != NULL)
14518     {
14519       if (priv->current_effect != NULL)
14520         {
14521           const GList *effects, *l;
14522
14523           /* if we are being called from within the paint sequence of
14524            * an actor, get the paint volume up to the current effect
14525            */
14526           effects = _clutter_meta_group_peek_metas (priv->effects);
14527           for (l = effects;
14528                l != NULL || (l != NULL && l->data != priv->current_effect);
14529                l = l->next)
14530             {
14531               if (!_clutter_effect_get_paint_volume (l->data, pv))
14532                 {
14533                   clutter_paint_volume_free (pv);
14534                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14535                                 "Effect (%s) failed to report a volume",
14536                                 _clutter_actor_get_debug_name (self),
14537                                 _clutter_actor_meta_get_debug_name (l->data));
14538                   return FALSE;
14539                 }
14540             }
14541         }
14542       else
14543         {
14544           const GList *effects, *l;
14545
14546           /* otherwise, get the cumulative volume */
14547           effects = _clutter_meta_group_peek_metas (priv->effects);
14548           for (l = effects; l != NULL; l = l->next)
14549             if (!_clutter_effect_get_paint_volume (l->data, pv))
14550               {
14551                 clutter_paint_volume_free (pv);
14552                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14553                               "Effect (%s) failed to report a volume",
14554                               _clutter_actor_get_debug_name (self),
14555                               _clutter_actor_meta_get_debug_name (l->data));
14556                 return FALSE;
14557               }
14558         }
14559     }
14560
14561   return TRUE;
14562 }
14563
14564 /* The public clutter_actor_get_paint_volume API returns a const
14565  * pointer since we return a pointer directly to the cached
14566  * PaintVolume associated with the actor and don't want the user to
14567  * inadvertently modify it, but for internal uses we sometimes need
14568  * access to the same PaintVolume but need to apply some book-keeping
14569  * modifications to it so we don't want a const pointer.
14570  */
14571 static ClutterPaintVolume *
14572 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
14573 {
14574   ClutterActorPrivate *priv;
14575
14576   priv = self->priv;
14577
14578   if (priv->paint_volume_valid)
14579     clutter_paint_volume_free (&priv->paint_volume);
14580
14581   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
14582     {
14583       priv->paint_volume_valid = TRUE;
14584       return &priv->paint_volume;
14585     }
14586   else
14587     {
14588       priv->paint_volume_valid = FALSE;
14589       return NULL;
14590     }
14591 }
14592
14593 /**
14594  * clutter_actor_get_paint_volume:
14595  * @self: a #ClutterActor
14596  *
14597  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
14598  * when a paint volume can't be determined.
14599  *
14600  * The paint volume is defined as the 3D space occupied by an actor
14601  * when being painted.
14602  *
14603  * This function will call the <function>get_paint_volume()</function>
14604  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
14605  * should not usually care about overriding the default implementation,
14606  * unless they are, for instance: painting outside their allocation, or
14607  * actors with a depth factor (not in terms of #ClutterActor:depth but real
14608  * 3D depth).
14609  *
14610  * <note>2D actors overriding <function>get_paint_volume()</function>
14611  * ensure their volume has a depth of 0. (This will be true so long as
14612  * you don't call clutter_paint_volume_set_depth().)</note>
14613  *
14614  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
14615  *   or %NULL if no volume could be determined. The returned pointer
14616  *   is not guaranteed to be valid across multiple frames; if you want
14617  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
14618  *
14619  * Since: 1.6
14620  */
14621 const ClutterPaintVolume *
14622 clutter_actor_get_paint_volume (ClutterActor *self)
14623 {
14624   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14625
14626   return _clutter_actor_get_paint_volume_mutable (self);
14627 }
14628
14629 /**
14630  * clutter_actor_get_transformed_paint_volume:
14631  * @self: a #ClutterActor
14632  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
14633  *    (or %NULL for the stage)
14634  *
14635  * Retrieves the 3D paint volume of an actor like
14636  * clutter_actor_get_paint_volume() does (Please refer to the
14637  * documentation of clutter_actor_get_paint_volume() for more
14638  * details.) and it additionally transforms the paint volume into the
14639  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
14640  * is passed for @relative_to_ancestor)
14641  *
14642  * This can be used by containers that base their paint volume on
14643  * the volume of their children. Such containers can query the
14644  * transformed paint volume of all of its children and union them
14645  * together using clutter_paint_volume_union().
14646  *
14647  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
14648  *   or %NULL if no volume could be determined. The returned pointer is
14649  *   not guaranteed to be valid across multiple frames; if you wish to
14650  *   keep it, you will have to copy it using clutter_paint_volume_copy().
14651  *
14652  * Since: 1.6
14653  */
14654 const ClutterPaintVolume *
14655 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
14656                                             ClutterActor *relative_to_ancestor)
14657 {
14658   const ClutterPaintVolume *volume;
14659   ClutterActor *stage;
14660   ClutterPaintVolume *transformed_volume;
14661
14662   stage = _clutter_actor_get_stage_internal (self);
14663   if (G_UNLIKELY (stage == NULL))
14664     return NULL;
14665
14666   if (relative_to_ancestor == NULL)
14667     relative_to_ancestor = stage;
14668
14669   volume = clutter_actor_get_paint_volume (self);
14670   if (volume == NULL)
14671     return NULL;
14672
14673   transformed_volume =
14674     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
14675
14676   _clutter_paint_volume_copy_static (volume, transformed_volume);
14677
14678   _clutter_paint_volume_transform_relative (transformed_volume,
14679                                             relative_to_ancestor);
14680
14681   return transformed_volume;
14682 }
14683
14684 /**
14685  * clutter_actor_get_paint_box:
14686  * @self: a #ClutterActor
14687  * @box: (out): return location for a #ClutterActorBox
14688  *
14689  * Retrieves the paint volume of the passed #ClutterActor, and
14690  * transforms it into a 2D bounding box in stage coordinates.
14691  *
14692  * This function is useful to determine the on screen area occupied by
14693  * the actor. The box is only an approximation and may often be
14694  * considerably larger due to the optimizations used to calculate the
14695  * box. The box is never smaller though, so it can reliably be used
14696  * for culling.
14697  *
14698  * There are times when a 2D paint box can't be determined, e.g.
14699  * because the actor isn't yet parented under a stage or because
14700  * the actor is unable to determine a paint volume.
14701  *
14702  * Return value: %TRUE if a 2D paint box could be determined, else
14703  * %FALSE.
14704  *
14705  * Since: 1.6
14706  */
14707 gboolean
14708 clutter_actor_get_paint_box (ClutterActor    *self,
14709                              ClutterActorBox *box)
14710 {
14711   ClutterActor *stage;
14712   ClutterPaintVolume *pv;
14713
14714   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14715   g_return_val_if_fail (box != NULL, FALSE);
14716
14717   stage = _clutter_actor_get_stage_internal (self);
14718   if (G_UNLIKELY (!stage))
14719     return FALSE;
14720
14721   pv = _clutter_actor_get_paint_volume_mutable (self);
14722   if (G_UNLIKELY (!pv))
14723     return FALSE;
14724
14725   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
14726
14727   return TRUE;
14728 }
14729
14730 /**
14731  * clutter_actor_has_overlaps:
14732  * @self: A #ClutterActor
14733  *
14734  * Asks the actor's implementation whether it may contain overlapping
14735  * primitives.
14736  *
14737  * For example; Clutter may use this to determine whether the painting
14738  * should be redirected to an offscreen buffer to correctly implement
14739  * the opacity property.
14740  *
14741  * Custom actors can override the default response by implementing the
14742  * #ClutterActor <function>has_overlaps</function> virtual function. See
14743  * clutter_actor_set_offscreen_redirect() for more information.
14744  *
14745  * Return value: %TRUE if the actor may have overlapping primitives, and
14746  *   %FALSE otherwise
14747  *
14748  * Since: 1.8
14749  */
14750 gboolean
14751 clutter_actor_has_overlaps (ClutterActor *self)
14752 {
14753   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14754
14755   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
14756 }
14757
14758 /**
14759  * clutter_actor_has_effects:
14760  * @self: A #ClutterActor
14761  *
14762  * Returns whether the actor has any effects applied.
14763  *
14764  * Return value: %TRUE if the actor has any effects,
14765  *   %FALSE otherwise
14766  *
14767  * Since: 1.10
14768  */
14769 gboolean
14770 clutter_actor_has_effects (ClutterActor *self)
14771 {
14772   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14773
14774   if (self->priv->effects == NULL)
14775     return FALSE;
14776
14777   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
14778 }
14779
14780 /**
14781  * clutter_actor_has_constraints:
14782  * @self: A #ClutterActor
14783  *
14784  * Returns whether the actor has any constraints applied.
14785  *
14786  * Return value: %TRUE if the actor has any constraints,
14787  *   %FALSE otherwise
14788  *
14789  * Since: 1.10
14790  */
14791 gboolean
14792 clutter_actor_has_constraints (ClutterActor *self)
14793 {
14794   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14795
14796   return self->priv->constraints != NULL;
14797 }
14798
14799 /**
14800  * clutter_actor_has_actions:
14801  * @self: A #ClutterActor
14802  *
14803  * Returns whether the actor has any actions applied.
14804  *
14805  * Return value: %TRUE if the actor has any actions,
14806  *   %FALSE otherwise
14807  *
14808  * Since: 1.10
14809  */
14810 gboolean
14811 clutter_actor_has_actions (ClutterActor *self)
14812 {
14813   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14814
14815   return self->priv->actions != NULL;
14816 }
14817
14818 /**
14819  * clutter_actor_get_n_children:
14820  * @self: a #ClutterActor
14821  *
14822  * Retrieves the number of children of @self.
14823  *
14824  * Return value: the number of children of an actor
14825  *
14826  * Since: 1.10
14827  */
14828 gint
14829 clutter_actor_get_n_children (ClutterActor *self)
14830 {
14831   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14832
14833   return self->priv->n_children;
14834 }
14835
14836 /**
14837  * clutter_actor_get_child_at_index:
14838  * @self: a #ClutterActor
14839  * @index_: the position in the list of children
14840  *
14841  * Retrieves the actor at the given @index_ inside the list of
14842  * children of @self.
14843  *
14844  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
14845  *
14846  * Since: 1.10
14847  */
14848 ClutterActor *
14849 clutter_actor_get_child_at_index (ClutterActor *self,
14850                                   gint          index_)
14851 {
14852   ClutterActor *iter;
14853   int i;
14854
14855   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14856   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
14857
14858   for (iter = self->priv->first_child, i = 0;
14859        iter != NULL && i < index_;
14860        iter = iter->priv->next_sibling, i += 1)
14861     ;
14862
14863   return iter;
14864 }
14865
14866 /*< private >
14867  * _clutter_actor_foreach_child:
14868  * @actor: The actor whos children you want to iterate
14869  * @callback: The function to call for each child
14870  * @user_data: Private data to pass to @callback
14871  *
14872  * Calls a given @callback once for each child of the specified @actor and
14873  * passing the @user_data pointer each time.
14874  *
14875  * Return value: returns %TRUE if all children were iterated, else
14876  *    %FALSE if a callback broke out of iteration early.
14877  */
14878 gboolean
14879 _clutter_actor_foreach_child (ClutterActor           *self,
14880                               ClutterForeachCallback  callback,
14881                               gpointer                user_data)
14882 {
14883   ClutterActorPrivate *priv = self->priv;
14884   ClutterActor *iter;
14885   gboolean cont;
14886
14887   for (cont = TRUE, iter = priv->first_child;
14888        cont && iter != NULL;
14889        iter = iter->priv->next_sibling)
14890     {
14891       cont = callback (iter, user_data);
14892     }
14893
14894   return cont;
14895 }
14896
14897 /* For debugging purposes this gives us a simple way to print out
14898  * the scenegraph e.g in gdb using:
14899  * [|
14900  *   _clutter_actor_traverse (stage,
14901  *                            0,
14902  *                            _clutter_debug_print_actor_cb,
14903  *                            NULL,
14904  *                            NULL);
14905  * |]
14906  */
14907 ClutterActorTraverseVisitFlags
14908 _clutter_debug_print_actor_cb (ClutterActor *actor,
14909                                int depth,
14910                                void *user_data)
14911 {
14912   g_print ("%*s%s:%p\n",
14913            depth * 2, "",
14914            _clutter_actor_get_debug_name (actor),
14915            actor);
14916
14917   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14918 }
14919
14920 static void
14921 _clutter_actor_traverse_breadth (ClutterActor           *actor,
14922                                  ClutterTraverseCallback callback,
14923                                  gpointer                user_data)
14924 {
14925   GQueue *queue = g_queue_new ();
14926   ClutterActor dummy;
14927   int current_depth = 0;
14928
14929   g_queue_push_tail (queue, actor);
14930   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
14931
14932   while ((actor = g_queue_pop_head (queue)))
14933     {
14934       ClutterActorTraverseVisitFlags flags;
14935
14936       if (actor == &dummy)
14937         {
14938           current_depth++;
14939           g_queue_push_tail (queue, &dummy);
14940           continue;
14941         }
14942
14943       flags = callback (actor, current_depth, user_data);
14944       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14945         break;
14946       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14947         {
14948           ClutterActor *iter;
14949
14950           for (iter = actor->priv->first_child;
14951                iter != NULL;
14952                iter = iter->priv->next_sibling)
14953             {
14954               g_queue_push_tail (queue, iter);
14955             }
14956         }
14957     }
14958
14959   g_queue_free (queue);
14960 }
14961
14962 static ClutterActorTraverseVisitFlags
14963 _clutter_actor_traverse_depth (ClutterActor           *actor,
14964                                ClutterTraverseCallback before_children_callback,
14965                                ClutterTraverseCallback after_children_callback,
14966                                int                     current_depth,
14967                                gpointer                user_data)
14968 {
14969   ClutterActorTraverseVisitFlags flags;
14970
14971   flags = before_children_callback (actor, current_depth, user_data);
14972   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14973     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14974
14975   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14976     {
14977       ClutterActor *iter;
14978
14979       for (iter = actor->priv->first_child;
14980            iter != NULL;
14981            iter = iter->priv->next_sibling)
14982         {
14983           flags = _clutter_actor_traverse_depth (iter,
14984                                                  before_children_callback,
14985                                                  after_children_callback,
14986                                                  current_depth + 1,
14987                                                  user_data);
14988
14989           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14990             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14991         }
14992     }
14993
14994   if (after_children_callback)
14995     return after_children_callback (actor, current_depth, user_data);
14996   else
14997     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14998 }
14999
15000 /* _clutter_actor_traverse:
15001  * @actor: The actor to start traversing the graph from
15002  * @flags: These flags may affect how the traversal is done
15003  * @before_children_callback: A function to call before visiting the
15004  *   children of the current actor.
15005  * @after_children_callback: A function to call after visiting the
15006  *   children of the current actor. (Ignored if
15007  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15008  * @user_data: The private data to pass to the callbacks
15009  *
15010  * Traverses the scenegraph starting at the specified @actor and
15011  * descending through all its children and its children's children.
15012  * For each actor traversed @before_children_callback and
15013  * @after_children_callback are called with the specified
15014  * @user_data, before and after visiting that actor's children.
15015  *
15016  * The callbacks can return flags that affect the ongoing traversal
15017  * such as by skipping over an actors children or bailing out of
15018  * any further traversing.
15019  */
15020 void
15021 _clutter_actor_traverse (ClutterActor              *actor,
15022                          ClutterActorTraverseFlags  flags,
15023                          ClutterTraverseCallback    before_children_callback,
15024                          ClutterTraverseCallback    after_children_callback,
15025                          gpointer                   user_data)
15026 {
15027   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15028     _clutter_actor_traverse_breadth (actor,
15029                                      before_children_callback,
15030                                      user_data);
15031   else /* DEPTH_FIRST */
15032     _clutter_actor_traverse_depth (actor,
15033                                    before_children_callback,
15034                                    after_children_callback,
15035                                    0, /* start depth */
15036                                    user_data);
15037 }
15038
15039 static void
15040 on_layout_manager_changed (ClutterLayoutManager *manager,
15041                            ClutterActor         *self)
15042 {
15043   clutter_actor_queue_relayout (self);
15044 }
15045
15046 /**
15047  * clutter_actor_set_layout_manager:
15048  * @self: a #ClutterActor
15049  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15050  *
15051  * Sets the #ClutterLayoutManager delegate object that will be used to
15052  * lay out the children of @self.
15053  *
15054  * The #ClutterActor will take a reference on the passed @manager which
15055  * will be released either when the layout manager is removed, or when
15056  * the actor is destroyed.
15057  *
15058  * Since: 1.10
15059  */
15060 void
15061 clutter_actor_set_layout_manager (ClutterActor         *self,
15062                                   ClutterLayoutManager *manager)
15063 {
15064   ClutterActorPrivate *priv;
15065
15066   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15067   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15068
15069   priv = self->priv;
15070
15071   if (priv->layout_manager != NULL)
15072     {
15073       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15074                                             G_CALLBACK (on_layout_manager_changed),
15075                                             self);
15076       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15077       g_object_unref (priv->layout_manager);
15078     }
15079
15080   priv->layout_manager = manager;
15081
15082   if (priv->layout_manager != NULL)
15083     {
15084       g_object_ref_sink (priv->layout_manager);
15085       clutter_layout_manager_set_container (priv->layout_manager,
15086                                             CLUTTER_CONTAINER (self));
15087       g_signal_connect (priv->layout_manager, "layout-changed",
15088                         G_CALLBACK (on_layout_manager_changed),
15089                         self);
15090     }
15091
15092   clutter_actor_queue_relayout (self);
15093
15094   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15095 }
15096
15097 /**
15098  * clutter_actor_get_layout_manager:
15099  * @self: a #ClutterActor
15100  *
15101  * Retrieves the #ClutterLayoutManager used by @self.
15102  *
15103  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15104  *   or %NULL
15105  *
15106  * Since: 1.10
15107  */
15108 ClutterLayoutManager *
15109 clutter_actor_get_layout_manager (ClutterActor *self)
15110 {
15111   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15112
15113   return self->priv->layout_manager;
15114 }
15115
15116 static const ClutterLayoutInfo default_layout_info = {
15117   0.f,                          /* fixed-x */
15118   0.f,                          /* fixed-y */
15119   { 0, 0, 0, 0 },               /* margin */
15120   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15121   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15122   0.f, 0.f,                     /* min_width, natural_width */
15123   0.f, 0.f,                     /* natual_width, natural_height */
15124 };
15125
15126 static void
15127 layout_info_free (gpointer data)
15128 {
15129   if (G_LIKELY (data != NULL))
15130     g_slice_free (ClutterLayoutInfo, data);
15131 }
15132
15133 /*< private >
15134  * _clutter_actor_get_layout_info:
15135  * @self: a #ClutterActor
15136  *
15137  * Retrieves a pointer to the ClutterLayoutInfo structure.
15138  *
15139  * If the actor does not have a ClutterLayoutInfo associated to it, one
15140  * will be created and initialized to the default values.
15141  *
15142  * This function should be used for setters.
15143  *
15144  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15145  * instead.
15146  *
15147  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15148  */
15149 ClutterLayoutInfo *
15150 _clutter_actor_get_layout_info (ClutterActor *self)
15151 {
15152   ClutterLayoutInfo *retval;
15153
15154   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15155   if (retval == NULL)
15156     {
15157       retval = g_slice_new (ClutterLayoutInfo);
15158
15159       *retval = default_layout_info;
15160
15161       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15162                                retval,
15163                                layout_info_free);
15164     }
15165
15166   return retval;
15167 }
15168
15169 /*< private >
15170  * _clutter_actor_get_layout_info_or_defaults:
15171  * @self: a #ClutterActor
15172  *
15173  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15174  *
15175  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15176  * then the default structure will be returned.
15177  *
15178  * This function should only be used for getters.
15179  *
15180  * Return value: a const pointer to the ClutterLayoutInfo structure
15181  */
15182 const ClutterLayoutInfo *
15183 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15184 {
15185   const ClutterLayoutInfo *info;
15186
15187   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15188   if (info == NULL)
15189     return &default_layout_info;
15190
15191   return info;
15192 }
15193
15194 /**
15195  * clutter_actor_set_x_align:
15196  * @self: a #ClutterActor
15197  * @x_align: the horizontal alignment policy
15198  *
15199  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15200  * actor received extra horizontal space.
15201  *
15202  * See also the #ClutterActor:x-align property.
15203  *
15204  * Since: 1.10
15205  */
15206 void
15207 clutter_actor_set_x_align (ClutterActor      *self,
15208                            ClutterActorAlign  x_align)
15209 {
15210   ClutterLayoutInfo *info;
15211
15212   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15213
15214   info = _clutter_actor_get_layout_info (self);
15215
15216   if (info->x_align != x_align)
15217     {
15218       info->x_align = x_align;
15219
15220       clutter_actor_queue_relayout (self);
15221
15222       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15223     }
15224 }
15225
15226 /**
15227  * clutter_actor_get_x_align:
15228  * @self: a #ClutterActor
15229  *
15230  * Retrieves the horizontal alignment policy set using
15231  * clutter_actor_set_x_align().
15232  *
15233  * Return value: the horizontal alignment policy.
15234  *
15235  * Since: 1.10
15236  */
15237 ClutterActorAlign
15238 clutter_actor_get_x_align (ClutterActor *self)
15239 {
15240   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15241
15242   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15243 }
15244
15245 /**
15246  * clutter_actor_set_y_align:
15247  * @self: a #ClutterActor
15248  * @y_align: the vertical alignment policy
15249  *
15250  * Sets the vertical alignment policy of a #ClutterActor, in case the
15251  * actor received extra vertical space.
15252  *
15253  * See also the #ClutterActor:y-align property.
15254  *
15255  * Since: 1.10
15256  */
15257 void
15258 clutter_actor_set_y_align (ClutterActor      *self,
15259                            ClutterActorAlign  y_align)
15260 {
15261   ClutterLayoutInfo *info;
15262
15263   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15264
15265   info = _clutter_actor_get_layout_info (self);
15266
15267   if (info->y_align != y_align)
15268     {
15269       info->y_align = y_align;
15270
15271       clutter_actor_queue_relayout (self);
15272
15273       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15274     }
15275 }
15276
15277 /**
15278  * clutter_actor_get_y_align:
15279  * @self: a #ClutterActor
15280  *
15281  * Retrieves the vertical alignment policy set using
15282  * clutter_actor_set_y_align().
15283  *
15284  * Return value: the vertical alignment policy.
15285  *
15286  * Since: 1.10
15287  */
15288 ClutterActorAlign
15289 clutter_actor_get_y_align (ClutterActor *self)
15290 {
15291   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15292
15293   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15294 }
15295
15296
15297 /**
15298  * clutter_margin_new:
15299  *
15300  * Creates a new #ClutterMargin.
15301  *
15302  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15303  *   clutter_margin_free() to free the resources associated with it when
15304  *   done.
15305  *
15306  * Since: 1.10
15307  */
15308 ClutterMargin *
15309 clutter_margin_new (void)
15310 {
15311   return g_slice_new0 (ClutterMargin);
15312 }
15313
15314 /**
15315  * clutter_margin_copy:
15316  * @margin_: a #ClutterMargin
15317  *
15318  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15319  * the newly created structure.
15320  *
15321  * Return value: (transfer full): a copy of the #ClutterMargin.
15322  *
15323  * Since: 1.10
15324  */
15325 ClutterMargin *
15326 clutter_margin_copy (const ClutterMargin *margin_)
15327 {
15328   if (G_LIKELY (margin_ != NULL))
15329     return g_slice_dup (ClutterMargin, margin_);
15330
15331   return NULL;
15332 }
15333
15334 /**
15335  * clutter_margin_free:
15336  * @margin_: a #ClutterMargin
15337  *
15338  * Frees the resources allocated by clutter_margin_new() and
15339  * clutter_margin_copy().
15340  *
15341  * Since: 1.10
15342  */
15343 void
15344 clutter_margin_free (ClutterMargin *margin_)
15345 {
15346   if (G_LIKELY (margin_ != NULL))
15347     g_slice_free (ClutterMargin, margin_);
15348 }
15349
15350 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15351                      clutter_margin_copy,
15352                      clutter_margin_free)
15353
15354 /**
15355  * clutter_actor_set_margin:
15356  * @self: a #ClutterActor
15357  * @margin: a #ClutterMargin
15358  *
15359  * Sets all the components of the margin of a #ClutterActor.
15360  *
15361  * Since: 1.10
15362  */
15363 void
15364 clutter_actor_set_margin (ClutterActor        *self,
15365                           const ClutterMargin *margin)
15366 {
15367   ClutterLayoutInfo *info;
15368   gboolean changed;
15369   GObject *obj;
15370
15371   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15372   g_return_if_fail (margin != NULL);
15373
15374   obj = G_OBJECT (self);
15375   changed = FALSE;
15376
15377   g_object_freeze_notify (obj);
15378
15379   info = _clutter_actor_get_layout_info (self);
15380
15381   if (info->margin.top != margin->top)
15382     {
15383       info->margin.top = margin->top;
15384       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15385       changed = TRUE;
15386     }
15387
15388   if (info->margin.right != margin->right)
15389     {
15390       info->margin.right = margin->right;
15391       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15392       changed = TRUE;
15393     }
15394
15395   if (info->margin.bottom != margin->bottom)
15396     {
15397       info->margin.bottom = margin->bottom;
15398       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15399       changed = TRUE;
15400     }
15401
15402   if (info->margin.left != margin->left)
15403     {
15404       info->margin.left = margin->left;
15405       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15406       changed = TRUE;
15407     }
15408
15409   if (changed)
15410     clutter_actor_queue_relayout (self);
15411
15412   g_object_thaw_notify (obj);
15413 }
15414
15415 /**
15416  * clutter_actor_get_margin:
15417  * @self: a #ClutterActor
15418  * @margin: (out caller-allocates): return location for a #ClutterMargin
15419  *
15420  * Retrieves all the components of the margin of a #ClutterActor.
15421  *
15422  * Since: 1.10
15423  */
15424 void
15425 clutter_actor_get_margin (ClutterActor  *self,
15426                           ClutterMargin *margin)
15427 {
15428   const ClutterLayoutInfo *info;
15429
15430   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15431   g_return_if_fail (margin != NULL);
15432
15433   info = _clutter_actor_get_layout_info_or_defaults (self);
15434
15435   *margin = info->margin;
15436 }
15437
15438 /**
15439  * clutter_actor_set_margin_top:
15440  * @self: a #ClutterActor
15441  * @margin: the top margin
15442  *
15443  * Sets the margin from the top of a #ClutterActor.
15444  *
15445  * Since: 1.10
15446  */
15447 void
15448 clutter_actor_set_margin_top (ClutterActor *self,
15449                               gfloat        margin)
15450 {
15451   ClutterLayoutInfo *info;
15452
15453   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15454   g_return_if_fail (margin >= 0.f);
15455
15456   info = _clutter_actor_get_layout_info (self);
15457
15458   if (info->margin.top == margin)
15459     return;
15460
15461   info->margin.top = margin;
15462
15463   clutter_actor_queue_relayout (self);
15464
15465   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15466 }
15467
15468 /**
15469  * clutter_actor_get_margin_top:
15470  * @self: a #ClutterActor
15471  *
15472  * Retrieves the top margin of a #ClutterActor.
15473  *
15474  * Return value: the top margin
15475  *
15476  * Since: 1.10
15477  */
15478 gfloat
15479 clutter_actor_get_margin_top (ClutterActor *self)
15480 {
15481   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15482
15483   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15484 }
15485
15486 /**
15487  * clutter_actor_set_margin_bottom:
15488  * @self: a #ClutterActor
15489  * @margin: the bottom margin
15490  *
15491  * Sets the margin from the bottom of a #ClutterActor.
15492  *
15493  * Since: 1.10
15494  */
15495 void
15496 clutter_actor_set_margin_bottom (ClutterActor *self,
15497                                  gfloat        margin)
15498 {
15499   ClutterLayoutInfo *info;
15500
15501   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15502   g_return_if_fail (margin >= 0.f);
15503
15504   info = _clutter_actor_get_layout_info (self);
15505
15506   if (info->margin.bottom == margin)
15507     return;
15508
15509   info->margin.bottom = margin;
15510
15511   clutter_actor_queue_relayout (self);
15512
15513   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
15514 }
15515
15516 /**
15517  * clutter_actor_get_margin_bottom:
15518  * @self: a #ClutterActor
15519  *
15520  * Retrieves the bottom margin of a #ClutterActor.
15521  *
15522  * Return value: the bottom margin
15523  *
15524  * Since: 1.10
15525  */
15526 gfloat
15527 clutter_actor_get_margin_bottom (ClutterActor *self)
15528 {
15529   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15530
15531   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
15532 }
15533
15534 /**
15535  * clutter_actor_set_margin_left:
15536  * @self: a #ClutterActor
15537  * @margin: the left margin
15538  *
15539  * Sets the margin from the left of a #ClutterActor.
15540  *
15541  * Since: 1.10
15542  */
15543 void
15544 clutter_actor_set_margin_left (ClutterActor *self,
15545                                gfloat        margin)
15546 {
15547   ClutterLayoutInfo *info;
15548
15549   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15550   g_return_if_fail (margin >= 0.f);
15551
15552   info = _clutter_actor_get_layout_info (self);
15553
15554   if (info->margin.left == margin)
15555     return;
15556
15557   info->margin.left = margin;
15558
15559   clutter_actor_queue_relayout (self);
15560
15561   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
15562 }
15563
15564 /**
15565  * clutter_actor_get_margin_left:
15566  * @self: a #ClutterActor
15567  *
15568  * Retrieves the left margin of a #ClutterActor.
15569  *
15570  * Return value: the left margin
15571  *
15572  * Since: 1.10
15573  */
15574 gfloat
15575 clutter_actor_get_margin_left (ClutterActor *self)
15576 {
15577   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15578
15579   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
15580 }
15581
15582 /**
15583  * clutter_actor_set_margin_right:
15584  * @self: a #ClutterActor
15585  * @margin: the right margin
15586  *
15587  * Sets the margin from the right of a #ClutterActor.
15588  *
15589  * Since: 1.10
15590  */
15591 void
15592 clutter_actor_set_margin_right (ClutterActor *self,
15593                                 gfloat        margin)
15594 {
15595   ClutterLayoutInfo *info;
15596
15597   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15598   g_return_if_fail (margin >= 0.f);
15599
15600   info = _clutter_actor_get_layout_info (self);
15601
15602   if (info->margin.right == margin)
15603     return;
15604
15605   info->margin.right = margin;
15606
15607   clutter_actor_queue_relayout (self);
15608
15609   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
15610 }
15611
15612 /**
15613  * clutter_actor_get_margin_right:
15614  * @self: a #ClutterActor
15615  *
15616  * Retrieves the right margin of a #ClutterActor.
15617  *
15618  * Return value: the right margin
15619  *
15620  * Since: 1.10
15621  */
15622 gfloat
15623 clutter_actor_get_margin_right (ClutterActor *self)
15624 {
15625   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15626
15627   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
15628 }
15629
15630 /**
15631  * clutter_actor_set_background_color:
15632  * @self: a #ClutterActor
15633  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
15634  *  set color
15635  *
15636  * Sets the background color of a #ClutterActor.
15637  *
15638  * The background color will be used to cover the whole allocation of the
15639  * actor. The default background color of an actor is transparent.
15640  *
15641  * To check whether an actor has a background color, you can use the
15642  * #ClutterActor:background-color-set actor property.
15643  *
15644  * Since: 1.10
15645  */
15646 void
15647 clutter_actor_set_background_color (ClutterActor       *self,
15648                                     const ClutterColor *color)
15649 {
15650   ClutterActorPrivate *priv;
15651
15652   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15653
15654   priv = self->priv;
15655
15656   if (color == NULL)
15657     {
15658       priv->bg_color_set = FALSE;
15659       g_object_notify_by_pspec (G_OBJECT (self),
15660                                 obj_props[PROP_BACKGROUND_COLOR_SET]);
15661       return;
15662     }
15663
15664   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
15665     return;
15666
15667   priv->bg_color = *color;
15668   priv->bg_color_set = TRUE;
15669
15670   clutter_actor_queue_redraw (self);
15671
15672   g_object_notify_by_pspec (G_OBJECT (self),
15673                             obj_props[PROP_BACKGROUND_COLOR_SET]);
15674   g_object_notify_by_pspec (G_OBJECT (self),
15675                             obj_props[PROP_BACKGROUND_COLOR]);
15676 }
15677
15678 /**
15679  * clutter_actor_get_background_color:
15680  * @self: a #ClutterActor
15681  * @color: (out caller-allocates): return location for a #ClutterColor
15682  *
15683  * Retrieves the color set using clutter_actor_set_background_color().
15684  *
15685  * Since: 1.10
15686  */
15687 void
15688 clutter_actor_get_background_color (ClutterActor *self,
15689                                     ClutterColor *color)
15690 {
15691   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15692   g_return_if_fail (color != NULL);
15693
15694   *color = self->priv->bg_color;
15695 }
15696
15697 /**
15698  * clutter_actor_get_previous_sibling:
15699  * @self: a #ClutterActor
15700  *
15701  * Retrieves the sibling of @self that comes before it in the list
15702  * of children of @self's parent.
15703  *
15704  * The returned pointer is only valid until the scene graph changes; it
15705  * is not safe to modify the list of children of @self while iterating
15706  * it.
15707  *
15708  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15709  *
15710  * Since: 1.10
15711  */
15712 ClutterActor *
15713 clutter_actor_get_previous_sibling (ClutterActor *self)
15714 {
15715   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15716
15717   return self->priv->prev_sibling;
15718 }
15719
15720 /**
15721  * clutter_actor_get_next_sibling:
15722  * @self: a #ClutterActor
15723  *
15724  * Retrieves the sibling of @self that comes after it in the list
15725  * of children of @self's parent.
15726  *
15727  * The returned pointer is only valid until the scene graph changes; it
15728  * is not safe to modify the list of children of @self while iterating
15729  * it.
15730  *
15731  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15732  *
15733  * Since: 1.10
15734  */
15735 ClutterActor *
15736 clutter_actor_get_next_sibling (ClutterActor *self)
15737 {
15738   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15739
15740   return self->priv->next_sibling;
15741 }
15742
15743 /**
15744  * clutter_actor_get_first_child:
15745  * @self: a #ClutterActor
15746  *
15747  * Retrieves the first child of @self.
15748  *
15749  * The returned pointer is only valid until the scene graph changes; it
15750  * is not safe to modify the list of children of @self while iterating
15751  * it.
15752  *
15753  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15754  *
15755  * Since: 1.10
15756  */
15757 ClutterActor *
15758 clutter_actor_get_first_child (ClutterActor *self)
15759 {
15760   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15761
15762   return self->priv->first_child;
15763 }
15764
15765 /**
15766  * clutter_actor_get_last_child:
15767  * @self: a #ClutterActor
15768  *
15769  * Retrieves the last child of @self.
15770  *
15771  * The returned pointer is only valid until the scene graph changes; it
15772  * is not safe to modify the list of children of @self while iterating
15773  * it.
15774  *
15775  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15776  *
15777  * Since: 1.10
15778  */
15779 ClutterActor *
15780 clutter_actor_get_last_child (ClutterActor *self)
15781 {
15782   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15783
15784   return self->priv->last_child;
15785 }
15786
15787 /* easy way to have properly named fields instead of the dummy ones
15788  * we use in the public structure
15789  */
15790 typedef struct _RealActorIter
15791 {
15792   ClutterActor *root;           /* dummy1 */
15793   ClutterActor *current;        /* dummy2 */
15794   gpointer padding_1;           /* dummy3 */
15795   gint age;                     /* dummy4 */
15796   gpointer padding_2;           /* dummy5 */
15797 } RealActorIter;
15798
15799 /**
15800  * clutter_actor_iter_init:
15801  * @iter: a #ClutterActorIter
15802  * @root: a #ClutterActor
15803  *
15804  * Initializes a #ClutterActorIter, which can then be used to iterate
15805  * efficiently over a section of the scene graph, and associates it
15806  * with @root.
15807  *
15808  * Modifying the scene graph section that contains @root will invalidate
15809  * the iterator.
15810  *
15811  * |[
15812  *   ClutterActorIter iter;
15813  *   ClutterActor *child;
15814  *
15815  *   clutter_actor_iter_init (&iter, container);
15816  *   while (clutter_actor_iter_next (&iter, &child))
15817  *     {
15818  *       /&ast; do something with child &ast;/
15819  *     }
15820  * ]|
15821  *
15822  * Since: 1.10
15823  */
15824 void
15825 clutter_actor_iter_init (ClutterActorIter *iter,
15826                          ClutterActor     *root)
15827 {
15828   RealActorIter *ri = (RealActorIter *) iter;
15829
15830   g_return_if_fail (iter != NULL);
15831   g_return_if_fail (CLUTTER_IS_ACTOR (root));
15832
15833   ri->root = root;
15834   ri->current = NULL;
15835   ri->age = root->priv->age;
15836 }
15837
15838 /**
15839  * clutter_actor_iter_next:
15840  * @iter: a #ClutterActorIter
15841  * @child: (out): return location for a #ClutterActor
15842  *
15843  * Advances the @iter and retrieves the next child of the root #ClutterActor
15844  * that was used to initialize the #ClutterActorIterator.
15845  *
15846  * If the iterator can advance, this function returns %TRUE and sets the
15847  * @child argument.
15848  *
15849  * If the iterator cannot advance, this function returns %FALSE, and
15850  * the contents of @child are undefined.
15851  *
15852  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15853  *
15854  * Since: 1.10
15855  */
15856 gboolean
15857 clutter_actor_iter_next (ClutterActorIter  *iter,
15858                          ClutterActor     **child)
15859 {
15860   RealActorIter *ri = (RealActorIter *) iter;
15861
15862   g_return_val_if_fail (iter != NULL, FALSE);
15863   g_return_val_if_fail (ri->root != NULL, FALSE);
15864 #ifndef G_DISABLE_ASSERT
15865   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15866 #endif
15867
15868   if (ri->current == NULL)
15869     ri->current = ri->root->priv->first_child;
15870   else
15871     ri->current = ri->current->priv->next_sibling;
15872
15873   if (child != NULL)
15874     *child = ri->current;
15875
15876   return ri->current != NULL;
15877 }
15878
15879 /**
15880  * clutter_actor_iter_prev:
15881  * @iter: a #ClutterActorIter
15882  * @child: (out): return location for a #ClutterActor
15883  *
15884  * Advances the @iter and retrieves the previous child of the root
15885  * #ClutterActor that was used to initialize the #ClutterActorIterator.
15886  *
15887  * If the iterator can advance, this function returns %TRUE and sets the
15888  * @child argument.
15889  *
15890  * If the iterator cannot advance, this function returns %FALSE, and
15891  * the contents of @child are undefined.
15892  *
15893  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15894  *
15895  * Since: 1.10
15896  */
15897 gboolean
15898 clutter_actor_iter_prev (ClutterActorIter  *iter,
15899                          ClutterActor     **child)
15900 {
15901   RealActorIter *ri = (RealActorIter *) iter;
15902
15903   g_return_val_if_fail (iter != NULL, FALSE);
15904   g_return_val_if_fail (ri->root != NULL, FALSE);
15905 #ifndef G_DISABLE_ASSERT
15906   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15907 #endif
15908
15909   if (ri->current == NULL)
15910     ri->current = ri->root->priv->last_child;
15911   else
15912     ri->current = ri->current->priv->prev_sibling;
15913
15914   if (child != NULL)
15915     *child = ri->current;
15916
15917   return ri->current != NULL;
15918 }
15919
15920 /**
15921  * clutter_actor_iter_remove:
15922  * @iter: a #ClutterActorIter
15923  *
15924  * Safely removes the #ClutterActor currently pointer to by the iterator
15925  * from its parent.
15926  *
15927  * This function can only be called after clutter_actor_iter_next() or
15928  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15929  * than once for the same actor.
15930  *
15931  * This function will call clutter_actor_remove_child() internally.
15932  *
15933  * Since: 1.10
15934  */
15935 void
15936 clutter_actor_iter_remove (ClutterActorIter *iter)
15937 {
15938   RealActorIter *ri = (RealActorIter *) iter;
15939   ClutterActor *cur;
15940
15941   g_return_if_fail (iter != NULL);
15942   g_return_if_fail (ri->root != NULL);
15943 #ifndef G_DISABLE_ASSERT
15944   g_return_if_fail (ri->age == ri->root->priv->age);
15945 #endif
15946   g_return_if_fail (ri->current != NULL);
15947
15948   cur = ri->current;
15949
15950   if (cur != NULL)
15951     {
15952       ri->current = cur->priv->prev_sibling;
15953
15954       clutter_actor_remove_child_internal (ri->root, cur,
15955                                            REMOVE_CHILD_DEFAULT_FLAGS);
15956
15957       ri->age += 1;
15958     }
15959 }
15960
15961 /**
15962  * clutter_actor_iter_destroy:
15963  * @iter: a #ClutterActorIter
15964  *
15965  * Safely destroys the #ClutterActor currently pointer to by the iterator
15966  * from its parent.
15967  *
15968  * This function can only be called after clutter_actor_iter_next() or
15969  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15970  * than once for the same actor.
15971  *
15972  * This function will call clutter_actor_destroy() internally.
15973  *
15974  * Since: 1.10
15975  */
15976 void
15977 clutter_actor_iter_destroy (ClutterActorIter *iter)
15978 {
15979   RealActorIter *ri = (RealActorIter *) iter;
15980   ClutterActor *cur;
15981
15982   g_return_if_fail (iter != NULL);
15983   g_return_if_fail (ri->root != NULL);
15984 #ifndef G_DISABLE_ASSERT
15985   g_return_if_fail (ri->age == ri->root->priv->age);
15986 #endif
15987   g_return_if_fail (ri->current != NULL);
15988
15989   cur = ri->current;
15990
15991   if (cur != NULL)
15992     {
15993       ri->current = cur->priv->prev_sibling;
15994
15995       clutter_actor_destroy (cur);
15996
15997       ri->age += 1;
15998     }
15999 }