Fix missing/redundant declarations
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: Base abstract class for all visual stage actors.
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-events">
119  *   <title>Handling events on an actor</title>
120  *   <para>A #ClutterActor can receive and handle input device events, for
121  *   instance pointer events and key events, as long as its
122  *   #ClutterActor:reactive property is set to %TRUE.</para>
123  *   <para>Once an actor has been determined to be the source of an event,
124  *   Clutter will traverse the scene graph from the top-level actor towards the
125  *   event source, emitting the #ClutterActor::captured-event signal on each
126  *   ancestor until it reaches the source; this phase is also called
127  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
128  *   stopped, the graph is walked backwards, from the source actor to the
129  *   top-level, and the #ClutterActor::event signal, along with other event
130  *   signals if needed, is emitted; this phase is also called <emphasis>the
131  *   bubble phase</emphasis>. At any point of the signal emission, signal
132  *   handlers can stop the propagation through the scene graph by returning
133  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
134  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
135  * </refsect2>
136  *
137  * <refsect2 id="ClutterActor-subclassing">
138  *   <title>Implementing an actor</title>
139  *   <para>Careful consideration should be given when deciding to implement
140  *   a #ClutterActor sub-class. It is generally recommended to implement a
141  *   sub-class of #ClutterActor only for actors that should be used as leaf
142  *   nodes of a scene graph.</para>
143  *   <para>If your actor should be painted in a custom way, you should
144  *   override the #ClutterActor::paint signal class handler. You can either
145  *   opt to chain up to the parent class implementation or decide to fully
146  *   override the default paint implementation; Clutter will set up the
147  *   transformations and clip regions prior to emitting the #ClutterActor::paint
148  *   signal.</para>
149  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
150  *   #ClutterActorClass.get_preferred_height() virtual functions it is
151  *   possible to change or provide the preferred size of an actor; similarly,
152  *   by overriding the #ClutterActorClass.allocate() virtual function it is
153  *   possible to control the layout of the children of an actor. Make sure to
154  *   always chain up to the parent implementation of the
155  *   #ClutterActorClass.allocate() virtual function.</para>
156  *   <para>In general, it is strongly encouraged to use delegation and
157  *   composition instead of direct subclassing.</para>
158  * </refsect2>
159  *
160  * <refsect2 id="ClutterActor-script">
161  *   <title>ClutterActor custom properties for #ClutterScript</title>
162  *   <para>#ClutterActor defines a custom "rotation" property which
163  *   allows a short-hand description of the rotations to be applied
164  *   to an actor.</para>
165  *   <para>The syntax of the "rotation" property is the following:</para>
166  *   <informalexample>
167  *     <programlisting>
168  * "rotation" : [
169  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
170  * ]
171  *     </programlisting>
172  *   </informalexample>
173  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
174  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
175  *   floating point value representing the rotation angle on the given axis,
176  *   in degrees.</para>
177  *   <para>The <emphasis>center</emphasis> array is optional, and if present
178  *   it must contain the center of rotation as described by two coordinates:
179  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
180  *   "z-axis".</para>
181  *   <para>#ClutterActor will also parse every positional and dimensional
182  *   property defined as a string through clutter_units_from_string(); you
183  *   should read the documentation for the #ClutterUnits parser format for
184  *   the valid units and syntax.</para>
185  * </refsect2>
186  *
187  * <refsect2 id="ClutterActor-animating">
188  *   <title>Custom animatable properties</title>
189  *   <para>#ClutterActor allows accessing properties of #ClutterAction
190  *   and #ClutterConstraint instances associated to an actor instance
191  *   for animation purposes.</para>
192  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
193  *   property it is necessary to set the #ClutterActorMeta:name property on the
194  *   given action or constraint.</para>
195  *   <para>The property can be accessed using the following syntax:</para>
196  *   <informalexample>
197  *     <programlisting>
198  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
199  *     </programlisting>
200  *   </informalexample>
201  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
202  *   <para>The <emphasis>section</emphasis> fragment can be one between
203  *   "actions", "constraints" and "effects".</para>
204  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
205  *   action or constraint, as specified by the #ClutterActorMeta:name
206  *   property.</para>
207  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
208  *   action or constraint property to be animated.</para>
209  *   <para>The example below animates a #ClutterBindConstraint applied to an
210  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
211  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
212  *   its initial state is fully transparent and overlapping the actor to
213  *   which is bound to. </para>
214  *   <informalexample><programlisting>
215  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
216  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
217  * clutter_actor_add_constraint (rect, constraint);
218  *
219  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
220  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
221  * clutter_actor_add_constraint (rect, constraint);
222  *
223  * clutter_actor_set_reactive (rect, TRUE);
224  * clutter_actor_set_opacity (rect, 0);
225  *
226  * g_signal_connect (rect, "button-press-event",
227  *                   G_CALLBACK (on_button_press),
228  *                   NULL);
229  *   </programlisting></informalexample>
230  *   <para>On button press, the rectangle "slides" from behind the actor to
231  *   which is bound to, using the #ClutterBindConstraint:offset property and
232  *   the #ClutterActor:opacity property.</para>
233  *   <informalexample><programlisting>
234  * float new_offset = clutter_actor_get_width (origin) + h_padding;
235  *
236  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
237  *                        "opacity", 255,
238  *                        "@constraints.bind-x.offset", new_offset,
239  *                        NULL);
240  *   </programlisting></informalexample>
241  * </refsect2>
242  */
243
244 /**
245  * CLUTTER_ACTOR_IS_MAPPED:
246  * @a: a #ClutterActor
247  *
248  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
249  *
250  * The mapped state is set when the actor is visible and all its parents up
251  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
252  *
253  * This check can be used to see if an actor is going to be painted, as only
254  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
255  *
256  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
257  * not be checked directly; instead, the recommended usage is to connect a
258  * handler on the #GObject::notify signal for the #ClutterActor:mapped
259  * property of #ClutterActor, and check the presence of
260  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
261  *
262  * It is also important to note that Clutter may delay the changes of
263  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
264  * limitations, or during the reparenting of an actor, to optimize
265  * unnecessary (and potentially expensive) state changes.
266  *
267  * Since: 0.2
268  */
269
270 /**
271  * CLUTTER_ACTOR_IS_REALIZED:
272  * @a: a #ClutterActor
273  *
274  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
275  *
276  * The realized state has an actor-dependant interpretation. If an
277  * actor wants to delay allocating resources until it is attached to a
278  * stage, it may use the realize state to do so. However it is
279  * perfectly acceptable for an actor to allocate Cogl resources before
280  * being realized because there is only one drawing context used by Clutter
281  * so any resources will work on any stage.  If an actor is mapped it
282  * must also be realized, but an actor can be realized and unmapped
283  * (this is so hiding an actor temporarily doesn't do an expensive
284  * unrealize/realize).
285  *
286  * To be realized an actor must be inside a stage, and all its parents
287  * must be realized.
288  *
289  * Since: 0.2
290  */
291
292 /**
293  * CLUTTER_ACTOR_IS_VISIBLE:
294  * @a: a #ClutterActor
295  *
296  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
297  * Equivalent to the ClutterActor::visible object property.
298  *
299  * Note that an actor is only painted onscreen if it's mapped, which
300  * means it's visible, and all its parents are visible, and one of the
301  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
302  *
303  * Since: 0.2
304  */
305
306 /**
307  * CLUTTER_ACTOR_IS_REACTIVE:
308  * @a: a #ClutterActor
309  *
310  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
311  *
312  * Only reactive actors will receive event-related signals.
313  *
314  * Since: 0.6
315  */
316
317 #ifdef HAVE_CONFIG_H
318 #include "config.h"
319 #endif
320
321 #include <math.h>
322
323 #include "cogl/cogl.h"
324
325 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
326 #define CLUTTER_ENABLE_EXPERIMENTAL_API
327
328 #include "clutter-actor-private.h"
329
330 #include "clutter-action.h"
331 #include "clutter-actor-meta-private.h"
332 #include "clutter-animatable.h"
333 #include "clutter-color-static.h"
334 #include "clutter-color.h"
335 #include "clutter-constraint.h"
336 #include "clutter-container.h"
337 #include "clutter-debug.h"
338 #include "clutter-effect-private.h"
339 #include "clutter-enum-types.h"
340 #include "clutter-fixed-layout.h"
341 #include "clutter-flatten-effect.h"
342 #include "clutter-interval.h"
343 #include "clutter-main.h"
344 #include "clutter-marshal.h"
345 #include "clutter-paint-volume-private.h"
346 #include "clutter-private.h"
347 #include "clutter-profile.h"
348 #include "clutter-scriptable.h"
349 #include "clutter-script-private.h"
350 #include "clutter-stage-private.h"
351 #include "clutter-units.h"
352
353 #include "deprecated/clutter-actor.h"
354 #include "deprecated/clutter-behaviour.h"
355 #include "deprecated/clutter-container.h"
356
357 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
358 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
359
360 /* Internal enum used to control mapped state update.  This is a hint
361  * which indicates when to do something other than just enforce
362  * invariants.
363  */
364 typedef enum {
365   MAP_STATE_CHECK,           /* just enforce invariants. */
366   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
367                               * used when about to unparent.
368                               */
369   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
370                               * used to set mapped on toplevels.
371                               */
372   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
373                               * used just before unmapping parent.
374                               */
375 } MapStateChange;
376
377 /* 3 entries should be a good compromise, few layout managers
378  * will ask for 3 different preferred size in each allocation cycle */
379 #define N_CACHED_SIZE_REQUESTS 3
380
381 struct _ClutterActorPrivate
382 {
383   /* request mode */
384   ClutterRequestMode request_mode;
385
386   /* our cached size requests for different width / height */
387   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
388   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
389
390   /* An age of 0 means the entry is not set */
391   guint cached_height_age;
392   guint cached_width_age;
393
394   /* the bounding box of the actor, relative to the parent's
395    * allocation
396    */
397   ClutterActorBox allocation;
398   ClutterAllocationFlags allocation_flags;
399
400   /* depth */
401   gfloat z;
402
403   /* clip, in actor coordinates */
404   cairo_rectangle_t clip;
405
406   /* the cached transformation matrix; see apply_transform() */
407   CoglMatrix transform;
408
409   guint8 opacity;
410   gint opacity_override;
411
412   ClutterOffscreenRedirect offscreen_redirect;
413
414   /* This is an internal effect used to implement the
415      offscreen-redirect property */
416   ClutterEffect *flatten_effect;
417
418   /* scene graph */
419   ClutterActor *parent;
420   ClutterActor *prev_sibling;
421   ClutterActor *next_sibling;
422   ClutterActor *first_child;
423   ClutterActor *last_child;
424
425   gint n_children;
426
427   /* tracks whenever the children of an actor are changed; the
428    * age is incremented by 1 whenever an actor is added or
429    * removed. the age is not incremented when the first or the
430    * last child pointers are changed, or when grandchildren of
431    * an actor are changed.
432    */
433   gint age;
434
435   gchar *name; /* a non-unique name, used for debugging */
436   guint32 id; /* unique id, used for backward compatibility */
437
438   gint32 pick_id; /* per-stage unique id, used for picking */
439
440   /* a back-pointer to the Pango context that we can use
441    * to create pre-configured PangoLayout
442    */
443   PangoContext *pango_context;
444
445   /* the text direction configured for this child - either by
446    * application code, or by the actor's parent
447    */
448   ClutterTextDirection text_direction;
449
450   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
451   gint internal_child;
452
453   /* meta classes */
454   ClutterMetaGroup *actions;
455   ClutterMetaGroup *constraints;
456   ClutterMetaGroup *effects;
457
458   /* delegate object used to allocate the children of this actor */
459   ClutterLayoutManager *layout_manager;
460
461   /* used when painting, to update the paint volume */
462   ClutterEffect *current_effect;
463
464   /* This is used to store an effect which needs to be redrawn. A
465      redraw can be queued to start from a particular effect. This is
466      used by parametrised effects that can cache an image of the
467      actor. If a parameter of the effect changes then it only needs to
468      redraw the cached image, not the actual actor. The pointer is
469      only valid if is_dirty == TRUE. If the pointer is NULL then the
470      whole actor is dirty. */
471   ClutterEffect *effect_to_redraw;
472
473   /* This is used when painting effects to implement the
474      clutter_actor_continue_paint() function. It points to the node in
475      the list of effects that is next in the chain */
476   const GList *next_effect_to_paint;
477
478   ClutterPaintVolume paint_volume;
479
480   /* NB: This volume isn't relative to this actor, it is in eye
481    * coordinates so that it can remain valid after the actor changes.
482    */
483   ClutterPaintVolume last_paint_volume;
484
485   ClutterStageQueueRedrawEntry *queue_redraw_entry;
486
487   ClutterColor bg_color;
488
489   /* bitfields */
490
491   /* fixed position and sizes */
492   guint position_set                : 1;
493   guint min_width_set               : 1;
494   guint min_height_set              : 1;
495   guint natural_width_set           : 1;
496   guint natural_height_set          : 1;
497   /* cached request is invalid (implies allocation is too) */
498   guint needs_width_request         : 1;
499   /* cached request is invalid (implies allocation is too) */
500   guint needs_height_request        : 1;
501   /* cached allocation is invalid (request has changed, probably) */
502   guint needs_allocation            : 1;
503   guint show_on_set_parent          : 1;
504   guint has_clip                    : 1;
505   guint clip_to_allocation          : 1;
506   guint enable_model_view_transform : 1;
507   guint enable_paint_unmapped       : 1;
508   guint has_pointer                 : 1;
509   guint propagated_one_redraw       : 1;
510   guint paint_volume_valid          : 1;
511   guint last_paint_volume_valid     : 1;
512   guint in_clone_paint              : 1;
513   guint transform_valid             : 1;
514   /* This is TRUE if anything has queued a redraw since we were last
515      painted. In this case effect_to_redraw will point to an effect
516      the redraw was queued from or it will be NULL if the redraw was
517      queued without an effect. */
518   guint is_dirty                    : 1;
519   guint bg_color_set                : 1;
520 };
521
522 enum
523 {
524   PROP_0,
525
526   PROP_NAME,
527
528   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
529    * when set they force a size request, when gotten they
530    * get the allocation if the allocation is valid, and the
531    * request otherwise
532    */
533   PROP_X,
534   PROP_Y,
535   PROP_WIDTH,
536   PROP_HEIGHT,
537
538   /* Then the rest of these size-related properties are the "actual"
539    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
540    */
541   PROP_FIXED_X,
542   PROP_FIXED_Y,
543
544   PROP_FIXED_POSITION_SET,
545
546   PROP_MIN_WIDTH,
547   PROP_MIN_WIDTH_SET,
548
549   PROP_MIN_HEIGHT,
550   PROP_MIN_HEIGHT_SET,
551
552   PROP_NATURAL_WIDTH,
553   PROP_NATURAL_WIDTH_SET,
554
555   PROP_NATURAL_HEIGHT,
556   PROP_NATURAL_HEIGHT_SET,
557
558   PROP_REQUEST_MODE,
559
560   /* Allocation properties are read-only */
561   PROP_ALLOCATION,
562
563   PROP_DEPTH,
564
565   PROP_CLIP,
566   PROP_HAS_CLIP,
567   PROP_CLIP_TO_ALLOCATION,
568
569   PROP_OPACITY,
570
571   PROP_OFFSCREEN_REDIRECT,
572
573   PROP_VISIBLE,
574   PROP_MAPPED,
575   PROP_REALIZED,
576   PROP_REACTIVE,
577
578   PROP_SCALE_X,
579   PROP_SCALE_Y,
580   PROP_SCALE_CENTER_X,
581   PROP_SCALE_CENTER_Y,
582   PROP_SCALE_GRAVITY,
583
584   PROP_ROTATION_ANGLE_X,
585   PROP_ROTATION_ANGLE_Y,
586   PROP_ROTATION_ANGLE_Z,
587   PROP_ROTATION_CENTER_X,
588   PROP_ROTATION_CENTER_Y,
589   PROP_ROTATION_CENTER_Z,
590   /* This property only makes sense for the z rotation because the
591      others would depend on the actor having a size along the
592      z-axis */
593   PROP_ROTATION_CENTER_Z_GRAVITY,
594
595   PROP_ANCHOR_X,
596   PROP_ANCHOR_Y,
597   PROP_ANCHOR_GRAVITY,
598
599   PROP_SHOW_ON_SET_PARENT,
600
601   PROP_TEXT_DIRECTION,
602   PROP_HAS_POINTER,
603
604   PROP_ACTIONS,
605   PROP_CONSTRAINTS,
606   PROP_EFFECT,
607
608   PROP_LAYOUT_MANAGER,
609
610   PROP_X_ALIGN,
611   PROP_Y_ALIGN,
612   PROP_MARGIN_TOP,
613   PROP_MARGIN_BOTTOM,
614   PROP_MARGIN_LEFT,
615   PROP_MARGIN_RIGHT,
616
617   PROP_BACKGROUND_COLOR,
618   PROP_BACKGROUND_COLOR_SET,
619
620   PROP_FIRST_CHILD,
621   PROP_LAST_CHILD,
622
623   PROP_LAST
624 };
625
626 static GParamSpec *obj_props[PROP_LAST];
627
628 enum
629 {
630   SHOW,
631   HIDE,
632   DESTROY,
633   PARENT_SET,
634   KEY_FOCUS_IN,
635   KEY_FOCUS_OUT,
636   PAINT,
637   PICK,
638   REALIZE,
639   UNREALIZE,
640   QUEUE_REDRAW,
641   QUEUE_RELAYOUT,
642   EVENT,
643   CAPTURED_EVENT,
644   BUTTON_PRESS_EVENT,
645   BUTTON_RELEASE_EVENT,
646   SCROLL_EVENT,
647   KEY_PRESS_EVENT,
648   KEY_RELEASE_EVENT,
649   MOTION_EVENT,
650   ENTER_EVENT,
651   LEAVE_EVENT,
652   ALLOCATION_CHANGED,
653
654   LAST_SIGNAL
655 };
656
657 static guint actor_signals[LAST_SIGNAL] = { 0, };
658
659 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
660 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
661 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
662 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
663
664 /* These setters are all static for now, maybe they should be in the
665  * public API, but they are perhaps obscure enough to leave only as
666  * properties
667  */
668 static void clutter_actor_set_min_width          (ClutterActor *self,
669                                                   gfloat        min_width);
670 static void clutter_actor_set_min_height         (ClutterActor *self,
671                                                   gfloat        min_height);
672 static void clutter_actor_set_natural_width      (ClutterActor *self,
673                                                   gfloat        natural_width);
674 static void clutter_actor_set_natural_height     (ClutterActor *self,
675                                                   gfloat        natural_height);
676 static void clutter_actor_set_min_width_set      (ClutterActor *self,
677                                                   gboolean      use_min_width);
678 static void clutter_actor_set_min_height_set     (ClutterActor *self,
679                                                   gboolean      use_min_height);
680 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
681                                                   gboolean  use_natural_width);
682 static void clutter_actor_set_natural_height_set (ClutterActor *self,
683                                                   gboolean  use_natural_height);
684 static void clutter_actor_update_map_state       (ClutterActor  *self,
685                                                   MapStateChange change);
686 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
687
688 /* Helper routines for managing anchor coords */
689 static void clutter_anchor_coord_get_units (ClutterActor      *self,
690                                             const AnchorCoord *coord,
691                                             gfloat            *x,
692                                             gfloat            *y,
693                                             gfloat            *z);
694 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
695                                             gfloat             x,
696                                             gfloat             y,
697                                             gfloat             z);
698
699 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
700 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
701                                                         ClutterGravity     gravity);
702
703 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
704
705 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
706
707 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
708                                                                ClutterActor *ancestor,
709                                                                CoglMatrix *matrix);
710
711 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
712
713 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
714
715 static void on_layout_manager_changed (ClutterLayoutManager *manager,
716                                        ClutterActor         *self);
717
718 /* Helper macro which translates by the anchor coord, applies the
719    given transformation and then translates back */
720 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
721   gfloat _tx, _ty, _tz;                                                \
722   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
723   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
724   { _transform; }                                                      \
725   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
726
727 static GQuark quark_shader_data = 0;
728 static GQuark quark_actor_layout_info = 0;
729 static GQuark quark_actor_transform_info = 0;
730
731 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
732                          clutter_actor,
733                          G_TYPE_INITIALLY_UNOWNED,
734                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
735                                                 clutter_container_iface_init)
736                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
737                                                 clutter_scriptable_iface_init)
738                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
739                                                 clutter_animatable_iface_init)
740                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
741                                                 atk_implementor_iface_init));
742
743 /*< private >
744  * clutter_actor_get_debug_name:
745  * @actor: a #ClutterActor
746  *
747  * Retrieves a printable name of @actor for debugging messages
748  *
749  * Return value: a string with a printable name
750  */
751 const gchar *
752 _clutter_actor_get_debug_name (ClutterActor *actor)
753 {
754   return actor->priv->name != NULL ? actor->priv->name
755                                    : G_OBJECT_TYPE_NAME (actor);
756 }
757
758 #ifdef CLUTTER_ENABLE_DEBUG
759 /* XXX - this is for debugging only, remove once working (or leave
760  * in only in some debug mode). Should leave it for a little while
761  * until we're confident in the new map/realize/visible handling.
762  */
763 static inline void
764 clutter_actor_verify_map_state (ClutterActor *self)
765 {
766   ClutterActorPrivate *priv = self->priv;
767
768   if (CLUTTER_ACTOR_IS_REALIZED (self))
769     {
770       /* all bets are off during reparent when we're potentially realized,
771        * but should not be according to invariants
772        */
773       if (!CLUTTER_ACTOR_IN_REPARENT (self))
774         {
775           if (priv->parent == NULL)
776             {
777               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
778                 {
779                 }
780               else
781                 g_warning ("Realized non-toplevel actor '%s' should "
782                            "have a parent",
783                            _clutter_actor_get_debug_name (self));
784             }
785           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
786             {
787               g_warning ("Realized actor %s has an unrealized parent %s",
788                          _clutter_actor_get_debug_name (self),
789                          _clutter_actor_get_debug_name (priv->parent));
790             }
791         }
792     }
793
794   if (CLUTTER_ACTOR_IS_MAPPED (self))
795     {
796       if (!CLUTTER_ACTOR_IS_REALIZED (self))
797         g_warning ("Actor '%s' is mapped but not realized",
798                    _clutter_actor_get_debug_name (self));
799
800       /* remaining bets are off during reparent when we're potentially
801        * mapped, but should not be according to invariants
802        */
803       if (!CLUTTER_ACTOR_IN_REPARENT (self))
804         {
805           if (priv->parent == NULL)
806             {
807               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
808                 {
809                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
810                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
811                     {
812                       g_warning ("Toplevel actor '%s' is mapped "
813                                  "but not visible",
814                                  _clutter_actor_get_debug_name (self));
815                     }
816                 }
817               else
818                 {
819                   g_warning ("Mapped actor '%s' should have a parent",
820                              _clutter_actor_get_debug_name (self));
821                 }
822             }
823           else
824             {
825               ClutterActor *iter = self;
826
827               /* check for the enable_paint_unmapped flag on the actor
828                * and parents; if the flag is enabled at any point of this
829                * branch of the scene graph then all the later checks
830                * become pointless
831                */
832               while (iter != NULL)
833                 {
834                   if (iter->priv->enable_paint_unmapped)
835                     return;
836
837                   iter = iter->priv->parent;
838                 }
839
840               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
841                 {
842                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
843                              "is not visible",
844                              _clutter_actor_get_debug_name (self),
845                              _clutter_actor_get_debug_name (priv->parent));
846                 }
847
848               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
849                 {
850                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
851                              "is not realized",
852                              _clutter_actor_get_debug_name (self),
853                              _clutter_actor_get_debug_name (priv->parent));
854                 }
855
856               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
857                 {
858                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
859                     g_warning ("Actor '%s' is mapped but its non-toplevel "
860                                "parent '%s' is not mapped",
861                                _clutter_actor_get_debug_name (self),
862                                _clutter_actor_get_debug_name (priv->parent));
863                 }
864             }
865         }
866     }
867 }
868
869 #endif /* CLUTTER_ENABLE_DEBUG */
870
871 static void
872 clutter_actor_set_mapped (ClutterActor *self,
873                           gboolean      mapped)
874 {
875   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
876     return;
877
878   if (mapped)
879     {
880       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
881       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
882     }
883   else
884     {
885       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
886       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
887     }
888 }
889
890 /* this function updates the mapped and realized states according to
891  * invariants, in the appropriate order.
892  */
893 static void
894 clutter_actor_update_map_state (ClutterActor  *self,
895                                 MapStateChange change)
896 {
897   gboolean was_mapped;
898
899   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
900
901   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
902     {
903       /* the mapped flag on top-level actors must be set by the
904        * per-backend implementation because it might be asynchronous.
905        *
906        * That is, the MAPPED flag on toplevels currently tracks the X
907        * server mapped-ness of the window, while the expected behavior
908        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
909        * This creates some weird complexity by breaking the invariant
910        * that if we're visible and all ancestors shown then we are
911        * also mapped - instead, we are mapped if all ancestors
912        * _possibly excepting_ the stage are mapped. The stage
913        * will map/unmap for example when it is minimized or
914        * moved to another workspace.
915        *
916        * So, the only invariant on the stage is that if visible it
917        * should be realized, and that it has to be visible to be
918        * mapped.
919        */
920       if (CLUTTER_ACTOR_IS_VISIBLE (self))
921         clutter_actor_realize (self);
922
923       switch (change)
924         {
925         case MAP_STATE_CHECK:
926           break;
927
928         case MAP_STATE_MAKE_MAPPED:
929           g_assert (!was_mapped);
930           clutter_actor_set_mapped (self, TRUE);
931           break;
932
933         case MAP_STATE_MAKE_UNMAPPED:
934           g_assert (was_mapped);
935           clutter_actor_set_mapped (self, FALSE);
936           break;
937
938         case MAP_STATE_MAKE_UNREALIZED:
939           /* we only use MAKE_UNREALIZED in unparent,
940            * and unparenting a stage isn't possible.
941            * If someone wants to just unrealize a stage
942            * then clutter_actor_unrealize() doesn't
943            * go through this codepath.
944            */
945           g_warning ("Trying to force unrealize stage is not allowed");
946           break;
947         }
948
949       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
950           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
951           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
952         {
953           g_warning ("Clutter toplevel of type '%s' is not visible, but "
954                      "it is somehow still mapped",
955                      _clutter_actor_get_debug_name (self));
956         }
957     }
958   else
959     {
960       ClutterActorPrivate *priv = self->priv;
961       ClutterActor *parent = priv->parent;
962       gboolean should_be_mapped;
963       gboolean may_be_realized;
964       gboolean must_be_realized;
965
966       should_be_mapped = FALSE;
967       may_be_realized = TRUE;
968       must_be_realized = FALSE;
969
970       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
971         {
972           may_be_realized = FALSE;
973         }
974       else
975         {
976           /* Maintain invariant that if parent is mapped, and we are
977            * visible, then we are mapped ...  unless parent is a
978            * stage, in which case we map regardless of parent's map
979            * state but do require stage to be visible and realized.
980            *
981            * If parent is realized, that does not force us to be
982            * realized; but if parent is unrealized, that does force
983            * us to be unrealized.
984            *
985            * The reason we don't force children to realize with
986            * parents is _clutter_actor_rerealize(); if we require that
987            * a realized parent means children are realized, then to
988            * unrealize an actor we would have to unrealize its
989            * parents, which would end up meaning unrealizing and
990            * hiding the entire stage. So we allow unrealizing a
991            * child (as long as that child is not mapped) while that
992            * child still has a realized parent.
993            *
994            * Also, if we unrealize from leaf nodes to root, and
995            * realize from root to leaf, the invariants are never
996            * violated if we allow children to be unrealized
997            * while parents are realized.
998            *
999            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1000            * to force us to unmap, even though parent is still
1001            * mapped. This is because we're unmapping from leaf nodes
1002            * up to root nodes.
1003            */
1004           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1005               change != MAP_STATE_MAKE_UNMAPPED)
1006             {
1007               gboolean parent_is_visible_realized_toplevel;
1008
1009               parent_is_visible_realized_toplevel =
1010                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1011                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1012                  CLUTTER_ACTOR_IS_REALIZED (parent));
1013
1014               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1015                   parent_is_visible_realized_toplevel)
1016                 {
1017                   must_be_realized = TRUE;
1018                   should_be_mapped = TRUE;
1019                 }
1020             }
1021
1022           /* if the actor has been set to be painted even if unmapped
1023            * then we should map it and check for realization as well;
1024            * this is an override for the branch of the scene graph
1025            * which begins with this node
1026            */
1027           if (priv->enable_paint_unmapped)
1028             {
1029               if (priv->parent == NULL)
1030                 g_warning ("Attempting to map an unparented actor '%s'",
1031                            _clutter_actor_get_debug_name (self));
1032
1033               should_be_mapped = TRUE;
1034               must_be_realized = TRUE;
1035             }
1036
1037           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1038             may_be_realized = FALSE;
1039         }
1040
1041       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1042         {
1043           if (parent == NULL)
1044             g_warning ("Attempting to map a child that does not "
1045                        "meet the necessary invariants: the actor '%s' "
1046                        "has no parent",
1047                        _clutter_actor_get_debug_name (self));
1048           else
1049             g_warning ("Attempting to map a child that does not "
1050                        "meet the necessary invariants: the actor '%s' "
1051                        "is parented to an unmapped actor '%s'",
1052                        _clutter_actor_get_debug_name (self),
1053                        _clutter_actor_get_debug_name (priv->parent));
1054         }
1055
1056       /* If in reparent, we temporarily suspend unmap and unrealize.
1057        *
1058        * We want to go in the order "realize, map" and "unmap, unrealize"
1059        */
1060
1061       /* Unmap */
1062       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1063         clutter_actor_set_mapped (self, FALSE);
1064
1065       /* Realize */
1066       if (must_be_realized)
1067         clutter_actor_realize (self);
1068
1069       /* if we must be realized then we may be, presumably */
1070       g_assert (!(must_be_realized && !may_be_realized));
1071
1072       /* Unrealize */
1073       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1074         clutter_actor_unrealize_not_hiding (self);
1075
1076       /* Map */
1077       if (should_be_mapped)
1078         {
1079           if (!must_be_realized)
1080             g_warning ("Somehow we think actor '%s' should be mapped but "
1081                        "not realized, which isn't allowed",
1082                        _clutter_actor_get_debug_name (self));
1083
1084           /* realization is allowed to fail (though I don't know what
1085            * an app is supposed to do about that - shouldn't it just
1086            * be a g_error? anyway, we have to avoid mapping if this
1087            * happens)
1088            */
1089           if (CLUTTER_ACTOR_IS_REALIZED (self))
1090             clutter_actor_set_mapped (self, TRUE);
1091         }
1092     }
1093
1094 #ifdef CLUTTER_ENABLE_DEBUG
1095   /* check all invariants were kept */
1096   clutter_actor_verify_map_state (self);
1097 #endif
1098 }
1099
1100 static void
1101 clutter_actor_real_map (ClutterActor *self)
1102 {
1103   ClutterActorPrivate *priv = self->priv;
1104   ClutterActor *stage, *iter;
1105
1106   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1107
1108   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1109                 _clutter_actor_get_debug_name (self));
1110
1111   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1112
1113   stage = _clutter_actor_get_stage_internal (self);
1114   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1115
1116   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1117                 priv->pick_id,
1118                 _clutter_actor_get_debug_name (self));
1119
1120   /* notify on parent mapped before potentially mapping
1121    * children, so apps see a top-down notification.
1122    */
1123   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1124
1125   for (iter = self->priv->first_child;
1126        iter != NULL;
1127        iter = iter->priv->next_sibling)
1128     {
1129       clutter_actor_map (iter);
1130     }
1131 }
1132
1133 /**
1134  * clutter_actor_map:
1135  * @self: A #ClutterActor
1136  *
1137  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1138  * and realizes its children if they are visible. Does nothing if the
1139  * actor is not visible.
1140  *
1141  * Calling this function is strongly disencouraged: the default
1142  * implementation of #ClutterActorClass.map() will map all the children
1143  * of an actor when mapping its parent.
1144  *
1145  * When overriding map, it is mandatory to chain up to the parent
1146  * implementation.
1147  *
1148  * Since: 1.0
1149  */
1150 void
1151 clutter_actor_map (ClutterActor *self)
1152 {
1153   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1154
1155   if (CLUTTER_ACTOR_IS_MAPPED (self))
1156     return;
1157
1158   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1159     return;
1160
1161   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1162 }
1163
1164 static void
1165 clutter_actor_real_unmap (ClutterActor *self)
1166 {
1167   ClutterActorPrivate *priv = self->priv;
1168   ClutterActor *iter;
1169
1170   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1171
1172   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1173                 _clutter_actor_get_debug_name (self));
1174
1175   for (iter = self->priv->first_child;
1176        iter != NULL;
1177        iter = iter->priv->next_sibling)
1178     {
1179       clutter_actor_unmap (iter);
1180     }
1181
1182   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1183
1184   /* clear the contents of the last paint volume, so that hiding + moving +
1185    * showing will not result in the wrong area being repainted
1186    */
1187   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1188   priv->last_paint_volume_valid = TRUE;
1189
1190   /* notify on parent mapped after potentially unmapping
1191    * children, so apps see a bottom-up notification.
1192    */
1193   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1194
1195   /* relinquish keyboard focus if we were unmapped while owning it */
1196   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1197     {
1198       ClutterStage *stage;
1199
1200       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1201
1202       if (stage != NULL)
1203         _clutter_stage_release_pick_id (stage, priv->pick_id);
1204
1205       priv->pick_id = -1;
1206
1207       if (stage != NULL &&
1208           clutter_stage_get_key_focus (stage) == self)
1209         {
1210           clutter_stage_set_key_focus (stage, NULL);
1211         }
1212     }
1213 }
1214
1215 /**
1216  * clutter_actor_unmap:
1217  * @self: A #ClutterActor
1218  *
1219  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1220  * unmaps its children if they were mapped.
1221  *
1222  * Calling this function is not encouraged: the default #ClutterActor
1223  * implementation of #ClutterActorClass.unmap() will also unmap any
1224  * eventual children by default when their parent is unmapped.
1225  *
1226  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1227  * chain up to the parent implementation.
1228  *
1229  * <note>It is important to note that the implementation of the
1230  * #ClutterActorClass.unmap() virtual function may be called after
1231  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1232  * implementation, but it is guaranteed to be called before the
1233  * #GObjectClass.finalize() implementation.</note>
1234  *
1235  * Since: 1.0
1236  */
1237 void
1238 clutter_actor_unmap (ClutterActor *self)
1239 {
1240   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1241
1242   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1243     return;
1244
1245   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1246 }
1247
1248 static void
1249 clutter_actor_real_show (ClutterActor *self)
1250 {
1251   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1252     {
1253       ClutterActorPrivate *priv = self->priv;
1254
1255       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1256
1257       /* we notify on the "visible" flag in the clutter_actor_show()
1258        * wrapper so the entire show signal emission completes first
1259        * (?)
1260        */
1261       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1262
1263       /* we queue a relayout unless the actor is inside a
1264        * container that explicitly told us not to
1265        */
1266       if (priv->parent != NULL &&
1267           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1268         {
1269           /* While an actor is hidden the parent may not have
1270            * allocated/requested so we need to start from scratch
1271            * and avoid the short-circuiting in
1272            * clutter_actor_queue_relayout().
1273            */
1274           priv->needs_width_request  = FALSE;
1275           priv->needs_height_request = FALSE;
1276           priv->needs_allocation     = FALSE;
1277           clutter_actor_queue_relayout (self);
1278         }
1279     }
1280 }
1281
1282 static inline void
1283 set_show_on_set_parent (ClutterActor *self,
1284                         gboolean      set_show)
1285 {
1286   ClutterActorPrivate *priv = self->priv;
1287
1288   set_show = !!set_show;
1289
1290   if (priv->show_on_set_parent == set_show)
1291     return;
1292
1293   if (priv->parent == NULL)
1294     {
1295       priv->show_on_set_parent = set_show;
1296       g_object_notify_by_pspec (G_OBJECT (self),
1297                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1298     }
1299 }
1300
1301 /**
1302  * clutter_actor_show:
1303  * @self: A #ClutterActor
1304  *
1305  * Flags an actor to be displayed. An actor that isn't shown will not
1306  * be rendered on the stage.
1307  *
1308  * Actors are visible by default.
1309  *
1310  * If this function is called on an actor without a parent, the
1311  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1312  * effect.
1313  */
1314 void
1315 clutter_actor_show (ClutterActor *self)
1316 {
1317   ClutterActorPrivate *priv;
1318
1319   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1320
1321   /* simple optimization */
1322   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1323     {
1324       /* we still need to set the :show-on-set-parent property, in
1325        * case show() is called on an unparented actor
1326        */
1327       set_show_on_set_parent (self, TRUE);
1328       return;
1329     }
1330
1331 #ifdef CLUTTER_ENABLE_DEBUG
1332   clutter_actor_verify_map_state (self);
1333 #endif
1334
1335   priv = self->priv;
1336
1337   g_object_freeze_notify (G_OBJECT (self));
1338
1339   set_show_on_set_parent (self, TRUE);
1340
1341   g_signal_emit (self, actor_signals[SHOW], 0);
1342   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1343
1344   if (priv->parent != NULL)
1345     clutter_actor_queue_redraw (priv->parent);
1346
1347   g_object_thaw_notify (G_OBJECT (self));
1348 }
1349
1350 /**
1351  * clutter_actor_show_all:
1352  * @self: a #ClutterActor
1353  *
1354  * Calls clutter_actor_show() on all children of an actor (if any).
1355  *
1356  * Since: 0.2
1357  *
1358  * Deprecated: 1.10: Actors are visible by default
1359  */
1360 void
1361 clutter_actor_show_all (ClutterActor *self)
1362 {
1363   ClutterActorClass *klass;
1364
1365   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1366
1367   klass = CLUTTER_ACTOR_GET_CLASS (self);
1368   if (klass->show_all)
1369     klass->show_all (self);
1370 }
1371
1372 static void
1373 clutter_actor_real_hide (ClutterActor *self)
1374 {
1375   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1376     {
1377       ClutterActorPrivate *priv = self->priv;
1378
1379       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1380
1381       /* we notify on the "visible" flag in the clutter_actor_hide()
1382        * wrapper so the entire hide signal emission completes first
1383        * (?)
1384        */
1385       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1386
1387       /* we queue a relayout unless the actor is inside a
1388        * container that explicitly told us not to
1389        */
1390       if (priv->parent != NULL &&
1391           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1392         clutter_actor_queue_relayout (priv->parent);
1393     }
1394 }
1395
1396 /**
1397  * clutter_actor_hide:
1398  * @self: A #ClutterActor
1399  *
1400  * Flags an actor to be hidden. A hidden actor will not be
1401  * rendered on the stage.
1402  *
1403  * Actors are visible by default.
1404  *
1405  * If this function is called on an actor without a parent, the
1406  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1407  * as a side-effect.
1408  */
1409 void
1410 clutter_actor_hide (ClutterActor *self)
1411 {
1412   ClutterActorPrivate *priv;
1413
1414   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1415
1416   /* simple optimization */
1417   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1418     {
1419       /* we still need to set the :show-on-set-parent property, in
1420        * case hide() is called on an unparented actor
1421        */
1422       set_show_on_set_parent (self, FALSE);
1423       return;
1424     }
1425
1426 #ifdef CLUTTER_ENABLE_DEBUG
1427   clutter_actor_verify_map_state (self);
1428 #endif
1429
1430   priv = self->priv;
1431
1432   g_object_freeze_notify (G_OBJECT (self));
1433
1434   set_show_on_set_parent (self, FALSE);
1435
1436   g_signal_emit (self, actor_signals[HIDE], 0);
1437   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1438
1439   if (priv->parent != NULL)
1440     clutter_actor_queue_redraw (priv->parent);
1441
1442   g_object_thaw_notify (G_OBJECT (self));
1443 }
1444
1445 /**
1446  * clutter_actor_hide_all:
1447  * @self: a #ClutterActor
1448  *
1449  * Calls clutter_actor_hide() on all child actors (if any).
1450  *
1451  * Since: 0.2
1452  *
1453  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1454  *   prevent its children from being painted as well.
1455  */
1456 void
1457 clutter_actor_hide_all (ClutterActor *self)
1458 {
1459   ClutterActorClass *klass;
1460
1461   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1462
1463   klass = CLUTTER_ACTOR_GET_CLASS (self);
1464   if (klass->hide_all)
1465     klass->hide_all (self);
1466 }
1467
1468 /**
1469  * clutter_actor_realize:
1470  * @self: A #ClutterActor
1471  *
1472  * Realization informs the actor that it is attached to a stage. It
1473  * can use this to allocate resources if it wanted to delay allocation
1474  * until it would be rendered. However it is perfectly acceptable for
1475  * an actor to create resources before being realized because Clutter
1476  * only ever has a single rendering context so that actor is free to
1477  * be moved from one stage to another.
1478  *
1479  * This function does nothing if the actor is already realized.
1480  *
1481  * Because a realized actor must have realized parent actors, calling
1482  * clutter_actor_realize() will also realize all parents of the actor.
1483  *
1484  * This function does not realize child actors, except in the special
1485  * case that realizing the stage, when the stage is visible, will
1486  * suddenly map (and thus realize) the children of the stage.
1487  **/
1488 void
1489 clutter_actor_realize (ClutterActor *self)
1490 {
1491   ClutterActorPrivate *priv;
1492
1493   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1494
1495   priv = self->priv;
1496
1497 #ifdef CLUTTER_ENABLE_DEBUG
1498   clutter_actor_verify_map_state (self);
1499 #endif
1500
1501   if (CLUTTER_ACTOR_IS_REALIZED (self))
1502     return;
1503
1504   /* To be realized, our parent actors must be realized first.
1505    * This will only succeed if we're inside a toplevel.
1506    */
1507   if (priv->parent != NULL)
1508     clutter_actor_realize (priv->parent);
1509
1510   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1511     {
1512       /* toplevels can be realized at any time */
1513     }
1514   else
1515     {
1516       /* "Fail" the realization if parent is missing or unrealized;
1517        * this should really be a g_warning() not some kind of runtime
1518        * failure; how can an app possibly recover? Instead it's a bug
1519        * in the app and the app should get an explanatory warning so
1520        * someone can fix it. But for now it's too hard to fix this
1521        * because e.g. ClutterTexture needs reworking.
1522        */
1523       if (priv->parent == NULL ||
1524           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1525         return;
1526     }
1527
1528   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1529
1530   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1531   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1532
1533   g_signal_emit (self, actor_signals[REALIZE], 0);
1534
1535   /* Stage actor is allowed to unset the realized flag again in its
1536    * default signal handler, though that is a pathological situation.
1537    */
1538
1539   /* If realization "failed" we'll have to update child state. */
1540   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1541 }
1542
1543 static void
1544 clutter_actor_real_unrealize (ClutterActor *self)
1545 {
1546   /* we must be unmapped (implying our children are also unmapped) */
1547   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1548 }
1549
1550 /**
1551  * clutter_actor_unrealize:
1552  * @self: A #ClutterActor
1553  *
1554  * Unrealization informs the actor that it may be being destroyed or
1555  * moved to another stage. The actor may want to destroy any
1556  * underlying graphics resources at this point. However it is
1557  * perfectly acceptable for it to retain the resources until the actor
1558  * is destroyed because Clutter only ever uses a single rendering
1559  * context and all of the graphics resources are valid on any stage.
1560  *
1561  * Because mapped actors must be realized, actors may not be
1562  * unrealized if they are mapped. This function hides the actor to be
1563  * sure it isn't mapped, an application-visible side effect that you
1564  * may not be expecting.
1565  *
1566  * This function should not be called by application code.
1567  */
1568 void
1569 clutter_actor_unrealize (ClutterActor *self)
1570 {
1571   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1572   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1573
1574 /* This function should not really be in the public API, because
1575  * there isn't a good reason to call it. ClutterActor will already
1576  * unrealize things for you when it's important to do so.
1577  *
1578  * If you were using clutter_actor_unrealize() in a dispose
1579  * implementation, then don't, just chain up to ClutterActor's
1580  * dispose.
1581  *
1582  * If you were using clutter_actor_unrealize() to implement
1583  * unrealizing children of your container, then don't, ClutterActor
1584  * will already take care of that.
1585  *
1586  * If you were using clutter_actor_unrealize() to re-realize to
1587  * create your resources in a different way, then use
1588  * _clutter_actor_rerealize() (inside Clutter) or just call your
1589  * code that recreates your resources directly (outside Clutter).
1590  */
1591
1592 #ifdef CLUTTER_ENABLE_DEBUG
1593   clutter_actor_verify_map_state (self);
1594 #endif
1595
1596   clutter_actor_hide (self);
1597
1598   clutter_actor_unrealize_not_hiding (self);
1599 }
1600
1601 static ClutterActorTraverseVisitFlags
1602 unrealize_actor_before_children_cb (ClutterActor *self,
1603                                     int depth,
1604                                     void *user_data)
1605 {
1606   /* If an actor is already unrealized we know its children have also
1607    * already been unrealized... */
1608   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1609     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1610
1611   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1612
1613   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1614 }
1615
1616 static ClutterActorTraverseVisitFlags
1617 unrealize_actor_after_children_cb (ClutterActor *self,
1618                                    int depth,
1619                                    void *user_data)
1620 {
1621   /* We want to unset the realized flag only _after_
1622    * child actors are unrealized, to maintain invariants.
1623    */
1624   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1625   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1626   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1627 }
1628
1629 /*
1630  * clutter_actor_unrealize_not_hiding:
1631  * @self: A #ClutterActor
1632  *
1633  * Unrealization informs the actor that it may be being destroyed or
1634  * moved to another stage. The actor may want to destroy any
1635  * underlying graphics resources at this point. However it is
1636  * perfectly acceptable for it to retain the resources until the actor
1637  * is destroyed because Clutter only ever uses a single rendering
1638  * context and all of the graphics resources are valid on any stage.
1639  *
1640  * Because mapped actors must be realized, actors may not be
1641  * unrealized if they are mapped. You must hide the actor or one of
1642  * its parents before attempting to unrealize.
1643  *
1644  * This function is separate from clutter_actor_unrealize() because it
1645  * does not automatically hide the actor.
1646  * Actors need not be hidden to be unrealized, they just need to
1647  * be unmapped. In fact we don't want to mess up the application's
1648  * setting of the "visible" flag, so hiding is very undesirable.
1649  *
1650  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1651  * backward compatibility.
1652  */
1653 static void
1654 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1655 {
1656   _clutter_actor_traverse (self,
1657                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1658                            unrealize_actor_before_children_cb,
1659                            unrealize_actor_after_children_cb,
1660                            NULL);
1661 }
1662
1663 /*
1664  * _clutter_actor_rerealize:
1665  * @self: A #ClutterActor
1666  * @callback: Function to call while unrealized
1667  * @data: data for callback
1668  *
1669  * If an actor is already unrealized, this just calls the callback.
1670  *
1671  * If it is realized, it unrealizes temporarily, calls the callback,
1672  * and then re-realizes the actor.
1673  *
1674  * As a side effect, leaves all children of the actor unrealized if
1675  * the actor was realized but not showing.  This is because when we
1676  * unrealize the actor temporarily we must unrealize its children
1677  * (e.g. children of a stage can't be realized if stage window is
1678  * gone). And we aren't clever enough to save the realization state of
1679  * all children. In most cases this should not matter, because
1680  * the children will automatically realize when they next become mapped.
1681  */
1682 void
1683 _clutter_actor_rerealize (ClutterActor    *self,
1684                           ClutterCallback  callback,
1685                           void            *data)
1686 {
1687   gboolean was_mapped;
1688   gboolean was_showing;
1689   gboolean was_realized;
1690
1691   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1692
1693 #ifdef CLUTTER_ENABLE_DEBUG
1694   clutter_actor_verify_map_state (self);
1695 #endif
1696
1697   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1698   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1699   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1700
1701   /* Must be unmapped to unrealize. Note we only have to hide this
1702    * actor if it was mapped (if all parents were showing).  If actor
1703    * is merely visible (but not mapped), then that's fine, we can
1704    * leave it visible.
1705    */
1706   if (was_mapped)
1707     clutter_actor_hide (self);
1708
1709   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1710
1711   /* unrealize self and all children */
1712   clutter_actor_unrealize_not_hiding (self);
1713
1714   if (callback != NULL)
1715     {
1716       (* callback) (self, data);
1717     }
1718
1719   if (was_showing)
1720     clutter_actor_show (self); /* will realize only if mapping implies it */
1721   else if (was_realized)
1722     clutter_actor_realize (self); /* realize self and all parents */
1723 }
1724
1725 static void
1726 clutter_actor_real_pick (ClutterActor       *self,
1727                          const ClutterColor *color)
1728 {
1729   /* the default implementation is just to paint a rectangle
1730    * with the same size of the actor using the passed color
1731    */
1732   if (clutter_actor_should_pick_paint (self))
1733     {
1734       ClutterActorBox box = { 0, };
1735       float width, height;
1736
1737       clutter_actor_get_allocation_box (self, &box);
1738
1739       width = box.x2 - box.x1;
1740       height = box.y2 - box.y1;
1741
1742       cogl_set_source_color4ub (color->red,
1743                                 color->green,
1744                                 color->blue,
1745                                 color->alpha);
1746
1747       cogl_rectangle (0, 0, width, height);
1748     }
1749
1750   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1751    * with existing container classes that override the pick() virtual
1752    * and chain up to the default implementation - otherwise we'll end up
1753    * painting our children twice.
1754    *
1755    * this has to go away for 2.0; hopefully along the pick() itself.
1756    */
1757   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1758     {
1759       ClutterActor *iter;
1760
1761       for (iter = self->priv->first_child;
1762            iter != NULL;
1763            iter = iter->priv->next_sibling)
1764         clutter_actor_paint (iter);
1765     }
1766 }
1767
1768 /**
1769  * clutter_actor_should_pick_paint:
1770  * @self: A #ClutterActor
1771  *
1772  * Should be called inside the implementation of the
1773  * #ClutterActor::pick virtual function in order to check whether
1774  * the actor should paint itself in pick mode or not.
1775  *
1776  * This function should never be called directly by applications.
1777  *
1778  * Return value: %TRUE if the actor should paint its silhouette,
1779  *   %FALSE otherwise
1780  */
1781 gboolean
1782 clutter_actor_should_pick_paint (ClutterActor *self)
1783 {
1784   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1785
1786   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1787       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1788        CLUTTER_ACTOR_IS_REACTIVE (self)))
1789     return TRUE;
1790
1791   return FALSE;
1792 }
1793
1794 static void
1795 clutter_actor_real_get_preferred_width (ClutterActor *self,
1796                                         gfloat        for_height,
1797                                         gfloat       *min_width_p,
1798                                         gfloat       *natural_width_p)
1799 {
1800   ClutterActorPrivate *priv = self->priv;
1801
1802   if (priv->n_children != 0 &&
1803       priv->layout_manager != NULL)
1804     {
1805       ClutterContainer *container = CLUTTER_CONTAINER (self);
1806
1807       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1808                     "for the preferred width",
1809                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1810                     priv->layout_manager);
1811
1812       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1813                                                   container,
1814                                                   for_height,
1815                                                   min_width_p,
1816                                                   natural_width_p);
1817
1818       return;
1819     }
1820
1821   /* Default implementation is always 0x0, usually an actor
1822    * using this default is relying on someone to set the
1823    * request manually
1824    */
1825   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1826
1827   if (min_width_p)
1828     *min_width_p = 0;
1829
1830   if (natural_width_p)
1831     *natural_width_p = 0;
1832 }
1833
1834 static void
1835 clutter_actor_real_get_preferred_height (ClutterActor *self,
1836                                          gfloat        for_width,
1837                                          gfloat       *min_height_p,
1838                                          gfloat       *natural_height_p)
1839 {
1840   ClutterActorPrivate *priv = self->priv;
1841
1842   if (priv->n_children != 0 &&
1843       priv->layout_manager != NULL)
1844     {
1845       ClutterContainer *container = CLUTTER_CONTAINER (self);
1846
1847       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1848                     "for the preferred height",
1849                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1850                     priv->layout_manager);
1851
1852       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1853                                                    container,
1854                                                    for_width,
1855                                                    min_height_p,
1856                                                    natural_height_p);
1857
1858       return;
1859     }
1860   /* Default implementation is always 0x0, usually an actor
1861    * using this default is relying on someone to set the
1862    * request manually
1863    */
1864   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1865
1866   if (min_height_p)
1867     *min_height_p = 0;
1868
1869   if (natural_height_p)
1870     *natural_height_p = 0;
1871 }
1872
1873 static void
1874 clutter_actor_store_old_geometry (ClutterActor    *self,
1875                                   ClutterActorBox *box)
1876 {
1877   *box = self->priv->allocation;
1878 }
1879
1880 static inline void
1881 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1882                                           const ClutterActorBox *old)
1883 {
1884   ClutterActorPrivate *priv = self->priv;
1885   GObject *obj = G_OBJECT (self);
1886
1887   g_object_freeze_notify (obj);
1888
1889   /* to avoid excessive requisition or allocation cycles we
1890    * use the cached values.
1891    *
1892    * - if we don't have an allocation we assume that we need
1893    *   to notify anyway
1894    * - if we don't have a width or a height request we notify
1895    *   width and height
1896    * - if we have a valid allocation then we check the old
1897    *   bounding box with the current allocation and we notify
1898    *   the changes
1899    */
1900   if (priv->needs_allocation)
1901     {
1902       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1903       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1904       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1905       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1906     }
1907   else if (priv->needs_width_request || priv->needs_height_request)
1908     {
1909       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1910       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1911     }
1912   else
1913     {
1914       gfloat xu, yu;
1915       gfloat widthu, heightu;
1916
1917       xu = priv->allocation.x1;
1918       yu = priv->allocation.y1;
1919       widthu = priv->allocation.x2 - priv->allocation.x1;
1920       heightu = priv->allocation.y2 - priv->allocation.y1;
1921
1922       if (xu != old->x1)
1923         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1924
1925       if (yu != old->y1)
1926         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1927
1928       if (widthu != (old->x2 - old->x1))
1929         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1930
1931       if (heightu != (old->y2 - old->y1))
1932         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1933     }
1934
1935   g_object_thaw_notify (obj);
1936 }
1937
1938 /*< private >
1939  * clutter_actor_set_allocation_internal:
1940  * @self: a #ClutterActor
1941  * @box: a #ClutterActorBox
1942  * @flags: allocation flags
1943  *
1944  * Stores the allocation of @self.
1945  *
1946  * This function only performs basic storage and property notification.
1947  *
1948  * This function should be called by clutter_actor_set_allocation()
1949  * and by the default implementation of #ClutterActorClass.allocate().
1950  *
1951  * Return value: %TRUE if the allocation of the #ClutterActor has been
1952  *   changed, and %FALSE otherwise
1953  */
1954 static inline gboolean
1955 clutter_actor_set_allocation_internal (ClutterActor           *self,
1956                                        const ClutterActorBox  *box,
1957                                        ClutterAllocationFlags  flags)
1958 {
1959   ClutterActorPrivate *priv = self->priv;
1960   GObject *obj;
1961   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
1962   gboolean flags_changed;
1963   gboolean retval;
1964   ClutterActorBox old_alloc = { 0, };
1965
1966   obj = G_OBJECT (self);
1967
1968   g_object_freeze_notify (obj);
1969
1970   clutter_actor_store_old_geometry (self, &old_alloc);
1971
1972   x1_changed = priv->allocation.x1 != box->x1;
1973   y1_changed = priv->allocation.y1 != box->y1;
1974   x2_changed = priv->allocation.x2 != box->x2;
1975   y2_changed = priv->allocation.y2 != box->y2;
1976
1977   flags_changed = priv->allocation_flags != flags;
1978
1979   priv->allocation = *box;
1980   priv->allocation_flags = flags;
1981
1982   /* allocation is authoritative */
1983   priv->needs_width_request = FALSE;
1984   priv->needs_height_request = FALSE;
1985   priv->needs_allocation = FALSE;
1986
1987   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1988     {
1989       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
1990                     _clutter_actor_get_debug_name (self));
1991
1992       priv->transform_valid = FALSE;
1993
1994       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
1995
1996       retval = TRUE;
1997     }
1998   else
1999     retval = FALSE;
2000
2001   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2002
2003   g_object_thaw_notify (obj);
2004
2005   return retval;
2006 }
2007
2008 static void clutter_actor_real_allocate (ClutterActor           *self,
2009                                          const ClutterActorBox  *box,
2010                                          ClutterAllocationFlags  flags);
2011
2012 static inline void
2013 clutter_actor_maybe_layout_children (ClutterActor           *self,
2014                                      const ClutterActorBox  *allocation,
2015                                      ClutterAllocationFlags  flags)
2016 {
2017   ClutterActorPrivate *priv = self->priv;
2018
2019   /* this is going to be a bit hard to follow, so let's put an explanation
2020    * here.
2021    *
2022    * we want ClutterActor to have a default layout manager if the actor was
2023    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2024    *
2025    * we also want any subclass of ClutterActor that does not override the
2026    * ::allocate() virtual function to delegate to a layout manager.
2027    *
2028    * finally, we want to allow people subclassing ClutterActor and overriding
2029    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2030    *
2031    * on the other hand, we want existing actor subclasses overriding the
2032    * ::allocate() virtual function and chaining up to the parent's
2033    * implementation to continue working without allocating their children
2034    * twice, or without entering an allocation loop.
2035    *
2036    * for the first two points, we check if the class of the actor is
2037    * overridding the ::allocate() virtual function; if it isn't, then we
2038    * follow through with checking whether we have children and a layout
2039    * manager, and eventually calling clutter_layout_manager_allocate().
2040    *
2041    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2042    * allocation flags that we got passed, and if it is present, we continue
2043    * with the check above.
2044    *
2045    * if neither of these two checks yields a positive result, we just
2046    * assume that the ::allocate() virtual function that resulted in this
2047    * function being called will also allocate the children of the actor.
2048    */
2049
2050   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2051     goto check_layout;
2052
2053   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2054     goto check_layout;
2055
2056   return;
2057
2058 check_layout:
2059   if (priv->n_children != 0 &&
2060       priv->layout_manager != NULL)
2061     {
2062       ClutterContainer *container = CLUTTER_CONTAINER (self);
2063       ClutterAllocationFlags children_flags;
2064       ClutterActorBox children_box;
2065
2066       /* normalize the box passed to the layout manager */
2067       children_box.x1 = children_box.y1 = 0.f;
2068       children_box.x2 = (allocation->x2 - allocation->x1);
2069       children_box.y2 = (allocation->y2 - allocation->y1);
2070
2071       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2072        * the actor's children, since it refers only to the current
2073        * actor's allocation.
2074        */
2075       children_flags = flags;
2076       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2077
2078       CLUTTER_NOTE (LAYOUT,
2079                     "Allocating %d children of %s "
2080                     "at { %.2f, %.2f - %.2f x %.2f } "
2081                     "using %s",
2082                     priv->n_children,
2083                     _clutter_actor_get_debug_name (self),
2084                     allocation->x1,
2085                     allocation->y1,
2086                     (allocation->x2 - allocation->x1),
2087                     (allocation->y2 - allocation->y1),
2088                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2089
2090       clutter_layout_manager_allocate (priv->layout_manager,
2091                                        container,
2092                                        &children_box,
2093                                        children_flags);
2094     }
2095 }
2096
2097 static void
2098 clutter_actor_real_allocate (ClutterActor           *self,
2099                              const ClutterActorBox  *box,
2100                              ClutterAllocationFlags  flags)
2101 {
2102   ClutterActorPrivate *priv = self->priv;
2103   gboolean changed;
2104
2105   g_object_freeze_notify (G_OBJECT (self));
2106
2107   changed = clutter_actor_set_allocation_internal (self, box, flags);
2108
2109   /* we allocate our children before we notify changes in our geometry,
2110    * so that people connecting to properties will be able to get valid
2111    * data out of the sub-tree of the scene graph that has this actor at
2112    * the root.
2113    */
2114   clutter_actor_maybe_layout_children (self, box, flags);
2115
2116   if (changed)
2117     {
2118       ClutterActorBox signal_box = priv->allocation;
2119       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2120
2121       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2122                      &signal_box,
2123                      signal_flags);
2124     }
2125
2126   g_object_thaw_notify (G_OBJECT (self));
2127 }
2128
2129 static void
2130 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2131                                     ClutterActor *origin)
2132 {
2133   /* no point in queuing a redraw on a destroyed actor */
2134   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2135     return;
2136
2137   /* NB: We can't bail out early here if the actor is hidden in case
2138    * the actor bas been cloned. In this case the clone will need to
2139    * receive the signal so it can queue its own redraw.
2140    */
2141
2142   /* calls klass->queue_redraw in default handler */
2143   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2144 }
2145
2146 static void
2147 clutter_actor_real_queue_redraw (ClutterActor *self,
2148                                  ClutterActor *origin)
2149 {
2150   ClutterActor *parent;
2151
2152   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2153                 _clutter_actor_get_debug_name (self),
2154                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2155                                : "same actor");
2156
2157   /* no point in queuing a redraw on a destroyed actor */
2158   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2159     return;
2160
2161   /* If the queue redraw is coming from a child then the actor has
2162      become dirty and any queued effect is no longer valid */
2163   if (self != origin)
2164     {
2165       self->priv->is_dirty = TRUE;
2166       self->priv->effect_to_redraw = NULL;
2167     }
2168
2169   /* If the actor isn't visible, we still had to emit the signal
2170    * to allow for a ClutterClone, but the appearance of the parent
2171    * won't change so we don't have to propagate up the hierarchy.
2172    */
2173   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2174     return;
2175
2176   /* Although we could determine here that a full stage redraw
2177    * has already been queued and immediately bail out, we actually
2178    * guarantee that we will propagate a queue-redraw signal to our
2179    * parent at least once so that it's possible to implement a
2180    * container that tracks which of its children have queued a
2181    * redraw.
2182    */
2183   if (self->priv->propagated_one_redraw)
2184     {
2185       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2186       if (stage != NULL &&
2187           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2188         return;
2189     }
2190
2191   self->priv->propagated_one_redraw = TRUE;
2192
2193   /* notify parents, if they are all visible eventually we'll
2194    * queue redraw on the stage, which queues the redraw idle.
2195    */
2196   parent = clutter_actor_get_parent (self);
2197   if (parent != NULL)
2198     {
2199       /* this will go up recursively */
2200       _clutter_actor_signal_queue_redraw (parent, origin);
2201     }
2202 }
2203
2204 static void
2205 clutter_actor_real_queue_relayout (ClutterActor *self)
2206 {
2207   ClutterActorPrivate *priv = self->priv;
2208
2209   /* no point in queueing a redraw on a destroyed actor */
2210   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2211     return;
2212
2213   priv->needs_width_request  = TRUE;
2214   priv->needs_height_request = TRUE;
2215   priv->needs_allocation     = TRUE;
2216
2217   /* reset the cached size requests */
2218   memset (priv->width_requests, 0,
2219           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2220   memset (priv->height_requests, 0,
2221           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2222
2223   /* We need to go all the way up the hierarchy */
2224   if (priv->parent != NULL)
2225     _clutter_actor_queue_only_relayout (priv->parent);
2226 }
2227
2228 /**
2229  * clutter_actor_apply_relative_transform_to_point:
2230  * @self: A #ClutterActor
2231  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2232  *   default #ClutterStage
2233  * @point: A point as #ClutterVertex
2234  * @vertex: (out caller-allocates): The translated #ClutterVertex
2235  *
2236  * Transforms @point in coordinates relative to the actor into
2237  * ancestor-relative coordinates using the relevant transform
2238  * stack (i.e. scale, rotation, etc).
2239  *
2240  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2241  * this case, the coordinates returned will be the coordinates on
2242  * the stage before the projection is applied. This is different from
2243  * the behaviour of clutter_actor_apply_transform_to_point().
2244  *
2245  * Since: 0.6
2246  */
2247 void
2248 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2249                                                  ClutterActor        *ancestor,
2250                                                  const ClutterVertex *point,
2251                                                  ClutterVertex       *vertex)
2252 {
2253   gfloat w;
2254   CoglMatrix matrix;
2255
2256   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2257   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2258   g_return_if_fail (point != NULL);
2259   g_return_if_fail (vertex != NULL);
2260
2261   *vertex = *point;
2262   w = 1.0;
2263
2264   if (ancestor == NULL)
2265     ancestor = _clutter_actor_get_stage_internal (self);
2266
2267   if (ancestor == NULL)
2268     {
2269       *vertex = *point;
2270       return;
2271     }
2272
2273   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2274   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2275 }
2276
2277 static gboolean
2278 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2279                                          const ClutterVertex *vertices_in,
2280                                          ClutterVertex *vertices_out,
2281                                          int n_vertices)
2282 {
2283   ClutterActor *stage;
2284   CoglMatrix modelview;
2285   CoglMatrix projection;
2286   float viewport[4];
2287
2288   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2289
2290   stage = _clutter_actor_get_stage_internal (self);
2291
2292   /* We really can't do anything meaningful in this case so don't try
2293    * to do any transform */
2294   if (stage == NULL)
2295     return FALSE;
2296
2297   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2298    * that gets us to stage coordinates, we want to go all the way to eye
2299    * coordinates */
2300   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2301
2302   /* Fetch the projection and viewport */
2303   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2304   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2305                                &viewport[0],
2306                                &viewport[1],
2307                                &viewport[2],
2308                                &viewport[3]);
2309
2310   _clutter_util_fully_transform_vertices (&modelview,
2311                                           &projection,
2312                                           viewport,
2313                                           vertices_in,
2314                                           vertices_out,
2315                                           n_vertices);
2316
2317   return TRUE;
2318 }
2319
2320 /**
2321  * clutter_actor_apply_transform_to_point:
2322  * @self: A #ClutterActor
2323  * @point: A point as #ClutterVertex
2324  * @vertex: (out caller-allocates): The translated #ClutterVertex
2325  *
2326  * Transforms @point in coordinates relative to the actor
2327  * into screen-relative coordinates with the current actor
2328  * transformation (i.e. scale, rotation, etc)
2329  *
2330  * Since: 0.4
2331  **/
2332 void
2333 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2334                                         const ClutterVertex *point,
2335                                         ClutterVertex       *vertex)
2336 {
2337   g_return_if_fail (point != NULL);
2338   g_return_if_fail (vertex != NULL);
2339   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2340 }
2341
2342 /*
2343  * _clutter_actor_get_relative_transformation_matrix:
2344  * @self: The actor whose coordinate space you want to transform from.
2345  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2346  *            or %NULL if you want to transform all the way to eye coordinates.
2347  * @matrix: A #CoglMatrix to store the transformation
2348  *
2349  * This gets a transformation @matrix that will transform coordinates from the
2350  * coordinate space of @self into the coordinate space of @ancestor.
2351  *
2352  * For example if you need a matrix that can transform the local actor
2353  * coordinates of @self into stage coordinates you would pass the actor's stage
2354  * pointer as the @ancestor.
2355  *
2356  * If you pass %NULL then the transformation will take you all the way through
2357  * to eye coordinates. This can be useful if you want to extract the entire
2358  * modelview transform that Clutter applies before applying the projection
2359  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2360  * using cogl_set_modelview_matrix() for example then you would want a matrix
2361  * that transforms into eye coordinates.
2362  *
2363  * <note><para>This function explicitly initializes the given @matrix. If you just
2364  * want clutter to multiply a relative transformation with an existing matrix
2365  * you can use clutter_actor_apply_relative_transformation_matrix()
2366  * instead.</para></note>
2367  *
2368  */
2369 /* XXX: We should consider caching the stage relative modelview along with
2370  * the actor itself */
2371 static void
2372 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2373                                                    ClutterActor *ancestor,
2374                                                    CoglMatrix *matrix)
2375 {
2376   cogl_matrix_init_identity (matrix);
2377
2378   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2379 }
2380
2381 /* Project the given @box into stage window coordinates, writing the
2382  * transformed vertices to @verts[]. */
2383 static gboolean
2384 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2385                                           const ClutterActorBox *box,
2386                                           ClutterVertex          verts[])
2387 {
2388   ClutterVertex box_vertices[4];
2389
2390   box_vertices[0].x = box->x1;
2391   box_vertices[0].y = box->y1;
2392   box_vertices[0].z = 0;
2393   box_vertices[1].x = box->x2;
2394   box_vertices[1].y = box->y1;
2395   box_vertices[1].z = 0;
2396   box_vertices[2].x = box->x1;
2397   box_vertices[2].y = box->y2;
2398   box_vertices[2].z = 0;
2399   box_vertices[3].x = box->x2;
2400   box_vertices[3].y = box->y2;
2401   box_vertices[3].z = 0;
2402
2403   return
2404     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2405 }
2406
2407 /**
2408  * clutter_actor_get_allocation_vertices:
2409  * @self: A #ClutterActor
2410  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2411  *   against, or %NULL to use the #ClutterStage
2412  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2413  *   location for an array of 4 #ClutterVertex in which to store the result
2414  *
2415  * Calculates the transformed coordinates of the four corners of the
2416  * actor in the plane of @ancestor. The returned vertices relate to
2417  * the #ClutterActorBox coordinates as follows:
2418  * <itemizedlist>
2419  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2420  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2421  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2422  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2423  * </itemizedlist>
2424  *
2425  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2426  * this case, the coordinates returned will be the coordinates on
2427  * the stage before the projection is applied. This is different from
2428  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2429  *
2430  * Since: 0.6
2431  */
2432 void
2433 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2434                                        ClutterActor  *ancestor,
2435                                        ClutterVertex  verts[])
2436 {
2437   ClutterActorPrivate *priv;
2438   ClutterActorBox box;
2439   ClutterVertex vertices[4];
2440   CoglMatrix modelview;
2441
2442   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2443   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2444
2445   if (ancestor == NULL)
2446     ancestor = _clutter_actor_get_stage_internal (self);
2447
2448   /* Fallback to a NOP transform if the actor isn't parented under a
2449    * stage. */
2450   if (ancestor == NULL)
2451     ancestor = self;
2452
2453   priv = self->priv;
2454
2455   /* if the actor needs to be allocated we force a relayout, so that
2456    * we will have valid values to use in the transformations */
2457   if (priv->needs_allocation)
2458     {
2459       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2460       if (stage)
2461         _clutter_stage_maybe_relayout (stage);
2462       else
2463         {
2464           box.x1 = box.y1 = 0;
2465           /* The result isn't really meaningful in this case but at
2466            * least try to do something *vaguely* reasonable... */
2467           clutter_actor_get_size (self, &box.x2, &box.y2);
2468         }
2469     }
2470
2471   clutter_actor_get_allocation_box (self, &box);
2472
2473   vertices[0].x = box.x1;
2474   vertices[0].y = box.y1;
2475   vertices[0].z = 0;
2476   vertices[1].x = box.x2;
2477   vertices[1].y = box.y1;
2478   vertices[1].z = 0;
2479   vertices[2].x = box.x1;
2480   vertices[2].y = box.y2;
2481   vertices[2].z = 0;
2482   vertices[3].x = box.x2;
2483   vertices[3].y = box.y2;
2484   vertices[3].z = 0;
2485
2486   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2487                                                      &modelview);
2488
2489   cogl_matrix_transform_points (&modelview,
2490                                 3,
2491                                 sizeof (ClutterVertex),
2492                                 vertices,
2493                                 sizeof (ClutterVertex),
2494                                 vertices,
2495                                 4);
2496 }
2497
2498 /**
2499  * clutter_actor_get_abs_allocation_vertices:
2500  * @self: A #ClutterActor
2501  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2502  *   of 4 #ClutterVertex where to store the result.
2503  *
2504  * Calculates the transformed screen coordinates of the four corners of
2505  * the actor; the returned vertices relate to the #ClutterActorBox
2506  * coordinates  as follows:
2507  * <itemizedlist>
2508  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2509  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2510  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2511  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2512  * </itemizedlist>
2513  *
2514  * Since: 0.4
2515  */
2516 void
2517 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2518                                            ClutterVertex  verts[])
2519 {
2520   ClutterActorPrivate *priv;
2521   ClutterActorBox actor_space_allocation;
2522
2523   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2524
2525   priv = self->priv;
2526
2527   /* if the actor needs to be allocated we force a relayout, so that
2528    * the actor allocation box will be valid for
2529    * _clutter_actor_transform_and_project_box()
2530    */
2531   if (priv->needs_allocation)
2532     {
2533       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2534       /* There's nothing meaningful we can do now */
2535       if (!stage)
2536         return;
2537
2538       _clutter_stage_maybe_relayout (stage);
2539     }
2540
2541   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2542    * own coordinate space... */
2543   actor_space_allocation.x1 = 0;
2544   actor_space_allocation.y1 = 0;
2545   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2546   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2547   _clutter_actor_transform_and_project_box (self,
2548                                             &actor_space_allocation,
2549                                             verts);
2550 }
2551
2552 static void
2553 clutter_actor_real_apply_transform (ClutterActor *self,
2554                                     CoglMatrix   *matrix)
2555 {
2556   ClutterActorPrivate *priv = self->priv;
2557
2558   if (!priv->transform_valid)
2559     {
2560       CoglMatrix *transform = &priv->transform;
2561       const ClutterTransformInfo *info;
2562
2563       info = _clutter_actor_get_transform_info_or_defaults (self);
2564
2565       cogl_matrix_init_identity (transform);
2566
2567       cogl_matrix_translate (transform,
2568                              priv->allocation.x1,
2569                              priv->allocation.y1,
2570                              0.0);
2571
2572       if (priv->z)
2573         cogl_matrix_translate (transform, 0, 0, priv->z);
2574
2575       /*
2576        * because the rotation involves translations, we must scale
2577        * before applying the rotations (if we apply the scale after
2578        * the rotations, the translations included in the rotation are
2579        * not scaled and so the entire object will move on the screen
2580        * as a result of rotating it).
2581        */
2582       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2583         {
2584           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2585                                         &info->scale_center,
2586                                         cogl_matrix_scale (transform,
2587                                                            info->scale_x,
2588                                                            info->scale_y,
2589                                                            1.0));
2590         }
2591
2592       if (info->rz_angle)
2593         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2594                                       &info->rz_center,
2595                                       cogl_matrix_rotate (transform,
2596                                                           info->rz_angle,
2597                                                           0, 0, 1.0));
2598
2599       if (info->ry_angle)
2600         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2601                                       &info->ry_center,
2602                                       cogl_matrix_rotate (transform,
2603                                                           info->ry_angle,
2604                                                           0, 1.0, 0));
2605
2606       if (info->rx_angle)
2607         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2608                                       &info->rx_center,
2609                                       cogl_matrix_rotate (transform,
2610                                                           info->rx_angle,
2611                                                           1.0, 0, 0));
2612
2613       if (!clutter_anchor_coord_is_zero (&info->anchor))
2614         {
2615           gfloat x, y, z;
2616
2617           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2618           cogl_matrix_translate (transform, -x, -y, -z);
2619         }
2620
2621       priv->transform_valid = TRUE;
2622     }
2623
2624   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2625 }
2626
2627 /* Applies the transforms associated with this actor to the given
2628  * matrix. */
2629 void
2630 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2631                                           CoglMatrix *matrix)
2632 {
2633   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2634 }
2635
2636 /*
2637  * clutter_actor_apply_relative_transformation_matrix:
2638  * @self: The actor whose coordinate space you want to transform from.
2639  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2640  *            or %NULL if you want to transform all the way to eye coordinates.
2641  * @matrix: A #CoglMatrix to apply the transformation too.
2642  *
2643  * This multiplies a transform with @matrix that will transform coordinates
2644  * from the coordinate space of @self into the coordinate space of @ancestor.
2645  *
2646  * For example if you need a matrix that can transform the local actor
2647  * coordinates of @self into stage coordinates you would pass the actor's stage
2648  * pointer as the @ancestor.
2649  *
2650  * If you pass %NULL then the transformation will take you all the way through
2651  * to eye coordinates. This can be useful if you want to extract the entire
2652  * modelview transform that Clutter applies before applying the projection
2653  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2654  * using cogl_set_modelview_matrix() for example then you would want a matrix
2655  * that transforms into eye coordinates.
2656  *
2657  * <note>This function doesn't initialize the given @matrix, it simply
2658  * multiplies the requested transformation matrix with the existing contents of
2659  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2660  * before calling this function, or you can use
2661  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2662  */
2663 void
2664 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2665                                                      ClutterActor *ancestor,
2666                                                      CoglMatrix *matrix)
2667 {
2668   ClutterActor *parent;
2669
2670   /* Note we terminate before ever calling stage->apply_transform()
2671    * since that would conceptually be relative to the underlying
2672    * window OpenGL coordinates so we'd need a special @ancestor
2673    * value to represent the fake parent of the stage. */
2674   if (self == ancestor)
2675     return;
2676
2677   parent = clutter_actor_get_parent (self);
2678
2679   if (parent != NULL)
2680     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2681                                                          matrix);
2682
2683   _clutter_actor_apply_modelview_transform (self, matrix);
2684 }
2685
2686 static void
2687 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2688                                        ClutterPaintVolume *pv,
2689                                        const char *label,
2690                                        const CoglColor *color)
2691 {
2692   static CoglPipeline *outline = NULL;
2693   CoglPrimitive *prim;
2694   ClutterVertex line_ends[12 * 2];
2695   int n_vertices;
2696   CoglContext *ctx =
2697     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2698   /* XXX: at some point we'll query this from the stage but we can't
2699    * do that until the osx backend uses Cogl natively. */
2700   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2701
2702   if (outline == NULL)
2703     outline = cogl_pipeline_new (ctx);
2704
2705   _clutter_paint_volume_complete (pv);
2706
2707   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2708
2709   /* Front face */
2710   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2711   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2712   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2713   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2714
2715   if (!pv->is_2d)
2716     {
2717       /* Back face */
2718       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2719       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2720       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2721       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2722
2723       /* Lines connecting front face to back face */
2724       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2725       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2726       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2727       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2728     }
2729
2730   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2731                                 n_vertices,
2732                                 (CoglVertexP3 *)line_ends);
2733
2734   cogl_pipeline_set_color (outline, color);
2735   cogl_framebuffer_draw_primitive (fb, outline, prim);
2736   cogl_object_unref (prim);
2737
2738   if (label)
2739     {
2740       PangoLayout *layout;
2741       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2742       pango_layout_set_text (layout, label, -1);
2743       cogl_pango_render_layout (layout,
2744                                 pv->vertices[0].x,
2745                                 pv->vertices[0].y,
2746                                 color,
2747                                 0);
2748       g_object_unref (layout);
2749     }
2750 }
2751
2752 static void
2753 _clutter_actor_draw_paint_volume (ClutterActor *self)
2754 {
2755   ClutterPaintVolume *pv;
2756   CoglColor color;
2757
2758   pv = _clutter_actor_get_paint_volume_mutable (self);
2759   if (!pv)
2760     {
2761       gfloat width, height;
2762       ClutterPaintVolume fake_pv;
2763
2764       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2765       _clutter_paint_volume_init_static (&fake_pv, stage);
2766
2767       clutter_actor_get_size (self, &width, &height);
2768       clutter_paint_volume_set_width (&fake_pv, width);
2769       clutter_paint_volume_set_height (&fake_pv, height);
2770
2771       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2772       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2773                                              _clutter_actor_get_debug_name (self),
2774                                              &color);
2775
2776       clutter_paint_volume_free (&fake_pv);
2777     }
2778   else
2779     {
2780       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2781       _clutter_actor_draw_paint_volume_full (self, pv,
2782                                              _clutter_actor_get_debug_name (self),
2783                                              &color);
2784     }
2785 }
2786
2787 static void
2788 _clutter_actor_paint_cull_result (ClutterActor *self,
2789                                   gboolean success,
2790                                   ClutterCullResult result)
2791 {
2792   ClutterPaintVolume *pv;
2793   CoglColor color;
2794
2795   if (success)
2796     {
2797       if (result == CLUTTER_CULL_RESULT_IN)
2798         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2799       else if (result == CLUTTER_CULL_RESULT_OUT)
2800         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2801       else
2802         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2803     }
2804   else
2805     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2806
2807   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2808     _clutter_actor_draw_paint_volume_full (self, pv,
2809                                            _clutter_actor_get_debug_name (self),
2810                                            &color);
2811   else
2812     {
2813       PangoLayout *layout;
2814       char *label =
2815         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2816       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2817       cogl_set_source_color (&color);
2818
2819       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2820       pango_layout_set_text (layout, label, -1);
2821       cogl_pango_render_layout (layout,
2822                                 0,
2823                                 0,
2824                                 &color,
2825                                 0);
2826       g_free (label);
2827       g_object_unref (layout);
2828     }
2829 }
2830
2831 static int clone_paint_level = 0;
2832
2833 void
2834 _clutter_actor_push_clone_paint (void)
2835 {
2836   clone_paint_level++;
2837 }
2838
2839 void
2840 _clutter_actor_pop_clone_paint (void)
2841 {
2842   clone_paint_level--;
2843 }
2844
2845 static gboolean
2846 in_clone_paint (void)
2847 {
2848   return clone_paint_level > 0;
2849 }
2850
2851 /* Returns TRUE if the actor can be ignored */
2852 /* FIXME: we should return a ClutterCullResult, and
2853  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2854  * means there's no point in trying to cull descendants of the current
2855  * node. */
2856 static gboolean
2857 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2858 {
2859   ClutterActorPrivate *priv = self->priv;
2860   ClutterActor *stage;
2861   const ClutterPlane *stage_clip;
2862
2863   if (!priv->last_paint_volume_valid)
2864     {
2865       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2866                     "->last_paint_volume_valid == FALSE",
2867                     _clutter_actor_get_debug_name (self));
2868       return FALSE;
2869     }
2870
2871   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2872     return FALSE;
2873
2874   stage = _clutter_actor_get_stage_internal (self);
2875   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2876   if (G_UNLIKELY (!stage_clip))
2877     {
2878       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2879                     "No stage clip set",
2880                     _clutter_actor_get_debug_name (self));
2881       return FALSE;
2882     }
2883
2884   if (cogl_get_draw_framebuffer () !=
2885       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2886     {
2887       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2888                     "Current framebuffer doesn't correspond to stage",
2889                     _clutter_actor_get_debug_name (self));
2890       return FALSE;
2891     }
2892
2893   *result_out =
2894     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2895   return TRUE;
2896 }
2897
2898 static void
2899 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2900 {
2901   ClutterActorPrivate *priv = self->priv;
2902   const ClutterPaintVolume *pv;
2903
2904   if (priv->last_paint_volume_valid)
2905     {
2906       clutter_paint_volume_free (&priv->last_paint_volume);
2907       priv->last_paint_volume_valid = FALSE;
2908     }
2909
2910   pv = clutter_actor_get_paint_volume (self);
2911   if (!pv)
2912     {
2913       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2914                     "Actor failed to report a paint volume",
2915                     _clutter_actor_get_debug_name (self));
2916       return;
2917     }
2918
2919   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2920
2921   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2922                                             NULL); /* eye coordinates */
2923
2924   priv->last_paint_volume_valid = TRUE;
2925 }
2926
2927 static inline gboolean
2928 actor_has_shader_data (ClutterActor *self)
2929 {
2930   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2931 }
2932
2933 guint32
2934 _clutter_actor_get_pick_id (ClutterActor *self)
2935 {
2936   if (self->priv->pick_id < 0)
2937     return 0;
2938
2939   return self->priv->pick_id;
2940 }
2941
2942 /* This is the same as clutter_actor_add_effect except that it doesn't
2943    queue a redraw and it doesn't notify on the effect property */
2944 static void
2945 _clutter_actor_add_effect_internal (ClutterActor  *self,
2946                                     ClutterEffect *effect)
2947 {
2948   ClutterActorPrivate *priv = self->priv;
2949
2950   if (priv->effects == NULL)
2951     {
2952       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
2953       priv->effects->actor = self;
2954     }
2955
2956   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2957 }
2958
2959 /* This is the same as clutter_actor_remove_effect except that it doesn't
2960    queue a redraw and it doesn't notify on the effect property */
2961 static void
2962 _clutter_actor_remove_effect_internal (ClutterActor  *self,
2963                                        ClutterEffect *effect)
2964 {
2965   ClutterActorPrivate *priv = self->priv;
2966
2967   if (priv->effects == NULL)
2968     return;
2969
2970   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2971 }
2972
2973 static gboolean
2974 needs_flatten_effect (ClutterActor *self)
2975 {
2976   ClutterActorPrivate *priv = self->priv;
2977
2978   if (G_UNLIKELY (clutter_paint_debug_flags &
2979                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
2980     return FALSE;
2981
2982   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
2983     return TRUE;
2984   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
2985     {
2986       if (clutter_actor_get_paint_opacity (self) < 255 &&
2987           clutter_actor_has_overlaps (self))
2988         return TRUE;
2989     }
2990
2991   return FALSE;
2992 }
2993
2994 static void
2995 add_or_remove_flatten_effect (ClutterActor *self)
2996 {
2997   ClutterActorPrivate *priv = self->priv;
2998
2999   /* Add or remove the flatten effect depending on the
3000      offscreen-redirect property. */
3001   if (needs_flatten_effect (self))
3002     {
3003       if (priv->flatten_effect == NULL)
3004         {
3005           ClutterActorMeta *actor_meta;
3006           gint priority;
3007
3008           priv->flatten_effect = _clutter_flatten_effect_new ();
3009           /* Keep a reference to the effect so that we can queue
3010              redraws from it */
3011           g_object_ref_sink (priv->flatten_effect);
3012
3013           /* Set the priority of the effect to high so that it will
3014              always be applied to the actor first. It uses an internal
3015              priority so that it won't be visible to applications */
3016           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3017           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3018           _clutter_actor_meta_set_priority (actor_meta, priority);
3019
3020           /* This will add the effect without queueing a redraw */
3021           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3022         }
3023     }
3024   else
3025     {
3026       if (priv->flatten_effect != NULL)
3027         {
3028           /* Destroy the effect so that it will lose its fbo cache of
3029              the actor */
3030           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3031           g_object_unref (priv->flatten_effect);
3032           priv->flatten_effect = NULL;
3033         }
3034     }
3035 }
3036
3037 static void
3038 clutter_actor_real_paint (ClutterActor *actor)
3039 {
3040   ClutterActorPrivate *priv = actor->priv;
3041   ClutterActor *iter;
3042
3043   /* paint the background color, if set */
3044   if (priv->bg_color_set)
3045     {
3046       float width, height;
3047       guint8 real_alpha;
3048
3049       clutter_actor_box_get_size (&priv->allocation, &width, &height);
3050
3051       real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3052                  * priv->bg_color.alpha
3053                  / 255;
3054
3055       cogl_set_source_color4ub (priv->bg_color.red,
3056                                 priv->bg_color.green,
3057                                 priv->bg_color.blue,
3058                                 real_alpha);
3059
3060       cogl_rectangle (0, 0, width, height);
3061     }
3062
3063   for (iter = priv->first_child;
3064        iter != NULL;
3065        iter = iter->priv->next_sibling)
3066     {
3067       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3068                     _clutter_actor_get_debug_name (iter),
3069                     _clutter_actor_get_debug_name (actor),
3070                     iter->priv->allocation.x1,
3071                     iter->priv->allocation.y1,
3072                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3073                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3074
3075       clutter_actor_paint (iter);
3076     }
3077 }
3078
3079 /**
3080  * clutter_actor_paint:
3081  * @self: A #ClutterActor
3082  *
3083  * Renders the actor to display.
3084  *
3085  * This function should not be called directly by applications.
3086  * Call clutter_actor_queue_redraw() to queue paints, instead.
3087  *
3088  * This function is context-aware, and will either cause a
3089  * regular paint or a pick paint.
3090  *
3091  * This function will emit the #ClutterActor::paint signal or
3092  * the #ClutterActor::pick signal, depending on the context.
3093  *
3094  * This function does not paint the actor if the actor is set to 0,
3095  * unless it is performing a pick paint.
3096  */
3097 void
3098 clutter_actor_paint (ClutterActor *self)
3099 {
3100   ClutterActorPrivate *priv;
3101   ClutterPickMode pick_mode;
3102   gboolean clip_set = FALSE;
3103   gboolean shader_applied = FALSE;
3104
3105   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3106                           "Actor real-paint counter",
3107                           "Increments each time any actor is painted",
3108                           0 /* no application private data */);
3109   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3110                           "Actor pick-paint counter",
3111                           "Increments each time any actor is painted "
3112                           "for picking",
3113                           0 /* no application private data */);
3114
3115   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3116
3117   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3118     return;
3119
3120   priv = self->priv;
3121
3122   pick_mode = _clutter_context_get_pick_mode ();
3123
3124   if (pick_mode == CLUTTER_PICK_NONE)
3125     priv->propagated_one_redraw = FALSE;
3126
3127   /* It's an important optimization that we consider painting of
3128    * actors with 0 opacity to be a NOP... */
3129   if (pick_mode == CLUTTER_PICK_NONE &&
3130       /* ignore top-levels, since they might be transparent */
3131       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3132       /* Use the override opacity if its been set */
3133       ((priv->opacity_override >= 0) ?
3134        priv->opacity_override : priv->opacity) == 0)
3135     return;
3136
3137   /* if we aren't paintable (not in a toplevel with all
3138    * parents paintable) then do nothing.
3139    */
3140   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3141     return;
3142
3143   /* mark that we are in the paint process */
3144   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3145
3146   cogl_push_matrix();
3147
3148   if (priv->enable_model_view_transform)
3149     {
3150       CoglMatrix matrix;
3151
3152       /* XXX: It could be better to cache the modelview with the actor
3153        * instead of progressively building up the transformations on
3154        * the matrix stack every time we paint. */
3155       cogl_get_modelview_matrix (&matrix);
3156       _clutter_actor_apply_modelview_transform (self, &matrix);
3157
3158 #ifdef CLUTTER_ENABLE_DEBUG
3159       /* Catch when out-of-band transforms have been made by actors not as part
3160        * of an apply_transform vfunc... */
3161       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3162         {
3163           CoglMatrix expected_matrix;
3164
3165           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3166                                                              &expected_matrix);
3167
3168           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3169             {
3170               GString *buf = g_string_sized_new (1024);
3171               ClutterActor *parent;
3172
3173               parent = self;
3174               while (parent != NULL)
3175                 {
3176                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3177
3178                   if (parent->priv->parent != NULL)
3179                     g_string_append (buf, "->");
3180
3181                   parent = parent->priv->parent;
3182                 }
3183
3184               g_warning ("Unexpected transform found when painting actor "
3185                          "\"%s\". This will be caused by one of the actor's "
3186                          "ancestors (%s) using the Cogl API directly to transform "
3187                          "children instead of using ::apply_transform().",
3188                          _clutter_actor_get_debug_name (self),
3189                          buf->str);
3190
3191               g_string_free (buf, TRUE);
3192             }
3193         }
3194 #endif /* CLUTTER_ENABLE_DEBUG */
3195
3196       cogl_set_modelview_matrix (&matrix);
3197     }
3198
3199   if (priv->has_clip)
3200     {
3201       cogl_clip_push_rectangle (priv->clip.x,
3202                                 priv->clip.y,
3203                                 priv->clip.x + priv->clip.width,
3204                                 priv->clip.y + priv->clip.height);
3205       clip_set = TRUE;
3206     }
3207   else if (priv->clip_to_allocation)
3208     {
3209       gfloat width, height;
3210
3211       width  = priv->allocation.x2 - priv->allocation.x1;
3212       height = priv->allocation.y2 - priv->allocation.y1;
3213
3214       cogl_clip_push_rectangle (0, 0, width, height);
3215       clip_set = TRUE;
3216     }
3217
3218   if (pick_mode == CLUTTER_PICK_NONE)
3219     {
3220       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3221
3222       /* We check whether we need to add the flatten effect before
3223          each paint so that we can avoid having a mechanism for
3224          applications to notify when the value of the
3225          has_overlaps virtual changes. */
3226       add_or_remove_flatten_effect (self);
3227     }
3228   else
3229     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3230
3231   /* We save the current paint volume so that the next time the
3232    * actor queues a redraw we can constrain the redraw to just
3233    * cover the union of the new bounding box and the old.
3234    *
3235    * We also fetch the current paint volume to perform culling so
3236    * we can avoid painting actors outside the current clip region.
3237    *
3238    * If we are painting inside a clone, we should neither update
3239    * the paint volume or use it to cull painting, since the paint
3240    * box represents the location of the source actor on the
3241    * screen.
3242    *
3243    * XXX: We are starting to do a lot of vertex transforms on
3244    * the CPU in a typical paint, so at some point we should
3245    * audit these and consider caching some things.
3246    *
3247    * NB: We don't perform culling while picking at this point because
3248    * clutter-stage.c doesn't setup the clipping planes appropriately.
3249    *
3250    * NB: We don't want to update the last-paint-volume during picking
3251    * because the last-paint-volume is used to determine the old screen
3252    * space location of an actor that has moved so we can know the
3253    * minimal region to redraw to clear an old view of the actor. If we
3254    * update this during picking then by the time we come around to
3255    * paint then the last-paint-volume would likely represent the new
3256    * actor position not the old.
3257    */
3258   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3259     {
3260       gboolean success;
3261       /* annoyingly gcc warns if uninitialized even though
3262        * the initialization is redundant :-( */
3263       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3264
3265       if (G_LIKELY ((clutter_paint_debug_flags &
3266                      (CLUTTER_DEBUG_DISABLE_CULLING |
3267                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3268                     (CLUTTER_DEBUG_DISABLE_CULLING |
3269                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3270         _clutter_actor_update_last_paint_volume (self);
3271
3272       success = cull_actor (self, &result);
3273
3274       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3275         _clutter_actor_paint_cull_result (self, success, result);
3276       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3277         goto done;
3278     }
3279
3280   if (priv->effects == NULL)
3281     {
3282       if (pick_mode == CLUTTER_PICK_NONE &&
3283           actor_has_shader_data (self))
3284         {
3285           _clutter_actor_shader_pre_paint (self, FALSE);
3286           shader_applied = TRUE;
3287         }
3288
3289       priv->next_effect_to_paint = NULL;
3290     }
3291   else
3292     priv->next_effect_to_paint =
3293       _clutter_meta_group_peek_metas (priv->effects);
3294
3295   clutter_actor_continue_paint (self);
3296
3297   if (shader_applied)
3298     _clutter_actor_shader_post_paint (self);
3299
3300   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3301                   pick_mode == CLUTTER_PICK_NONE))
3302     _clutter_actor_draw_paint_volume (self);
3303
3304 done:
3305   /* If we make it here then the actor has run through a complete
3306      paint run including all the effects so it's no longer dirty */
3307   if (pick_mode == CLUTTER_PICK_NONE)
3308     priv->is_dirty = FALSE;
3309
3310   if (clip_set)
3311     cogl_clip_pop();
3312
3313   cogl_pop_matrix();
3314
3315   /* paint sequence complete */
3316   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3317 }
3318
3319 /**
3320  * clutter_actor_continue_paint:
3321  * @self: A #ClutterActor
3322  *
3323  * Run the next stage of the paint sequence. This function should only
3324  * be called within the implementation of the ‘run’ virtual of a
3325  * #ClutterEffect. It will cause the run method of the next effect to
3326  * be applied, or it will paint the actual actor if the current effect
3327  * is the last effect in the chain.
3328  *
3329  * Since: 1.8
3330  */
3331 void
3332 clutter_actor_continue_paint (ClutterActor *self)
3333 {
3334   ClutterActorPrivate *priv;
3335
3336   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3337   /* This should only be called from with in the ‘run’ implementation
3338      of a ClutterEffect */
3339   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3340
3341   priv = self->priv;
3342
3343   /* Skip any effects that are disabled */
3344   while (priv->next_effect_to_paint &&
3345          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3346     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3347
3348   /* If this has come from the last effect then we'll just paint the
3349      actual actor */
3350   if (priv->next_effect_to_paint == NULL)
3351     {
3352       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3353         {
3354           g_signal_emit (self, actor_signals[PAINT], 0);
3355         }
3356       else
3357         {
3358           ClutterColor col = { 0, };
3359
3360           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3361
3362           /* Actor will then paint silhouette of itself in supplied
3363            * color.  See clutter_stage_get_actor_at_pos() for where
3364            * picking is enabled.
3365            */
3366           g_signal_emit (self, actor_signals[PICK], 0, &col);
3367         }
3368     }
3369   else
3370     {
3371       ClutterEffect *old_current_effect;
3372       ClutterEffectPaintFlags run_flags = 0;
3373
3374       /* Cache the current effect so that we can put it back before
3375          returning */
3376       old_current_effect = priv->current_effect;
3377
3378       priv->current_effect = priv->next_effect_to_paint->data;
3379       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3380
3381       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3382         {
3383           if (priv->is_dirty)
3384             {
3385               /* If there's an effect queued with this redraw then all
3386                  effects up to that one will be considered dirty. It
3387                  is expected the queued effect will paint the cached
3388                  image and not call clutter_actor_continue_paint again
3389                  (although it should work ok if it does) */
3390               if (priv->effect_to_redraw == NULL ||
3391                   priv->current_effect != priv->effect_to_redraw)
3392                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3393             }
3394
3395           _clutter_effect_paint (priv->current_effect, run_flags);
3396         }
3397       else
3398         {
3399           /* We can't determine when an actor has been modified since
3400              its last pick so lets just assume it has always been
3401              modified */
3402           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3403
3404           _clutter_effect_pick (priv->current_effect, run_flags);
3405         }
3406
3407       priv->current_effect = old_current_effect;
3408     }
3409 }
3410
3411 static ClutterActorTraverseVisitFlags
3412 invalidate_queue_redraw_entry (ClutterActor *self,
3413                                int           depth,
3414                                gpointer      user_data)
3415 {
3416   ClutterActorPrivate *priv = self->priv;
3417
3418   if (priv->queue_redraw_entry != NULL)
3419     {
3420       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3421       priv->queue_redraw_entry = NULL;
3422     }
3423
3424   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3425 }
3426
3427 static inline void
3428 remove_child (ClutterActor *self,
3429               ClutterActor *child)
3430 {
3431   ClutterActor *prev_sibling, *next_sibling;
3432
3433   prev_sibling = child->priv->prev_sibling;
3434   next_sibling = child->priv->next_sibling;
3435
3436   if (prev_sibling != NULL)
3437     prev_sibling->priv->next_sibling = next_sibling;
3438
3439   if (next_sibling != NULL)
3440     next_sibling->priv->prev_sibling = prev_sibling;
3441
3442   if (self->priv->first_child == child)
3443     self->priv->first_child = next_sibling;
3444
3445   if (self->priv->last_child == child)
3446     self->priv->last_child = prev_sibling;
3447
3448   child->priv->parent = NULL;
3449   child->priv->prev_sibling = NULL;
3450   child->priv->next_sibling = NULL;
3451 }
3452
3453 typedef enum {
3454   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3455   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3456   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3457   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3458   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3459   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3460
3461   /* default flags for public API */
3462   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3463                                     REMOVE_CHILD_EMIT_PARENT_SET |
3464                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3465                                     REMOVE_CHILD_CHECK_STATE |
3466                                     REMOVE_CHILD_FLUSH_QUEUE |
3467                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3468
3469   /* flags for legacy/deprecated API */
3470   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3471                                     REMOVE_CHILD_FLUSH_QUEUE |
3472                                     REMOVE_CHILD_EMIT_PARENT_SET |
3473                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3474 } ClutterActorRemoveChildFlags;
3475
3476 /*< private >
3477  * clutter_actor_remove_child_internal:
3478  * @self: a #ClutterActor
3479  * @child: the child of @self that has to be removed
3480  * @flags: control the removal operations
3481  *
3482  * Removes @child from the list of children of @self.
3483  */
3484 static void
3485 clutter_actor_remove_child_internal (ClutterActor                 *self,
3486                                      ClutterActor                 *child,
3487                                      ClutterActorRemoveChildFlags  flags)
3488 {
3489   ClutterActor *old_first, *old_last;
3490   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3491   gboolean flush_queue;
3492   gboolean notify_first_last;
3493   gboolean was_mapped;
3494
3495   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3496   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3497   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3498   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3499   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3500   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3501
3502   g_object_freeze_notify (G_OBJECT (self));
3503
3504   if (destroy_meta)
3505     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3506
3507   if (check_state)
3508     {
3509       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3510
3511       /* we need to unrealize *before* we set parent_actor to NULL,
3512        * because in an unrealize method actors are dissociating from the
3513        * stage, which means they need to be able to
3514        * clutter_actor_get_stage().
3515        *
3516        * yhis should unmap and unrealize, unless we're reparenting.
3517        */
3518       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3519     }
3520   else
3521     was_mapped = FALSE;
3522
3523   if (flush_queue)
3524     {
3525       /* We take this opportunity to invalidate any queue redraw entry
3526        * associated with the actor and descendants since we won't be able to
3527        * determine the appropriate stage after this.
3528        *
3529        * we do this after we updated the mapped state because actors might
3530        * end up queueing redraws inside their mapped/unmapped virtual
3531        * functions, and if we invalidate the redraw entry we could end up
3532        * with an inconsistent state and weird memory corruption. see
3533        * bugs:
3534        *
3535        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3536        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3537        */
3538       _clutter_actor_traverse (child,
3539                                0,
3540                                invalidate_queue_redraw_entry,
3541                                NULL,
3542                                NULL);
3543     }
3544
3545   old_first = self->priv->first_child;
3546   old_last = self->priv->last_child;
3547
3548   remove_child (self, child);
3549
3550   self->priv->n_children -= 1;
3551
3552   self->priv->age += 1;
3553
3554   /* clutter_actor_reparent() will emit ::parent-set for us */
3555   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3556     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3557
3558   /* if the child was mapped then we need to relayout ourselves to account
3559    * for the removed child
3560    */
3561   if (was_mapped)
3562     clutter_actor_queue_relayout (self);
3563
3564   /* we need to emit the signal before dropping the reference */
3565   if (emit_actor_removed)
3566     g_signal_emit_by_name (self, "actor-removed", child);
3567
3568   if (notify_first_last)
3569     {
3570       if (old_first != self->priv->first_child)
3571         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3572
3573       if (old_last != self->priv->last_child)
3574         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3575     }
3576
3577   g_object_thaw_notify (G_OBJECT (self));
3578
3579   /* remove the reference we acquired in clutter_actor_add_child() */
3580   g_object_unref (child);
3581 }
3582
3583 static const ClutterTransformInfo default_transform_info = {
3584   0.0, { 0, },          /* rotation-x */
3585   0.0, { 0, },          /* rotation-y */
3586   0.0, { 0, },          /* rotation-z */
3587
3588   1.0, 1.0, { 0, },     /* scale */
3589
3590   { 0, },               /* anchor */
3591 };
3592
3593 /*< private >
3594  * _clutter_actor_get_transform_info_or_defaults:
3595  * @self: a #ClutterActor
3596  *
3597  * Retrieves the ClutterTransformInfo structure associated to an actor.
3598  *
3599  * If the actor does not have a ClutterTransformInfo structure associated
3600  * to it, then the default structure will be returned.
3601  *
3602  * This function should only be used for getters.
3603  *
3604  * Return value: a const pointer to the ClutterTransformInfo structure
3605  */
3606 const ClutterTransformInfo *
3607 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3608 {
3609   ClutterTransformInfo *info;
3610
3611   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3612   if (info != NULL)
3613     return info;
3614
3615   return &default_transform_info;
3616 }
3617
3618 static void
3619 clutter_transform_info_free (gpointer data)
3620 {
3621   if (data != NULL)
3622     g_slice_free (ClutterTransformInfo, data);
3623 }
3624
3625 /*< private >
3626  * _clutter_actor_get_transform_info:
3627  * @self: a #ClutterActor
3628  *
3629  * Retrieves a pointer to the ClutterTransformInfo structure.
3630  *
3631  * If the actor does not have a ClutterTransformInfo associated to it, one
3632  * will be created and initialized to the default values.
3633  *
3634  * This function should be used for setters.
3635  *
3636  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3637  * instead.
3638  *
3639  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3640  *   structure
3641  */
3642 ClutterTransformInfo *
3643 _clutter_actor_get_transform_info (ClutterActor *self)
3644 {
3645   ClutterTransformInfo *info;
3646
3647   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3648   if (info == NULL)
3649     {
3650       info = g_slice_new (ClutterTransformInfo);
3651
3652       *info = default_transform_info;
3653
3654       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3655                                info,
3656                                clutter_transform_info_free);
3657     }
3658
3659   return info;
3660 }
3661
3662 /*< private >
3663  * clutter_actor_set_rotation_angle_internal:
3664  * @self: a #ClutterActor
3665  * @axis: the axis of the angle to change
3666  * @angle: the angle of rotation
3667  *
3668  * Sets the rotation angle on the given axis without affecting the
3669  * rotation center point.
3670  */
3671 static inline void
3672 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3673                                            ClutterRotateAxis  axis,
3674                                            gdouble            angle)
3675 {
3676   GObject *obj = G_OBJECT (self);
3677   ClutterTransformInfo *info;
3678
3679   info = _clutter_actor_get_transform_info (self);
3680
3681   g_object_freeze_notify (obj);
3682
3683   switch (axis)
3684     {
3685     case CLUTTER_X_AXIS:
3686       info->rx_angle = angle;
3687       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3688       break;
3689
3690     case CLUTTER_Y_AXIS:
3691       info->ry_angle = angle;
3692       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3693       break;
3694
3695     case CLUTTER_Z_AXIS:
3696       info->rz_angle = angle;
3697       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3698       break;
3699     }
3700
3701   self->priv->transform_valid = FALSE;
3702
3703   g_object_thaw_notify (obj);
3704
3705   clutter_actor_queue_redraw (self);
3706 }
3707
3708 /*< private >
3709  * clutter_actor_set_rotation_center_internal:
3710  * @self: a #ClutterActor
3711  * @axis: the axis of the center to change
3712  * @center: the coordinates of the rotation center
3713  *
3714  * Sets the rotation center on the given axis without affecting the
3715  * rotation angle.
3716  */
3717 static inline void
3718 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3719                                             ClutterRotateAxis    axis,
3720                                             const ClutterVertex *center)
3721 {
3722   GObject *obj = G_OBJECT (self);
3723   ClutterTransformInfo *info;
3724   ClutterVertex v = { 0, 0, 0 };
3725
3726   info = _clutter_actor_get_transform_info (self);
3727
3728   if (center != NULL)
3729     v = *center;
3730
3731   g_object_freeze_notify (obj);
3732
3733   switch (axis)
3734     {
3735     case CLUTTER_X_AXIS:
3736       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3737       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3738       break;
3739
3740     case CLUTTER_Y_AXIS:
3741       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3742       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3743       break;
3744
3745     case CLUTTER_Z_AXIS:
3746       /* if the previously set rotation center was fractional, then
3747        * setting explicit coordinates will have to notify the
3748        * :rotation-center-z-gravity property as well
3749        */
3750       if (info->rz_center.is_fractional)
3751         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3752
3753       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3754       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3755       break;
3756     }
3757
3758   self->priv->transform_valid = FALSE;
3759
3760   g_object_thaw_notify (obj);
3761
3762   clutter_actor_queue_redraw (self);
3763 }
3764
3765 static inline void
3766 clutter_actor_set_scale_factor (ClutterActor      *self,
3767                                 ClutterRotateAxis  axis,
3768                                 gdouble            factor)
3769 {
3770   GObject *obj = G_OBJECT (self);
3771   ClutterTransformInfo *info;
3772
3773   info = _clutter_actor_get_transform_info (self);
3774
3775   g_object_freeze_notify (obj);
3776
3777   switch (axis)
3778     {
3779     case CLUTTER_X_AXIS:
3780       info->scale_x = factor;
3781       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
3782       break;
3783
3784     case CLUTTER_Y_AXIS:
3785       info->scale_y = factor;
3786       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
3787       break;
3788
3789     default:
3790       g_assert_not_reached ();
3791     }
3792
3793   self->priv->transform_valid = FALSE;
3794
3795   clutter_actor_queue_redraw (self);
3796
3797   g_object_thaw_notify (obj);
3798 }
3799
3800 static inline void
3801 clutter_actor_set_scale_center (ClutterActor      *self,
3802                                 ClutterRotateAxis  axis,
3803                                 gfloat             coord)
3804 {
3805   GObject *obj = G_OBJECT (self);
3806   ClutterTransformInfo *info;
3807   gfloat center_x, center_y;
3808
3809   info = _clutter_actor_get_transform_info (self);
3810
3811   g_object_freeze_notify (obj);
3812
3813   /* get the current scale center coordinates */
3814   clutter_anchor_coord_get_units (self, &info->scale_center,
3815                                   &center_x,
3816                                   &center_y,
3817                                   NULL);
3818
3819   /* we need to notify this too, because setting explicit coordinates will
3820    * change the gravity as a side effect
3821    */
3822   if (info->scale_center.is_fractional)
3823     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3824
3825   switch (axis)
3826     {
3827     case CLUTTER_X_AXIS:
3828       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3829       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3830       break;
3831
3832     case CLUTTER_Y_AXIS:
3833       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3834       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3835       break;
3836
3837     default:
3838       g_assert_not_reached ();
3839     }
3840
3841   self->priv->transform_valid = FALSE;
3842
3843   clutter_actor_queue_redraw (self);
3844
3845   g_object_thaw_notify (obj);
3846 }
3847
3848 static inline void
3849 clutter_actor_set_anchor_coord (ClutterActor      *self,
3850                                 ClutterRotateAxis  axis,
3851                                 gfloat             coord)
3852 {
3853   GObject *obj = G_OBJECT (self);
3854   ClutterTransformInfo *info;
3855   gfloat anchor_x, anchor_y;
3856
3857   info = _clutter_actor_get_transform_info (self);
3858
3859   g_object_freeze_notify (obj);
3860
3861   clutter_anchor_coord_get_units (self, &info->anchor,
3862                                   &anchor_x,
3863                                   &anchor_y,
3864                                   NULL);
3865
3866   if (info->anchor.is_fractional)
3867     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
3868
3869   switch (axis)
3870     {
3871     case CLUTTER_X_AXIS:
3872       clutter_anchor_coord_set_units (&info->anchor,
3873                                       coord,
3874                                       anchor_y,
3875                                       0.0);
3876       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
3877       break;
3878
3879     case CLUTTER_Y_AXIS:
3880       clutter_anchor_coord_set_units (&info->anchor,
3881                                       anchor_x,
3882                                       coord,
3883                                       0.0);
3884       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
3885       break;
3886
3887     default:
3888       g_assert_not_reached ();
3889     }
3890
3891   self->priv->transform_valid = FALSE;
3892
3893   clutter_actor_queue_redraw (self);
3894
3895   g_object_thaw_notify (obj);
3896 }
3897
3898 static void
3899 clutter_actor_set_property (GObject      *object,
3900                             guint         prop_id,
3901                             const GValue *value,
3902                             GParamSpec   *pspec)
3903 {
3904   ClutterActor *actor = CLUTTER_ACTOR (object);
3905   ClutterActorPrivate *priv = actor->priv;
3906
3907   switch (prop_id)
3908     {
3909     case PROP_X:
3910       clutter_actor_set_x (actor, g_value_get_float (value));
3911       break;
3912
3913     case PROP_Y:
3914       clutter_actor_set_y (actor, g_value_get_float (value));
3915       break;
3916
3917     case PROP_WIDTH:
3918       clutter_actor_set_width (actor, g_value_get_float (value));
3919       break;
3920
3921     case PROP_HEIGHT:
3922       clutter_actor_set_height (actor, g_value_get_float (value));
3923       break;
3924
3925     case PROP_FIXED_X:
3926       clutter_actor_set_x (actor, g_value_get_float (value));
3927       break;
3928
3929     case PROP_FIXED_Y:
3930       clutter_actor_set_y (actor, g_value_get_float (value));
3931       break;
3932
3933     case PROP_FIXED_POSITION_SET:
3934       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
3935       break;
3936
3937     case PROP_MIN_WIDTH:
3938       clutter_actor_set_min_width (actor, g_value_get_float (value));
3939       break;
3940
3941     case PROP_MIN_HEIGHT:
3942       clutter_actor_set_min_height (actor, g_value_get_float (value));
3943       break;
3944
3945     case PROP_NATURAL_WIDTH:
3946       clutter_actor_set_natural_width (actor, g_value_get_float (value));
3947       break;
3948
3949     case PROP_NATURAL_HEIGHT:
3950       clutter_actor_set_natural_height (actor, g_value_get_float (value));
3951       break;
3952
3953     case PROP_MIN_WIDTH_SET:
3954       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
3955       break;
3956
3957     case PROP_MIN_HEIGHT_SET:
3958       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
3959       break;
3960
3961     case PROP_NATURAL_WIDTH_SET:
3962       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
3963       break;
3964
3965     case PROP_NATURAL_HEIGHT_SET:
3966       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
3967       break;
3968
3969     case PROP_REQUEST_MODE:
3970       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
3971       break;
3972
3973     case PROP_DEPTH:
3974       clutter_actor_set_depth (actor, g_value_get_float (value));
3975       break;
3976
3977     case PROP_OPACITY:
3978       clutter_actor_set_opacity (actor, g_value_get_uint (value));
3979       break;
3980
3981     case PROP_OFFSCREEN_REDIRECT:
3982       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
3983       break;
3984
3985     case PROP_NAME:
3986       clutter_actor_set_name (actor, g_value_get_string (value));
3987       break;
3988
3989     case PROP_VISIBLE:
3990       if (g_value_get_boolean (value) == TRUE)
3991         clutter_actor_show (actor);
3992       else
3993         clutter_actor_hide (actor);
3994       break;
3995
3996     case PROP_SCALE_X:
3997       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
3998                                       g_value_get_double (value));
3999       break;
4000
4001     case PROP_SCALE_Y:
4002       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4003                                       g_value_get_double (value));
4004       break;
4005
4006     case PROP_SCALE_CENTER_X:
4007       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4008                                       g_value_get_float (value));
4009       break;
4010
4011     case PROP_SCALE_CENTER_Y:
4012       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4013                                       g_value_get_float (value));
4014       break;
4015
4016     case PROP_SCALE_GRAVITY:
4017       {
4018         const ClutterTransformInfo *info;
4019         ClutterGravity gravity;
4020
4021         info = _clutter_actor_get_transform_info_or_defaults (actor);
4022         gravity = g_value_get_enum (value);
4023
4024         clutter_actor_set_scale_with_gravity (actor,
4025                                               info->scale_x,
4026                                               info->scale_y,
4027                                               gravity);
4028       }
4029       break;
4030
4031     case PROP_CLIP:
4032       {
4033         const ClutterGeometry *geom = g_value_get_boxed (value);
4034
4035         clutter_actor_set_clip (actor,
4036                                 geom->x, geom->y,
4037                                 geom->width, geom->height);
4038       }
4039       break;
4040
4041     case PROP_CLIP_TO_ALLOCATION:
4042       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4043       break;
4044
4045     case PROP_REACTIVE:
4046       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4047       break;
4048
4049     case PROP_ROTATION_ANGLE_X:
4050       clutter_actor_set_rotation_angle_internal (actor,
4051                                                  CLUTTER_X_AXIS,
4052                                                  g_value_get_double (value));
4053       break;
4054
4055     case PROP_ROTATION_ANGLE_Y:
4056       clutter_actor_set_rotation_angle_internal (actor,
4057                                                  CLUTTER_Y_AXIS,
4058                                                  g_value_get_double (value));
4059       break;
4060
4061     case PROP_ROTATION_ANGLE_Z:
4062       clutter_actor_set_rotation_angle_internal (actor,
4063                                                  CLUTTER_Z_AXIS,
4064                                                  g_value_get_double (value));
4065       break;
4066
4067     case PROP_ROTATION_CENTER_X:
4068       clutter_actor_set_rotation_center_internal (actor,
4069                                                   CLUTTER_X_AXIS,
4070                                                   g_value_get_boxed (value));
4071       break;
4072
4073     case PROP_ROTATION_CENTER_Y:
4074       clutter_actor_set_rotation_center_internal (actor,
4075                                                   CLUTTER_Y_AXIS,
4076                                                   g_value_get_boxed (value));
4077       break;
4078
4079     case PROP_ROTATION_CENTER_Z:
4080       clutter_actor_set_rotation_center_internal (actor,
4081                                                   CLUTTER_Z_AXIS,
4082                                                   g_value_get_boxed (value));
4083       break;
4084
4085     case PROP_ROTATION_CENTER_Z_GRAVITY:
4086       {
4087         const ClutterTransformInfo *info;
4088
4089         info = _clutter_actor_get_transform_info_or_defaults (actor);
4090         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4091                                                    g_value_get_enum (value));
4092       }
4093       break;
4094
4095     case PROP_ANCHOR_X:
4096       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4097                                       g_value_get_float (value));
4098       break;
4099
4100     case PROP_ANCHOR_Y:
4101       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4102                                       g_value_get_float (value));
4103       break;
4104
4105     case PROP_ANCHOR_GRAVITY:
4106       clutter_actor_set_anchor_point_from_gravity (actor,
4107                                                    g_value_get_enum (value));
4108       break;
4109
4110     case PROP_SHOW_ON_SET_PARENT:
4111       priv->show_on_set_parent = g_value_get_boolean (value);
4112       break;
4113
4114     case PROP_TEXT_DIRECTION:
4115       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4116       break;
4117
4118     case PROP_ACTIONS:
4119       clutter_actor_add_action (actor, g_value_get_object (value));
4120       break;
4121
4122     case PROP_CONSTRAINTS:
4123       clutter_actor_add_constraint (actor, g_value_get_object (value));
4124       break;
4125
4126     case PROP_EFFECT:
4127       clutter_actor_add_effect (actor, g_value_get_object (value));
4128       break;
4129
4130     case PROP_LAYOUT_MANAGER:
4131       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4132       break;
4133
4134     case PROP_X_ALIGN:
4135       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4136       break;
4137
4138     case PROP_Y_ALIGN:
4139       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4140       break;
4141
4142     case PROP_MARGIN_TOP:
4143       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4144       break;
4145
4146     case PROP_MARGIN_BOTTOM:
4147       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4148       break;
4149
4150     case PROP_MARGIN_LEFT:
4151       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4152       break;
4153
4154     case PROP_MARGIN_RIGHT:
4155       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4156       break;
4157
4158     case PROP_BACKGROUND_COLOR:
4159       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4160       break;
4161
4162     default:
4163       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4164       break;
4165     }
4166 }
4167
4168 static void
4169 clutter_actor_get_property (GObject    *object,
4170                             guint       prop_id,
4171                             GValue     *value,
4172                             GParamSpec *pspec)
4173 {
4174   ClutterActor *actor = CLUTTER_ACTOR (object);
4175   ClutterActorPrivate *priv = actor->priv;
4176
4177   switch (prop_id)
4178     {
4179     case PROP_X:
4180       g_value_set_float (value, clutter_actor_get_x (actor));
4181       break;
4182
4183     case PROP_Y:
4184       g_value_set_float (value, clutter_actor_get_y (actor));
4185       break;
4186
4187     case PROP_WIDTH:
4188       g_value_set_float (value, clutter_actor_get_width (actor));
4189       break;
4190
4191     case PROP_HEIGHT:
4192       g_value_set_float (value, clutter_actor_get_height (actor));
4193       break;
4194
4195     case PROP_FIXED_X:
4196       {
4197         const ClutterLayoutInfo *info;
4198
4199         info = _clutter_actor_get_layout_info_or_defaults (actor);
4200         g_value_set_float (value, info->fixed_x);
4201       }
4202       break;
4203
4204     case PROP_FIXED_Y:
4205       {
4206         const ClutterLayoutInfo *info;
4207
4208         info = _clutter_actor_get_layout_info_or_defaults (actor);
4209         g_value_set_float (value, info->fixed_y);
4210       }
4211       break;
4212
4213     case PROP_FIXED_POSITION_SET:
4214       g_value_set_boolean (value, priv->position_set);
4215       break;
4216
4217     case PROP_MIN_WIDTH:
4218       {
4219         const ClutterLayoutInfo *info;
4220
4221         info = _clutter_actor_get_layout_info_or_defaults (actor);
4222         g_value_set_float (value, info->min_width);
4223       }
4224       break;
4225
4226     case PROP_MIN_HEIGHT:
4227       {
4228         const ClutterLayoutInfo *info;
4229
4230         info = _clutter_actor_get_layout_info_or_defaults (actor);
4231         g_value_set_float (value, info->min_height);
4232       }
4233       break;
4234
4235     case PROP_NATURAL_WIDTH:
4236       {
4237         const ClutterLayoutInfo *info;
4238
4239         info = _clutter_actor_get_layout_info_or_defaults (actor);
4240         g_value_set_float (value, info->natural_width);
4241       }
4242       break;
4243
4244     case PROP_NATURAL_HEIGHT:
4245       {
4246         const ClutterLayoutInfo *info;
4247
4248         info = _clutter_actor_get_layout_info_or_defaults (actor);
4249         g_value_set_float (value, info->natural_height);
4250       }
4251       break;
4252
4253     case PROP_MIN_WIDTH_SET:
4254       g_value_set_boolean (value, priv->min_width_set);
4255       break;
4256
4257     case PROP_MIN_HEIGHT_SET:
4258       g_value_set_boolean (value, priv->min_height_set);
4259       break;
4260
4261     case PROP_NATURAL_WIDTH_SET:
4262       g_value_set_boolean (value, priv->natural_width_set);
4263       break;
4264
4265     case PROP_NATURAL_HEIGHT_SET:
4266       g_value_set_boolean (value, priv->natural_height_set);
4267       break;
4268
4269     case PROP_REQUEST_MODE:
4270       g_value_set_enum (value, priv->request_mode);
4271       break;
4272
4273     case PROP_ALLOCATION:
4274       g_value_set_boxed (value, &priv->allocation);
4275       break;
4276
4277     case PROP_DEPTH:
4278       g_value_set_float (value, clutter_actor_get_depth (actor));
4279       break;
4280
4281     case PROP_OPACITY:
4282       g_value_set_uint (value, priv->opacity);
4283       break;
4284
4285     case PROP_OFFSCREEN_REDIRECT:
4286       g_value_set_enum (value, priv->offscreen_redirect);
4287       break;
4288
4289     case PROP_NAME:
4290       g_value_set_string (value, priv->name);
4291       break;
4292
4293     case PROP_VISIBLE:
4294       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4295       break;
4296
4297     case PROP_MAPPED:
4298       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4299       break;
4300
4301     case PROP_REALIZED:
4302       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4303       break;
4304
4305     case PROP_HAS_CLIP:
4306       g_value_set_boolean (value, priv->has_clip);
4307       break;
4308
4309     case PROP_CLIP:
4310       {
4311         ClutterGeometry clip;
4312
4313         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4314         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4315         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4316         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4317
4318         g_value_set_boxed (value, &clip);
4319       }
4320       break;
4321
4322     case PROP_CLIP_TO_ALLOCATION:
4323       g_value_set_boolean (value, priv->clip_to_allocation);
4324       break;
4325
4326     case PROP_SCALE_X:
4327       {
4328         const ClutterTransformInfo *info;
4329
4330         info = _clutter_actor_get_transform_info_or_defaults (actor);
4331         g_value_set_double (value, info->scale_x);
4332       }
4333       break;
4334
4335     case PROP_SCALE_Y:
4336       {
4337         const ClutterTransformInfo *info;
4338
4339         info = _clutter_actor_get_transform_info_or_defaults (actor);
4340         g_value_set_double (value, info->scale_y);
4341       }
4342       break;
4343
4344     case PROP_SCALE_CENTER_X:
4345       {
4346         gfloat center;
4347
4348         clutter_actor_get_scale_center (actor, &center, NULL);
4349
4350         g_value_set_float (value, center);
4351       }
4352       break;
4353
4354     case PROP_SCALE_CENTER_Y:
4355       {
4356         gfloat center;
4357
4358         clutter_actor_get_scale_center (actor, NULL, &center);
4359
4360         g_value_set_float (value, center);
4361       }
4362       break;
4363
4364     case PROP_SCALE_GRAVITY:
4365       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4366       break;
4367
4368     case PROP_REACTIVE:
4369       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4370       break;
4371
4372     case PROP_ROTATION_ANGLE_X:
4373       {
4374         const ClutterTransformInfo *info;
4375
4376         info = _clutter_actor_get_transform_info_or_defaults (actor);
4377         g_value_set_double (value, info->rx_angle);
4378       }
4379       break;
4380
4381     case PROP_ROTATION_ANGLE_Y:
4382       {
4383         const ClutterTransformInfo *info;
4384
4385         info = _clutter_actor_get_transform_info_or_defaults (actor);
4386         g_value_set_double (value, info->ry_angle);
4387       }
4388       break;
4389
4390     case PROP_ROTATION_ANGLE_Z:
4391       {
4392         const ClutterTransformInfo *info;
4393
4394         info = _clutter_actor_get_transform_info_or_defaults (actor);
4395         g_value_set_double (value, info->rz_angle);
4396       }
4397       break;
4398
4399     case PROP_ROTATION_CENTER_X:
4400       {
4401         ClutterVertex center;
4402
4403         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4404                                     &center.x,
4405                                     &center.y,
4406                                     &center.z);
4407
4408         g_value_set_boxed (value, &center);
4409       }
4410       break;
4411
4412     case PROP_ROTATION_CENTER_Y:
4413       {
4414         ClutterVertex center;
4415
4416         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4417                                     &center.x,
4418                                     &center.y,
4419                                     &center.z);
4420
4421         g_value_set_boxed (value, &center);
4422       }
4423       break;
4424
4425     case PROP_ROTATION_CENTER_Z:
4426       {
4427         ClutterVertex center;
4428
4429         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4430                                     &center.x,
4431                                     &center.y,
4432                                     &center.z);
4433
4434         g_value_set_boxed (value, &center);
4435       }
4436       break;
4437
4438     case PROP_ROTATION_CENTER_Z_GRAVITY:
4439       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4440       break;
4441
4442     case PROP_ANCHOR_X:
4443       {
4444         const ClutterTransformInfo *info;
4445         gfloat anchor_x;
4446
4447         info = _clutter_actor_get_transform_info_or_defaults (actor);
4448         clutter_anchor_coord_get_units (actor, &info->anchor,
4449                                         &anchor_x,
4450                                         NULL,
4451                                         NULL);
4452         g_value_set_float (value, anchor_x);
4453       }
4454       break;
4455
4456     case PROP_ANCHOR_Y:
4457       {
4458         const ClutterTransformInfo *info;
4459         gfloat anchor_y;
4460
4461         info = _clutter_actor_get_transform_info_or_defaults (actor);
4462         clutter_anchor_coord_get_units (actor, &info->anchor,
4463                                         NULL,
4464                                         &anchor_y,
4465                                         NULL);
4466         g_value_set_float (value, anchor_y);
4467       }
4468       break;
4469
4470     case PROP_ANCHOR_GRAVITY:
4471       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4472       break;
4473
4474     case PROP_SHOW_ON_SET_PARENT:
4475       g_value_set_boolean (value, priv->show_on_set_parent);
4476       break;
4477
4478     case PROP_TEXT_DIRECTION:
4479       g_value_set_enum (value, priv->text_direction);
4480       break;
4481
4482     case PROP_HAS_POINTER:
4483       g_value_set_boolean (value, priv->has_pointer);
4484       break;
4485
4486     case PROP_LAYOUT_MANAGER:
4487       g_value_set_object (value, priv->layout_manager);
4488       break;
4489
4490     case PROP_X_ALIGN:
4491       {
4492         const ClutterLayoutInfo *info;
4493
4494         info = _clutter_actor_get_layout_info_or_defaults (actor);
4495         g_value_set_enum (value, info->x_align);
4496       }
4497       break;
4498
4499     case PROP_Y_ALIGN:
4500       {
4501         const ClutterLayoutInfo *info;
4502
4503         info = _clutter_actor_get_layout_info_or_defaults (actor);
4504         g_value_set_enum (value, info->y_align);
4505       }
4506       break;
4507
4508     case PROP_MARGIN_TOP:
4509       {
4510         const ClutterLayoutInfo *info;
4511
4512         info = _clutter_actor_get_layout_info_or_defaults (actor);
4513         g_value_set_float (value, info->margin.top);
4514       }
4515       break;
4516
4517     case PROP_MARGIN_BOTTOM:
4518       {
4519         const ClutterLayoutInfo *info;
4520
4521         info = _clutter_actor_get_layout_info_or_defaults (actor);
4522         g_value_set_float (value, info->margin.bottom);
4523       }
4524       break;
4525
4526     case PROP_MARGIN_LEFT:
4527       {
4528         const ClutterLayoutInfo *info;
4529
4530         info = _clutter_actor_get_layout_info_or_defaults (actor);
4531         g_value_set_float (value, info->margin.left);
4532       }
4533       break;
4534
4535     case PROP_MARGIN_RIGHT:
4536       {
4537         const ClutterLayoutInfo *info;
4538
4539         info = _clutter_actor_get_layout_info_or_defaults (actor);
4540         g_value_set_float (value, info->margin.right);
4541       }
4542       break;
4543
4544     case PROP_BACKGROUND_COLOR_SET:
4545       g_value_set_boolean (value, priv->bg_color_set);
4546       break;
4547
4548     case PROP_BACKGROUND_COLOR:
4549       g_value_set_boxed (value, &priv->bg_color);
4550       break;
4551
4552     case PROP_FIRST_CHILD:
4553       g_value_set_object (value, priv->first_child);
4554       break;
4555
4556     case PROP_LAST_CHILD:
4557       g_value_set_object (value, priv->last_child);
4558       break;
4559
4560     default:
4561       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4562       break;
4563     }
4564 }
4565
4566 static void
4567 clutter_actor_dispose (GObject *object)
4568 {
4569   ClutterActor *self = CLUTTER_ACTOR (object);
4570   ClutterActorPrivate *priv = self->priv;
4571
4572   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4573                 priv->id,
4574                 g_type_name (G_OBJECT_TYPE (self)),
4575                 object->ref_count);
4576
4577   g_signal_emit (self, actor_signals[DESTROY], 0);
4578
4579   /* avoid recursing when called from clutter_actor_destroy() */
4580   if (priv->parent != NULL)
4581     {
4582       ClutterActor *parent = priv->parent;
4583
4584       /* go through the Container implementation unless this
4585        * is an internal child and has been marked as such.
4586        *
4587        * removing the actor from its parent will reset the
4588        * realized and mapped states.
4589        */
4590       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4591         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4592       else
4593         clutter_actor_remove_child_internal (parent, self,
4594                                              REMOVE_CHILD_LEGACY_FLAGS);
4595     }
4596
4597   /* parent must be gone at this point */
4598   g_assert (priv->parent == NULL);
4599
4600   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4601     {
4602       /* can't be mapped or realized with no parent */
4603       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4604       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4605     }
4606
4607   g_clear_object (&priv->pango_context);
4608   g_clear_object (&priv->actions);
4609   g_clear_object (&priv->constraints);
4610   g_clear_object (&priv->effects);
4611   g_clear_object (&priv->flatten_effect);
4612
4613   if (priv->layout_manager != NULL)
4614     {
4615       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4616       g_object_unref (priv->layout_manager);
4617       priv->layout_manager = NULL;
4618     }
4619
4620   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4621 }
4622
4623 static void
4624 clutter_actor_finalize (GObject *object)
4625 {
4626   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4627
4628   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4629                 priv->name != NULL ? priv->name : "<none>",
4630                 priv->id,
4631                 g_type_name (G_OBJECT_TYPE (object)));
4632
4633   _clutter_context_release_id (priv->id);
4634
4635   g_free (priv->name);
4636
4637   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4638 }
4639
4640
4641 /**
4642  * clutter_actor_get_accessible:
4643  * @self: a #ClutterActor
4644  *
4645  * Returns the accessible object that describes the actor to an
4646  * assistive technology.
4647  *
4648  * If no class-specific #AtkObject implementation is available for the
4649  * actor instance in question, it will inherit an #AtkObject
4650  * implementation from the first ancestor class for which such an
4651  * implementation is defined.
4652  *
4653  * The documentation of the <ulink
4654  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4655  * library contains more information about accessible objects and
4656  * their uses.
4657  *
4658  * Returns: (transfer none): the #AtkObject associated with @actor
4659  */
4660 AtkObject *
4661 clutter_actor_get_accessible (ClutterActor *self)
4662 {
4663   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4664
4665   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4666 }
4667
4668 static AtkObject *
4669 clutter_actor_real_get_accessible (ClutterActor *actor)
4670 {
4671   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4672 }
4673
4674 static AtkObject *
4675 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4676 {
4677   AtkObject *accessible;
4678
4679   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4680   if (accessible != NULL)
4681     g_object_ref (accessible);
4682
4683   return accessible;
4684 }
4685
4686 static void
4687 atk_implementor_iface_init (AtkImplementorIface *iface)
4688 {
4689   iface->ref_accessible = _clutter_actor_ref_accessible;
4690 }
4691
4692 static gboolean
4693 clutter_actor_update_default_paint_volume (ClutterActor       *self,
4694                                            ClutterPaintVolume *volume)
4695 {
4696   ClutterActorPrivate *priv = self->priv;
4697   gboolean res = FALSE;
4698
4699   /* we start from the allocation */
4700   clutter_paint_volume_set_width (volume,
4701                                   priv->allocation.x2 - priv->allocation.x1);
4702   clutter_paint_volume_set_height (volume,
4703                                    priv->allocation.y2 - priv->allocation.y1);
4704
4705   /* if the actor has a clip set then we have a pretty definite
4706    * size for the paint volume: the actor cannot possibly paint
4707    * outside the clip region.
4708    */
4709   if (priv->clip_to_allocation)
4710     {
4711       /* the allocation has already been set, so we just flip the
4712        * return value
4713        */
4714       res = TRUE;
4715     }
4716   else
4717     {
4718       ClutterActor *child;
4719
4720       if (priv->has_clip &&
4721           priv->clip.width >= 0 &&
4722           priv->clip.height >= 0)
4723         {
4724           ClutterVertex origin;
4725
4726           origin.x = priv->clip.x;
4727           origin.y = priv->clip.y;
4728           origin.z = 0;
4729
4730           clutter_paint_volume_set_origin (volume, &origin);
4731           clutter_paint_volume_set_width (volume, priv->clip.width);
4732           clutter_paint_volume_set_height (volume, priv->clip.height);
4733
4734           res = TRUE;
4735         }
4736
4737       /* if we don't have children we just bail out here... */
4738       if (priv->n_children == 0)
4739         return res;
4740
4741       /* ...but if we have children then we ask for their paint volume in
4742        * our coordinates. if any of our children replies that it doesn't
4743        * have a paint volume, we bail out
4744        */
4745       for (child = priv->first_child;
4746            child != NULL;
4747            child = child->priv->next_sibling)
4748         {
4749           const ClutterPaintVolume *child_volume;
4750
4751           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4752           if (child_volume == NULL)
4753             {
4754               res = FALSE;
4755               break;
4756             }
4757
4758           clutter_paint_volume_union (volume, child_volume);
4759           res = TRUE;
4760         }
4761     }
4762
4763   return res;
4764
4765 }
4766
4767 static gboolean
4768 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4769                                      ClutterPaintVolume *volume)
4770 {
4771   ClutterActorClass *klass;
4772   gboolean res;
4773
4774   klass = CLUTTER_ACTOR_GET_CLASS (self);
4775
4776   /* XXX - this thoroughly sucks, but we don't want to penalize users
4777    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
4778    * redraw. This should go away in 2.0.
4779    */
4780   if (klass->paint == clutter_actor_real_paint &&
4781       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
4782     {
4783       res = TRUE;
4784     }
4785   else
4786     {
4787       /* this is the default return value: we cannot know if a class
4788        * is going to paint outside its allocation, so we take the
4789        * conservative approach.
4790        */
4791       res = FALSE;
4792     }
4793
4794   if (clutter_actor_update_default_paint_volume (self, volume))
4795     return res;
4796
4797   return FALSE;
4798 }
4799
4800 /**
4801  * clutter_actor_get_default_paint_volume:
4802  * @self: a #ClutterActor
4803  *
4804  * Retrieves the default paint volume for @self.
4805  *
4806  * This function provides the same #ClutterPaintVolume that would be
4807  * computed by the default implementation inside #ClutterActor of the
4808  * #ClutterActorClass.get_paint_volume() virtual function.
4809  *
4810  * This function should only be used by #ClutterActor subclasses that
4811  * cannot chain up to the parent implementation when computing their
4812  * paint volume.
4813  *
4814  * Return value: (transfer none): a pointer to the default
4815  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
4816  *   the actor could not compute a valid paint volume. The returned value
4817  *   is not guaranteed to be stable across multiple frames, so if you
4818  *   want to retain it, you will need to copy it using
4819  *   clutter_paint_volume_copy().
4820  *
4821  * Since: 1.10
4822  */
4823 const ClutterPaintVolume *
4824 clutter_actor_get_default_paint_volume (ClutterActor *self)
4825 {
4826   ClutterPaintVolume volume;
4827   ClutterPaintVolume *res;
4828
4829   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4830
4831   res = NULL;
4832   _clutter_paint_volume_init_static (&volume, self);
4833   if (clutter_actor_update_default_paint_volume (self, &volume))
4834     {
4835       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
4836
4837       if (stage != NULL)
4838         {
4839           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
4840           _clutter_paint_volume_copy_static (&volume, res);
4841         }
4842     }
4843
4844   clutter_paint_volume_free (&volume);
4845
4846   return res;
4847 }
4848
4849 static gboolean
4850 clutter_actor_real_has_overlaps (ClutterActor *self)
4851 {
4852   /* By default we'll assume that all actors need an offscreen redirect to get
4853    * the correct opacity. Actors such as ClutterTexture that would never need
4854    * an offscreen redirect can override this to return FALSE. */
4855   return TRUE;
4856 }
4857
4858 static void
4859 clutter_actor_real_destroy (ClutterActor *actor)
4860 {
4861   ClutterActorIter iter;
4862
4863   clutter_actor_iter_init (&iter, actor);
4864   while (clutter_actor_iter_next (&iter, NULL))
4865     clutter_actor_iter_destroy (&iter);
4866 }
4867
4868 static GObject *
4869 clutter_actor_constructor (GType gtype,
4870                            guint n_props,
4871                            GObjectConstructParam *props)
4872 {
4873   GObjectClass *gobject_class;
4874   ClutterActor *self;
4875   GObject *retval;
4876
4877   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
4878   retval = gobject_class->constructor (gtype, n_props, props);
4879   self = CLUTTER_ACTOR (retval);
4880
4881   if (self->priv->layout_manager == NULL)
4882     {
4883       ClutterLayoutManager *default_layout;
4884
4885       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
4886
4887       default_layout = clutter_fixed_layout_new ();
4888       clutter_actor_set_layout_manager (self, default_layout);
4889     }
4890
4891   return retval;
4892 }
4893
4894 static void
4895 clutter_actor_class_init (ClutterActorClass *klass)
4896 {
4897   GObjectClass *object_class = G_OBJECT_CLASS (klass);
4898
4899   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
4900   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
4901   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
4902
4903   object_class->constructor = clutter_actor_constructor;
4904   object_class->set_property = clutter_actor_set_property;
4905   object_class->get_property = clutter_actor_get_property;
4906   object_class->dispose = clutter_actor_dispose;
4907   object_class->finalize = clutter_actor_finalize;
4908
4909   klass->show = clutter_actor_real_show;
4910   klass->show_all = clutter_actor_show;
4911   klass->hide = clutter_actor_real_hide;
4912   klass->hide_all = clutter_actor_hide;
4913   klass->map = clutter_actor_real_map;
4914   klass->unmap = clutter_actor_real_unmap;
4915   klass->unrealize = clutter_actor_real_unrealize;
4916   klass->pick = clutter_actor_real_pick;
4917   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
4918   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4919   klass->allocate = clutter_actor_real_allocate;
4920   klass->queue_redraw = clutter_actor_real_queue_redraw;
4921   klass->queue_relayout = clutter_actor_real_queue_relayout;
4922   klass->apply_transform = clutter_actor_real_apply_transform;
4923   klass->get_accessible = clutter_actor_real_get_accessible;
4924   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
4925   klass->has_overlaps = clutter_actor_real_has_overlaps;
4926   klass->paint = clutter_actor_real_paint;
4927   klass->destroy = clutter_actor_real_destroy;
4928
4929   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
4930
4931   /**
4932    * ClutterActor:x:
4933    *
4934    * X coordinate of the actor in pixels. If written, forces a fixed
4935    * position for the actor. If read, returns the fixed position if any,
4936    * otherwise the allocation if available, otherwise 0.
4937    */
4938   obj_props[PROP_X] =
4939     g_param_spec_float ("x",
4940                         P_("X coordinate"),
4941                         P_("X coordinate of the actor"),
4942                         -G_MAXFLOAT, G_MAXFLOAT,
4943                         0.0,
4944                         CLUTTER_PARAM_READWRITE);
4945
4946   /**
4947    * ClutterActor:y:
4948    *
4949    * Y coordinate of the actor in pixels. If written, forces a fixed
4950    * position for the actor.  If read, returns the fixed position if
4951    * any, otherwise the allocation if available, otherwise 0.
4952    */
4953   obj_props[PROP_Y] =
4954     g_param_spec_float ("y",
4955                         P_("Y coordinate"),
4956                         P_("Y coordinate of the actor"),
4957                         -G_MAXFLOAT, G_MAXFLOAT,
4958                         0.0,
4959                         CLUTTER_PARAM_READWRITE);
4960
4961   /**
4962    * ClutterActor:width:
4963    *
4964    * Width of the actor (in pixels). If written, forces the minimum and
4965    * natural size request of the actor to the given width. If read, returns
4966    * the allocated width if available, otherwise the width request.
4967    */
4968   obj_props[PROP_WIDTH] =
4969     g_param_spec_float ("width",
4970                         P_("Width"),
4971                         P_("Width of the actor"),
4972                         0.0, G_MAXFLOAT,
4973                         0.0,
4974                         CLUTTER_PARAM_READWRITE);
4975
4976   /**
4977    * ClutterActor:height:
4978    *
4979    * Height of the actor (in pixels).  If written, forces the minimum and
4980    * natural size request of the actor to the given height. If read, returns
4981    * the allocated height if available, otherwise the height request.
4982    */
4983   obj_props[PROP_HEIGHT] =
4984     g_param_spec_float ("height",
4985                         P_("Height"),
4986                         P_("Height of the actor"),
4987                         0.0, G_MAXFLOAT,
4988                         0.0,
4989                         CLUTTER_PARAM_READWRITE);
4990
4991   /**
4992    * ClutterActor:fixed-x:
4993    *
4994    * The fixed X position of the actor in pixels.
4995    *
4996    * Writing this property sets #ClutterActor:fixed-position-set
4997    * property as well, as a side effect
4998    *
4999    * Since: 0.8
5000    */
5001   obj_props[PROP_FIXED_X] =
5002     g_param_spec_float ("fixed-x",
5003                         P_("Fixed X"),
5004                         P_("Forced X position of the actor"),
5005                         -G_MAXFLOAT, G_MAXFLOAT,
5006                         0.0,
5007                         CLUTTER_PARAM_READWRITE);
5008
5009   /**
5010    * ClutterActor:fixed-y:
5011    *
5012    * The fixed Y position of the actor in pixels.
5013    *
5014    * Writing this property sets the #ClutterActor:fixed-position-set
5015    * property as well, as a side effect
5016    *
5017    * Since: 0.8
5018    */
5019   obj_props[PROP_FIXED_Y] =
5020     g_param_spec_float ("fixed-y",
5021                         P_("Fixed Y"),
5022                         P_("Forced Y position of the actor"),
5023                         -G_MAXFLOAT, G_MAXFLOAT,
5024                         0,
5025                         CLUTTER_PARAM_READWRITE);
5026
5027   /**
5028    * ClutterActor:fixed-position-set:
5029    *
5030    * This flag controls whether the #ClutterActor:fixed-x and
5031    * #ClutterActor:fixed-y properties are used
5032    *
5033    * Since: 0.8
5034    */
5035   obj_props[PROP_FIXED_POSITION_SET] =
5036     g_param_spec_boolean ("fixed-position-set",
5037                           P_("Fixed position set"),
5038                           P_("Whether to use fixed positioning for the actor"),
5039                           FALSE,
5040                           CLUTTER_PARAM_READWRITE);
5041
5042   /**
5043    * ClutterActor:min-width:
5044    *
5045    * A forced minimum width request for the actor, in pixels
5046    *
5047    * Writing this property sets the #ClutterActor:min-width-set property
5048    * as well, as a side effect.
5049    *
5050    *This property overrides the usual width request of the actor.
5051    *
5052    * Since: 0.8
5053    */
5054   obj_props[PROP_MIN_WIDTH] =
5055     g_param_spec_float ("min-width",
5056                         P_("Min Width"),
5057                         P_("Forced minimum width request for the actor"),
5058                         0.0, G_MAXFLOAT,
5059                         0.0,
5060                         CLUTTER_PARAM_READWRITE);
5061
5062   /**
5063    * ClutterActor:min-height:
5064    *
5065    * A forced minimum height request for the actor, in pixels
5066    *
5067    * Writing this property sets the #ClutterActor:min-height-set property
5068    * as well, as a side effect. This property overrides the usual height
5069    * request of the actor.
5070    *
5071    * Since: 0.8
5072    */
5073   obj_props[PROP_MIN_HEIGHT] =
5074     g_param_spec_float ("min-height",
5075                         P_("Min Height"),
5076                         P_("Forced minimum height request for the actor"),
5077                         0.0, G_MAXFLOAT,
5078                         0.0,
5079                         CLUTTER_PARAM_READWRITE);
5080
5081   /**
5082    * ClutterActor:natural-width:
5083    *
5084    * A forced natural width request for the actor, in pixels
5085    *
5086    * Writing this property sets the #ClutterActor:natural-width-set
5087    * property as well, as a side effect. This property overrides the
5088    * usual width request of the actor
5089    *
5090    * Since: 0.8
5091    */
5092   obj_props[PROP_NATURAL_WIDTH] =
5093     g_param_spec_float ("natural-width",
5094                         P_("Natural Width"),
5095                         P_("Forced natural width request for the actor"),
5096                         0.0, G_MAXFLOAT,
5097                         0.0,
5098                         CLUTTER_PARAM_READWRITE);
5099
5100   /**
5101    * ClutterActor:natural-height:
5102    *
5103    * A forced natural height request for the actor, in pixels
5104    *
5105    * Writing this property sets the #ClutterActor:natural-height-set
5106    * property as well, as a side effect. This property overrides the
5107    * usual height request of the actor
5108    *
5109    * Since: 0.8
5110    */
5111   obj_props[PROP_NATURAL_HEIGHT] =
5112     g_param_spec_float ("natural-height",
5113                         P_("Natural Height"),
5114                         P_("Forced natural height request for the actor"),
5115                         0.0, G_MAXFLOAT,
5116                         0.0,
5117                         CLUTTER_PARAM_READWRITE);
5118
5119   /**
5120    * ClutterActor:min-width-set:
5121    *
5122    * This flag controls whether the #ClutterActor:min-width property
5123    * is used
5124    *
5125    * Since: 0.8
5126    */
5127   obj_props[PROP_MIN_WIDTH_SET] =
5128     g_param_spec_boolean ("min-width-set",
5129                           P_("Minimum width set"),
5130                           P_("Whether to use the min-width property"),
5131                           FALSE,
5132                           CLUTTER_PARAM_READWRITE);
5133
5134   /**
5135    * ClutterActor:min-height-set:
5136    *
5137    * This flag controls whether the #ClutterActor:min-height property
5138    * is used
5139    *
5140    * Since: 0.8
5141    */
5142   obj_props[PROP_MIN_HEIGHT_SET] =
5143     g_param_spec_boolean ("min-height-set",
5144                           P_("Minimum height set"),
5145                           P_("Whether to use the min-height property"),
5146                           FALSE,
5147                           CLUTTER_PARAM_READWRITE);
5148
5149   /**
5150    * ClutterActor:natural-width-set:
5151    *
5152    * This flag controls whether the #ClutterActor:natural-width property
5153    * is used
5154    *
5155    * Since: 0.8
5156    */
5157   obj_props[PROP_NATURAL_WIDTH_SET] =
5158     g_param_spec_boolean ("natural-width-set",
5159                           P_("Natural width set"),
5160                           P_("Whether to use the natural-width property"),
5161                           FALSE,
5162                           CLUTTER_PARAM_READWRITE);
5163
5164   /**
5165    * ClutterActor:natural-height-set:
5166    *
5167    * This flag controls whether the #ClutterActor:natural-height property
5168    * is used
5169    *
5170    * Since: 0.8
5171    */
5172   obj_props[PROP_NATURAL_HEIGHT_SET] =
5173     g_param_spec_boolean ("natural-height-set",
5174                           P_("Natural height set"),
5175                           P_("Whether to use the natural-height property"),
5176                           FALSE,
5177                           CLUTTER_PARAM_READWRITE);
5178
5179   /**
5180    * ClutterActor:allocation:
5181    *
5182    * The allocation for the actor, in pixels
5183    *
5184    * This is property is read-only, but you might monitor it to know when an
5185    * actor moves or resizes
5186    *
5187    * Since: 0.8
5188    */
5189   obj_props[PROP_ALLOCATION] =
5190     g_param_spec_boxed ("allocation",
5191                         P_("Allocation"),
5192                         P_("The actor's allocation"),
5193                         CLUTTER_TYPE_ACTOR_BOX,
5194                         CLUTTER_PARAM_READABLE);
5195
5196   /**
5197    * ClutterActor:request-mode:
5198    *
5199    * Request mode for the #ClutterActor. The request mode determines the
5200    * type of geometry management used by the actor, either height for width
5201    * (the default) or width for height.
5202    *
5203    * For actors implementing height for width, the parent container should get
5204    * the preferred width first, and then the preferred height for that width.
5205    *
5206    * For actors implementing width for height, the parent container should get
5207    * the preferred height first, and then the preferred width for that height.
5208    *
5209    * For instance:
5210    *
5211    * |[
5212    *   ClutterRequestMode mode;
5213    *   gfloat natural_width, min_width;
5214    *   gfloat natural_height, min_height;
5215    *
5216    *   mode = clutter_actor_get_request_mode (child);
5217    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5218    *     {
5219    *       clutter_actor_get_preferred_width (child, -1,
5220    *                                          &amp;min_width,
5221    *                                          &amp;natural_width);
5222    *       clutter_actor_get_preferred_height (child, natural_width,
5223    *                                           &amp;min_height,
5224    *                                           &amp;natural_height);
5225    *     }
5226    *   else
5227    *     {
5228    *       clutter_actor_get_preferred_height (child, -1,
5229    *                                           &amp;min_height,
5230    *                                           &amp;natural_height);
5231    *       clutter_actor_get_preferred_width (child, natural_height,
5232    *                                          &amp;min_width,
5233    *                                          &amp;natural_width);
5234    *     }
5235    * ]|
5236    *
5237    * will retrieve the minimum and natural width and height depending on the
5238    * preferred request mode of the #ClutterActor "child".
5239    *
5240    * The clutter_actor_get_preferred_size() function will implement this
5241    * check for you.
5242    *
5243    * Since: 0.8
5244    */
5245   obj_props[PROP_REQUEST_MODE] =
5246     g_param_spec_enum ("request-mode",
5247                        P_("Request Mode"),
5248                        P_("The actor's request mode"),
5249                        CLUTTER_TYPE_REQUEST_MODE,
5250                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5251                        CLUTTER_PARAM_READWRITE);
5252
5253   /**
5254    * ClutterActor:depth:
5255    *
5256    * The position of the actor on the Z axis
5257    *
5258    * Since: 0.6
5259    */
5260   obj_props[PROP_DEPTH] =
5261     g_param_spec_float ("depth",
5262                         P_("Depth"),
5263                         P_("Position on the Z axis"),
5264                         -G_MAXFLOAT, G_MAXFLOAT,
5265                         0.0,
5266                         CLUTTER_PARAM_READWRITE);
5267
5268   /**
5269    * ClutterActor:opacity:
5270    *
5271    * Opacity of an actor, between 0 (fully transparent) and
5272    * 255 (fully opaque)
5273    */
5274   obj_props[PROP_OPACITY] =
5275     g_param_spec_uint ("opacity",
5276                        P_("Opacity"),
5277                        P_("Opacity of an actor"),
5278                        0, 255,
5279                        255,
5280                        CLUTTER_PARAM_READWRITE);
5281
5282   /**
5283    * ClutterActor:offscreen-redirect:
5284    *
5285    * Determines the conditions in which the actor will be redirected
5286    * to an offscreen framebuffer while being painted. For example this
5287    * can be used to cache an actor in a framebuffer or for improved
5288    * handling of transparent actors. See
5289    * clutter_actor_set_offscreen_redirect() for details.
5290    *
5291    * Since: 1.8
5292    */
5293   obj_props[PROP_OFFSCREEN_REDIRECT] =
5294     g_param_spec_flags ("offscreen-redirect",
5295                         P_("Offscreen redirect"),
5296                         P_("Flags controlling when to flatten the actor into a single image"),
5297                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5298                         0,
5299                         CLUTTER_PARAM_READWRITE);
5300
5301   /**
5302    * ClutterActor:visible:
5303    *
5304    * Whether the actor is set to be visible or not
5305    *
5306    * See also #ClutterActor:mapped
5307    */
5308   obj_props[PROP_VISIBLE] =
5309     g_param_spec_boolean ("visible",
5310                           P_("Visible"),
5311                           P_("Whether the actor is visible or not"),
5312                           FALSE,
5313                           CLUTTER_PARAM_READWRITE);
5314
5315   /**
5316    * ClutterActor:mapped:
5317    *
5318    * Whether the actor is mapped (will be painted when the stage
5319    * to which it belongs is mapped)
5320    *
5321    * Since: 1.0
5322    */
5323   obj_props[PROP_MAPPED] =
5324     g_param_spec_boolean ("mapped",
5325                           P_("Mapped"),
5326                           P_("Whether the actor will be painted"),
5327                           FALSE,
5328                           CLUTTER_PARAM_READABLE);
5329
5330   /**
5331    * ClutterActor:realized:
5332    *
5333    * Whether the actor has been realized
5334    *
5335    * Since: 1.0
5336    */
5337   obj_props[PROP_REALIZED] =
5338     g_param_spec_boolean ("realized",
5339                           P_("Realized"),
5340                           P_("Whether the actor has been realized"),
5341                           FALSE,
5342                           CLUTTER_PARAM_READABLE);
5343
5344   /**
5345    * ClutterActor:reactive:
5346    *
5347    * Whether the actor is reactive to events or not
5348    *
5349    * Only reactive actors will emit event-related signals
5350    *
5351    * Since: 0.6
5352    */
5353   obj_props[PROP_REACTIVE] =
5354     g_param_spec_boolean ("reactive",
5355                           P_("Reactive"),
5356                           P_("Whether the actor is reactive to events"),
5357                           FALSE,
5358                           CLUTTER_PARAM_READWRITE);
5359
5360   /**
5361    * ClutterActor:has-clip:
5362    *
5363    * Whether the actor has the #ClutterActor:clip property set or not
5364    */
5365   obj_props[PROP_HAS_CLIP] =
5366     g_param_spec_boolean ("has-clip",
5367                           P_("Has Clip"),
5368                           P_("Whether the actor has a clip set"),
5369                           FALSE,
5370                           CLUTTER_PARAM_READABLE);
5371
5372   /**
5373    * ClutterActor:clip:
5374    *
5375    * The clip region for the actor, in actor-relative coordinates
5376    *
5377    * Every part of the actor outside the clip region will not be
5378    * painted
5379    */
5380   obj_props[PROP_CLIP] =
5381     g_param_spec_boxed ("clip",
5382                         P_("Clip"),
5383                         P_("The clip region for the actor"),
5384                         CLUTTER_TYPE_GEOMETRY,
5385                         CLUTTER_PARAM_READWRITE);
5386
5387   /**
5388    * ClutterActor:name:
5389    *
5390    * The name of the actor
5391    *
5392    * Since: 0.2
5393    */
5394   obj_props[PROP_NAME] =
5395     g_param_spec_string ("name",
5396                          P_("Name"),
5397                          P_("Name of the actor"),
5398                          NULL,
5399                          CLUTTER_PARAM_READWRITE);
5400
5401   /**
5402    * ClutterActor:scale-x:
5403    *
5404    * The horizontal scale of the actor
5405    *
5406    * Since: 0.6
5407    */
5408   obj_props[PROP_SCALE_X] =
5409     g_param_spec_double ("scale-x",
5410                          P_("Scale X"),
5411                          P_("Scale factor on the X axis"),
5412                          0.0, G_MAXDOUBLE,
5413                          1.0,
5414                          CLUTTER_PARAM_READWRITE);
5415
5416   /**
5417    * ClutterActor:scale-y:
5418    *
5419    * The vertical scale of the actor
5420    *
5421    * Since: 0.6
5422    */
5423   obj_props[PROP_SCALE_Y] =
5424     g_param_spec_double ("scale-y",
5425                          P_("Scale Y"),
5426                          P_("Scale factor on the Y axis"),
5427                          0.0, G_MAXDOUBLE,
5428                          1.0,
5429                          CLUTTER_PARAM_READWRITE);
5430
5431   /**
5432    * ClutterActor:scale-center-x:
5433    *
5434    * The horizontal center point for scaling
5435    *
5436    * Since: 1.0
5437    */
5438   obj_props[PROP_SCALE_CENTER_X] =
5439     g_param_spec_float ("scale-center-x",
5440                         P_("Scale Center X"),
5441                         P_("Horizontal scale center"),
5442                         -G_MAXFLOAT, G_MAXFLOAT,
5443                         0.0,
5444                         CLUTTER_PARAM_READWRITE);
5445
5446   /**
5447    * ClutterActor:scale-center-y:
5448    *
5449    * The vertical center point for scaling
5450    *
5451    * Since: 1.0
5452    */
5453   obj_props[PROP_SCALE_CENTER_Y] =
5454     g_param_spec_float ("scale-center-y",
5455                         P_("Scale Center Y"),
5456                         P_("Vertical scale center"),
5457                         -G_MAXFLOAT, G_MAXFLOAT,
5458                         0.0,
5459                         CLUTTER_PARAM_READWRITE);
5460
5461   /**
5462    * ClutterActor:scale-gravity:
5463    *
5464    * The center point for scaling expressed as a #ClutterGravity
5465    *
5466    * Since: 1.0
5467    */
5468   obj_props[PROP_SCALE_GRAVITY] =
5469     g_param_spec_enum ("scale-gravity",
5470                        P_("Scale Gravity"),
5471                        P_("The center of scaling"),
5472                        CLUTTER_TYPE_GRAVITY,
5473                        CLUTTER_GRAVITY_NONE,
5474                        CLUTTER_PARAM_READWRITE);
5475
5476   /**
5477    * ClutterActor:rotation-angle-x:
5478    *
5479    * The rotation angle on the X axis
5480    *
5481    * Since: 0.6
5482    */
5483   obj_props[PROP_ROTATION_ANGLE_X] =
5484     g_param_spec_double ("rotation-angle-x",
5485                          P_("Rotation Angle X"),
5486                          P_("The rotation angle on the X axis"),
5487                          -G_MAXDOUBLE, G_MAXDOUBLE,
5488                          0.0,
5489                          CLUTTER_PARAM_READWRITE);
5490
5491   /**
5492    * ClutterActor:rotation-angle-y:
5493    *
5494    * The rotation angle on the Y axis
5495    *
5496    * Since: 0.6
5497    */
5498   obj_props[PROP_ROTATION_ANGLE_Y] =
5499     g_param_spec_double ("rotation-angle-y",
5500                          P_("Rotation Angle Y"),
5501                          P_("The rotation angle on the Y axis"),
5502                          -G_MAXDOUBLE, G_MAXDOUBLE,
5503                          0.0,
5504                          CLUTTER_PARAM_READWRITE);
5505
5506   /**
5507    * ClutterActor:rotation-angle-z:
5508    *
5509    * The rotation angle on the Z axis
5510    *
5511    * Since: 0.6
5512    */
5513   obj_props[PROP_ROTATION_ANGLE_Z] =
5514     g_param_spec_double ("rotation-angle-z",
5515                          P_("Rotation Angle Z"),
5516                          P_("The rotation angle on the Z axis"),
5517                          -G_MAXDOUBLE, G_MAXDOUBLE,
5518                          0.0,
5519                          CLUTTER_PARAM_READWRITE);
5520
5521   /**
5522    * ClutterActor:rotation-center-x:
5523    *
5524    * The rotation center on the X axis.
5525    *
5526    * Since: 0.6
5527    */
5528   obj_props[PROP_ROTATION_CENTER_X] =
5529     g_param_spec_boxed ("rotation-center-x",
5530                         P_("Rotation Center X"),
5531                         P_("The rotation center on the X axis"),
5532                         CLUTTER_TYPE_VERTEX,
5533                         CLUTTER_PARAM_READWRITE);
5534
5535   /**
5536    * ClutterActor:rotation-center-y:
5537    *
5538    * The rotation center on the Y axis.
5539    *
5540    * Since: 0.6
5541    */
5542   obj_props[PROP_ROTATION_CENTER_Y] =
5543     g_param_spec_boxed ("rotation-center-y",
5544                         P_("Rotation Center Y"),
5545                         P_("The rotation center on the Y axis"),
5546                         CLUTTER_TYPE_VERTEX,
5547                         CLUTTER_PARAM_READWRITE);
5548
5549   /**
5550    * ClutterActor:rotation-center-z:
5551    *
5552    * The rotation center on the Z axis.
5553    *
5554    * Since: 0.6
5555    */
5556   obj_props[PROP_ROTATION_CENTER_Z] =
5557     g_param_spec_boxed ("rotation-center-z",
5558                         P_("Rotation Center Z"),
5559                         P_("The rotation center on the Z axis"),
5560                         CLUTTER_TYPE_VERTEX,
5561                         CLUTTER_PARAM_READWRITE);
5562
5563   /**
5564    * ClutterActor:rotation-center-z-gravity:
5565    *
5566    * The rotation center on the Z axis expressed as a #ClutterGravity.
5567    *
5568    * Since: 1.0
5569    */
5570   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5571     g_param_spec_enum ("rotation-center-z-gravity",
5572                        P_("Rotation Center Z Gravity"),
5573                        P_("Center point for rotation around the Z axis"),
5574                        CLUTTER_TYPE_GRAVITY,
5575                        CLUTTER_GRAVITY_NONE,
5576                        CLUTTER_PARAM_READWRITE);
5577
5578   /**
5579    * ClutterActor:anchor-x:
5580    *
5581    * The X coordinate of an actor's anchor point, relative to
5582    * the actor coordinate space, in pixels
5583    *
5584    * Since: 0.8
5585    */
5586   obj_props[PROP_ANCHOR_X] =
5587     g_param_spec_float ("anchor-x",
5588                         P_("Anchor X"),
5589                         P_("X coordinate of the anchor point"),
5590                         -G_MAXFLOAT, G_MAXFLOAT,
5591                         0,
5592                         CLUTTER_PARAM_READWRITE);
5593
5594   /**
5595    * ClutterActor:anchor-y:
5596    *
5597    * The Y coordinate of an actor's anchor point, relative to
5598    * the actor coordinate space, in pixels
5599    *
5600    * Since: 0.8
5601    */
5602   obj_props[PROP_ANCHOR_Y] =
5603     g_param_spec_float ("anchor-y",
5604                         P_("Anchor Y"),
5605                         P_("Y coordinate of the anchor point"),
5606                         -G_MAXFLOAT, G_MAXFLOAT,
5607                         0,
5608                         CLUTTER_PARAM_READWRITE);
5609
5610   /**
5611    * ClutterActor:anchor-gravity:
5612    *
5613    * The anchor point expressed as a #ClutterGravity
5614    *
5615    * Since: 1.0
5616    */
5617   obj_props[PROP_ANCHOR_GRAVITY] =
5618     g_param_spec_enum ("anchor-gravity",
5619                        P_("Anchor Gravity"),
5620                        P_("The anchor point as a ClutterGravity"),
5621                        CLUTTER_TYPE_GRAVITY,
5622                        CLUTTER_GRAVITY_NONE,
5623                        CLUTTER_PARAM_READWRITE);
5624
5625   /**
5626    * ClutterActor:show-on-set-parent:
5627    *
5628    * If %TRUE, the actor is automatically shown when parented.
5629    *
5630    * Calling clutter_actor_hide() on an actor which has not been
5631    * parented will set this property to %FALSE as a side effect.
5632    *
5633    * Since: 0.8
5634    */
5635   obj_props[PROP_SHOW_ON_SET_PARENT] =
5636     g_param_spec_boolean ("show-on-set-parent",
5637                           P_("Show on set parent"),
5638                           P_("Whether the actor is shown when parented"),
5639                           TRUE,
5640                           CLUTTER_PARAM_READWRITE);
5641
5642   /**
5643    * ClutterActor:clip-to-allocation:
5644    *
5645    * Whether the clip region should track the allocated area
5646    * of the actor.
5647    *
5648    * This property is ignored if a clip area has been explicitly
5649    * set using clutter_actor_set_clip().
5650    *
5651    * Since: 1.0
5652    */
5653   obj_props[PROP_CLIP_TO_ALLOCATION] =
5654     g_param_spec_boolean ("clip-to-allocation",
5655                           P_("Clip to Allocation"),
5656                           P_("Sets the clip region to track the actor's allocation"),
5657                           FALSE,
5658                           CLUTTER_PARAM_READWRITE);
5659
5660   /**
5661    * ClutterActor:text-direction:
5662    *
5663    * The direction of the text inside a #ClutterActor.
5664    *
5665    * Since: 1.0
5666    */
5667   obj_props[PROP_TEXT_DIRECTION] =
5668     g_param_spec_enum ("text-direction",
5669                        P_("Text Direction"),
5670                        P_("Direction of the text"),
5671                        CLUTTER_TYPE_TEXT_DIRECTION,
5672                        CLUTTER_TEXT_DIRECTION_LTR,
5673                        CLUTTER_PARAM_READWRITE);
5674
5675   /**
5676    * ClutterActor:has-pointer:
5677    *
5678    * Whether the actor contains the pointer of a #ClutterInputDevice
5679    * or not.
5680    *
5681    * Since: 1.2
5682    */
5683   obj_props[PROP_HAS_POINTER] =
5684     g_param_spec_boolean ("has-pointer",
5685                           P_("Has Pointer"),
5686                           P_("Whether the actor contains the pointer of an input device"),
5687                           FALSE,
5688                           CLUTTER_PARAM_READABLE);
5689
5690   /**
5691    * ClutterActor:actions:
5692    *
5693    * Adds a #ClutterAction to the actor
5694    *
5695    * Since: 1.4
5696    */
5697   obj_props[PROP_ACTIONS] =
5698     g_param_spec_object ("actions",
5699                          P_("Actions"),
5700                          P_("Adds an action to the actor"),
5701                          CLUTTER_TYPE_ACTION,
5702                          CLUTTER_PARAM_WRITABLE);
5703
5704   /**
5705    * ClutterActor:constraints:
5706    *
5707    * Adds a #ClutterConstraint to the actor
5708    *
5709    * Since: 1.4
5710    */
5711   obj_props[PROP_CONSTRAINTS] =
5712     g_param_spec_object ("constraints",
5713                          P_("Constraints"),
5714                          P_("Adds a constraint to the actor"),
5715                          CLUTTER_TYPE_CONSTRAINT,
5716                          CLUTTER_PARAM_WRITABLE);
5717
5718   /**
5719    * ClutterActor:effect:
5720    *
5721    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5722    *
5723    * Since: 1.4
5724    */
5725   obj_props[PROP_EFFECT] =
5726     g_param_spec_object ("effect",
5727                          P_("Effect"),
5728                          P_("Add an effect to be applied on the actor"),
5729                          CLUTTER_TYPE_EFFECT,
5730                          CLUTTER_PARAM_WRITABLE);
5731
5732   /**
5733    * ClutterActor:layout-manager:
5734    *
5735    * A delegate object for controlling the layout of the children of
5736    * an actor.
5737    *
5738    * Since: 1.10
5739    */
5740   obj_props[PROP_LAYOUT_MANAGER] =
5741     g_param_spec_object ("layout-manager",
5742                          P_("Layout Manager"),
5743                          P_("The object controlling the layout of an actor's children"),
5744                          CLUTTER_TYPE_LAYOUT_MANAGER,
5745                          CLUTTER_PARAM_READWRITE);
5746
5747
5748   /**
5749    * ClutterActor:x-align:
5750    *
5751    * The alignment of an actor on the X axis, if the actor has been given
5752    * extra space for its allocation.
5753    *
5754    * Since: 1.10
5755    */
5756   obj_props[PROP_X_ALIGN] =
5757     g_param_spec_enum ("x-align",
5758                        P_("X Alignment"),
5759                        P_("The alignment of the actor on the X axis within its allocation"),
5760                        CLUTTER_TYPE_ACTOR_ALIGN,
5761                        CLUTTER_ACTOR_ALIGN_FILL,
5762                        CLUTTER_PARAM_READWRITE);
5763
5764   /**
5765    * ClutterActor:y-align:
5766    *
5767    * The alignment of an actor on the Y axis, if the actor has been given
5768    * extra space for its allocation.
5769    *
5770    * Since: 1.10
5771    */
5772   obj_props[PROP_Y_ALIGN] =
5773     g_param_spec_enum ("y-align",
5774                        P_("Y Alignment"),
5775                        P_("The alignment of the actor on the Y axis within its allocation"),
5776                        CLUTTER_TYPE_ACTOR_ALIGN,
5777                        CLUTTER_ACTOR_ALIGN_FILL,
5778                        CLUTTER_PARAM_READWRITE);
5779
5780   /**
5781    * ClutterActor:margin-top:
5782    *
5783    * The margin (in pixels) from the top of the actor.
5784    *
5785    * This property adds a margin to the actor's preferred size; the margin
5786    * will be automatically taken into account when allocating the actor.
5787    *
5788    * Since: 1.10
5789    */
5790   obj_props[PROP_MARGIN_TOP] =
5791     g_param_spec_float ("margin-top",
5792                         P_("Margin Top"),
5793                         P_("Extra space at the top"),
5794                         0.0, G_MAXFLOAT,
5795                         0.0,
5796                         CLUTTER_PARAM_READWRITE);
5797
5798   /**
5799    * ClutterActor:margin-bottom:
5800    *
5801    * The margin (in pixels) from the bottom of the actor.
5802    *
5803    * This property adds a margin to the actor's preferred size; the margin
5804    * will be automatically taken into account when allocating the actor.
5805    *
5806    * Since: 1.10
5807    */
5808   obj_props[PROP_MARGIN_BOTTOM] =
5809     g_param_spec_float ("margin-bottom",
5810                         P_("Margin Bottom"),
5811                         P_("Extra space at the bottom"),
5812                         0.0, G_MAXFLOAT,
5813                         0.0,
5814                         CLUTTER_PARAM_READWRITE);
5815
5816   /**
5817    * ClutterActor:margin-left:
5818    *
5819    * The margin (in pixels) from the left of the actor.
5820    *
5821    * This property adds a margin to the actor's preferred size; the margin
5822    * will be automatically taken into account when allocating the actor.
5823    *
5824    * Since: 1.10
5825    */
5826   obj_props[PROP_MARGIN_LEFT] =
5827     g_param_spec_float ("margin-left",
5828                         P_("Margin Left"),
5829                         P_("Extra space at the left"),
5830                         0.0, G_MAXFLOAT,
5831                         0.0,
5832                         CLUTTER_PARAM_READWRITE);
5833
5834   /**
5835    * ClutterActor:margin-right:
5836    *
5837    * The margin (in pixels) from the right of the actor.
5838    *
5839    * This property adds a margin to the actor's preferred size; the margin
5840    * will be automatically taken into account when allocating the actor.
5841    *
5842    * Since: 1.10
5843    */
5844   obj_props[PROP_MARGIN_RIGHT] =
5845     g_param_spec_float ("margin-right",
5846                         P_("Margin Right"),
5847                         P_("Extra space at the right"),
5848                         0.0, G_MAXFLOAT,
5849                         0.0,
5850                         CLUTTER_PARAM_READWRITE);
5851
5852   /**
5853    * ClutterActor:background-color-set:
5854    *
5855    * Whether the #ClutterActor:background-color property has been set.
5856    *
5857    * Since: 1.10
5858    */
5859   obj_props[PROP_BACKGROUND_COLOR_SET] =
5860     g_param_spec_boolean ("background-color-set",
5861                           P_("Background Color Set"),
5862                           P_("Whether the background color is set"),
5863                           FALSE,
5864                           CLUTTER_PARAM_READABLE);
5865
5866   /**
5867    * ClutterActor:background-color:
5868    *
5869    * Paints a solid fill of the actor's allocation using the specified
5870    * color.
5871    *
5872    * Since: 1.10
5873    */
5874   obj_props[PROP_BACKGROUND_COLOR] =
5875     clutter_param_spec_color ("background-color",
5876                               P_("Background color"),
5877                               P_("The actor's background color"),
5878                               CLUTTER_COLOR_Transparent,
5879                               CLUTTER_PARAM_READWRITE);
5880
5881   /**
5882    * ClutterActor:first-child:
5883    *
5884    * The actor's first child.
5885    *
5886    * Since: 1.10
5887    */
5888   obj_props[PROP_FIRST_CHILD] =
5889     g_param_spec_object ("first-child",
5890                          P_("First Child"),
5891                          P_("The actor's first child"),
5892                          CLUTTER_TYPE_ACTOR,
5893                          CLUTTER_PARAM_READABLE);
5894
5895   /**
5896    * ClutterActor:last-child:
5897    *
5898    * The actor's last child.
5899    *
5900    * Since: 1.10
5901    */
5902   obj_props[PROP_LAST_CHILD] =
5903     g_param_spec_object ("last-child",
5904                          P_("Last Child"),
5905                          P_("The actor's last child"),
5906                          CLUTTER_TYPE_ACTOR,
5907                          CLUTTER_PARAM_READABLE);
5908
5909   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
5910
5911   /**
5912    * ClutterActor::destroy:
5913    * @actor: the #ClutterActor which emitted the signal
5914    *
5915    * The ::destroy signal notifies that all references held on the
5916    * actor which emitted it should be released.
5917    *
5918    * The ::destroy signal should be used by all holders of a reference
5919    * on @actor.
5920    *
5921    * This signal might result in the finalization of the #ClutterActor
5922    * if all references are released.
5923    *
5924    * Composite actors and actors implementing the #ClutterContainer
5925    * interface should override the default implementation of the
5926    * class handler of this signal and call clutter_actor_destroy() on
5927    * their children. When overriding the default class handler, it is
5928    * required to chain up to the parent's implementation.
5929    *
5930    * Since: 0.2
5931    */
5932   actor_signals[DESTROY] =
5933     g_signal_new (I_("destroy"),
5934                   G_TYPE_FROM_CLASS (object_class),
5935                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
5936                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
5937                   NULL, NULL,
5938                   _clutter_marshal_VOID__VOID,
5939                   G_TYPE_NONE, 0);
5940   /**
5941    * ClutterActor::show:
5942    * @actor: the object which received the signal
5943    *
5944    * The ::show signal is emitted when an actor is visible and
5945    * rendered on the stage.
5946    *
5947    * Since: 0.2
5948    */
5949   actor_signals[SHOW] =
5950     g_signal_new (I_("show"),
5951                   G_TYPE_FROM_CLASS (object_class),
5952                   G_SIGNAL_RUN_FIRST,
5953                   G_STRUCT_OFFSET (ClutterActorClass, show),
5954                   NULL, NULL,
5955                   _clutter_marshal_VOID__VOID,
5956                   G_TYPE_NONE, 0);
5957   /**
5958    * ClutterActor::hide:
5959    * @actor: the object which received the signal
5960    *
5961    * The ::hide signal is emitted when an actor is no longer rendered
5962    * on the stage.
5963    *
5964    * Since: 0.2
5965    */
5966   actor_signals[HIDE] =
5967     g_signal_new (I_("hide"),
5968                   G_TYPE_FROM_CLASS (object_class),
5969                   G_SIGNAL_RUN_FIRST,
5970                   G_STRUCT_OFFSET (ClutterActorClass, hide),
5971                   NULL, NULL,
5972                   _clutter_marshal_VOID__VOID,
5973                   G_TYPE_NONE, 0);
5974   /**
5975    * ClutterActor::parent-set:
5976    * @actor: the object which received the signal
5977    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
5978    *
5979    * This signal is emitted when the parent of the actor changes.
5980    *
5981    * Since: 0.2
5982    */
5983   actor_signals[PARENT_SET] =
5984     g_signal_new (I_("parent-set"),
5985                   G_TYPE_FROM_CLASS (object_class),
5986                   G_SIGNAL_RUN_LAST,
5987                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
5988                   NULL, NULL,
5989                   _clutter_marshal_VOID__OBJECT,
5990                   G_TYPE_NONE, 1,
5991                   CLUTTER_TYPE_ACTOR);
5992
5993   /**
5994    * ClutterActor::queue-redraw:
5995    * @actor: the actor we're bubbling the redraw request through
5996    * @origin: the actor which initiated the redraw request
5997    *
5998    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
5999    * is called on @origin.
6000    *
6001    * The default implementation for #ClutterActor chains up to the
6002    * parent actor and queues a redraw on the parent, thus "bubbling"
6003    * the redraw queue up through the actor graph. The default
6004    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6005    * in a main loop idle handler.
6006    *
6007    * Note that the @origin actor may be the stage, or a container; it
6008    * does not have to be a leaf node in the actor graph.
6009    *
6010    * Toolkits embedding a #ClutterStage which require a redraw and
6011    * relayout cycle can stop the emission of this signal using the
6012    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6013    * themselves, like:
6014    *
6015    * |[
6016    *   static void
6017    *   on_redraw_complete (gpointer data)
6018    *   {
6019    *     ClutterStage *stage = data;
6020    *
6021    *     /&ast; execute the Clutter drawing pipeline &ast;/
6022    *     clutter_stage_ensure_redraw (stage);
6023    *   }
6024    *
6025    *   static void
6026    *   on_stage_queue_redraw (ClutterStage *stage)
6027    *   {
6028    *     /&ast; this prevents the default handler to run &ast;/
6029    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6030    *
6031    *     /&ast; queue a redraw with the host toolkit and call
6032    *      &ast; a function when the redraw has been completed
6033    *      &ast;/
6034    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6035    *   }
6036    * ]|
6037    *
6038    * <note><para>This signal is emitted before the Clutter paint
6039    * pipeline is executed. If you want to know when the pipeline has
6040    * been completed you should connect to the ::paint signal on the
6041    * Stage with g_signal_connect_after().</para></note>
6042    *
6043    * Since: 1.0
6044    */
6045   actor_signals[QUEUE_REDRAW] =
6046     g_signal_new (I_("queue-redraw"),
6047                   G_TYPE_FROM_CLASS (object_class),
6048                   G_SIGNAL_RUN_LAST,
6049                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6050                   NULL, NULL,
6051                   _clutter_marshal_VOID__OBJECT,
6052                   G_TYPE_NONE, 1,
6053                   CLUTTER_TYPE_ACTOR);
6054
6055   /**
6056    * ClutterActor::queue-relayout
6057    * @actor: the actor being queued for relayout
6058    *
6059    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6060    * is called on an actor.
6061    *
6062    * The default implementation for #ClutterActor chains up to the
6063    * parent actor and queues a relayout on the parent, thus "bubbling"
6064    * the relayout queue up through the actor graph.
6065    *
6066    * The main purpose of this signal is to allow relayout to be propagated
6067    * properly in the procense of #ClutterClone actors. Applications will
6068    * not normally need to connect to this signal.
6069    *
6070    * Since: 1.2
6071    */
6072   actor_signals[QUEUE_RELAYOUT] =
6073     g_signal_new (I_("queue-relayout"),
6074                   G_TYPE_FROM_CLASS (object_class),
6075                   G_SIGNAL_RUN_LAST,
6076                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6077                   NULL, NULL,
6078                   _clutter_marshal_VOID__VOID,
6079                   G_TYPE_NONE, 0);
6080
6081   /**
6082    * ClutterActor::event:
6083    * @actor: the actor which received the event
6084    * @event: a #ClutterEvent
6085    *
6086    * The ::event signal is emitted each time an event is received
6087    * by the @actor. This signal will be emitted on every actor,
6088    * following the hierarchy chain, until it reaches the top-level
6089    * container (the #ClutterStage).
6090    *
6091    * Return value: %TRUE if the event has been handled by the actor,
6092    *   or %FALSE to continue the emission.
6093    *
6094    * Since: 0.6
6095    */
6096   actor_signals[EVENT] =
6097     g_signal_new (I_("event"),
6098                   G_TYPE_FROM_CLASS (object_class),
6099                   G_SIGNAL_RUN_LAST,
6100                   G_STRUCT_OFFSET (ClutterActorClass, event),
6101                   _clutter_boolean_handled_accumulator, NULL,
6102                   _clutter_marshal_BOOLEAN__BOXED,
6103                   G_TYPE_BOOLEAN, 1,
6104                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6105   /**
6106    * ClutterActor::button-press-event:
6107    * @actor: the actor which received the event
6108    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6109    *
6110    * The ::button-press-event signal is emitted each time a mouse button
6111    * is pressed on @actor.
6112    *
6113    * Return value: %TRUE if the event has been handled by the actor,
6114    *   or %FALSE to continue the emission.
6115    *
6116    * Since: 0.6
6117    */
6118   actor_signals[BUTTON_PRESS_EVENT] =
6119     g_signal_new (I_("button-press-event"),
6120                   G_TYPE_FROM_CLASS (object_class),
6121                   G_SIGNAL_RUN_LAST,
6122                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6123                   _clutter_boolean_handled_accumulator, NULL,
6124                   _clutter_marshal_BOOLEAN__BOXED,
6125                   G_TYPE_BOOLEAN, 1,
6126                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6127   /**
6128    * ClutterActor::button-release-event:
6129    * @actor: the actor which received the event
6130    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6131    *
6132    * The ::button-release-event signal is emitted each time a mouse button
6133    * is released on @actor.
6134    *
6135    * Return value: %TRUE if the event has been handled by the actor,
6136    *   or %FALSE to continue the emission.
6137    *
6138    * Since: 0.6
6139    */
6140   actor_signals[BUTTON_RELEASE_EVENT] =
6141     g_signal_new (I_("button-release-event"),
6142                   G_TYPE_FROM_CLASS (object_class),
6143                   G_SIGNAL_RUN_LAST,
6144                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6145                   _clutter_boolean_handled_accumulator, NULL,
6146                   _clutter_marshal_BOOLEAN__BOXED,
6147                   G_TYPE_BOOLEAN, 1,
6148                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6149   /**
6150    * ClutterActor::scroll-event:
6151    * @actor: the actor which received the event
6152    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6153    *
6154    * The ::scroll-event signal is emitted each time the mouse is
6155    * scrolled on @actor
6156    *
6157    * Return value: %TRUE if the event has been handled by the actor,
6158    *   or %FALSE to continue the emission.
6159    *
6160    * Since: 0.6
6161    */
6162   actor_signals[SCROLL_EVENT] =
6163     g_signal_new (I_("scroll-event"),
6164                   G_TYPE_FROM_CLASS (object_class),
6165                   G_SIGNAL_RUN_LAST,
6166                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6167                   _clutter_boolean_handled_accumulator, NULL,
6168                   _clutter_marshal_BOOLEAN__BOXED,
6169                   G_TYPE_BOOLEAN, 1,
6170                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6171   /**
6172    * ClutterActor::key-press-event:
6173    * @actor: the actor which received the event
6174    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6175    *
6176    * The ::key-press-event signal is emitted each time a keyboard button
6177    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6178    *
6179    * Return value: %TRUE if the event has been handled by the actor,
6180    *   or %FALSE to continue the emission.
6181    *
6182    * Since: 0.6
6183    */
6184   actor_signals[KEY_PRESS_EVENT] =
6185     g_signal_new (I_("key-press-event"),
6186                   G_TYPE_FROM_CLASS (object_class),
6187                   G_SIGNAL_RUN_LAST,
6188                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6189                   _clutter_boolean_handled_accumulator, NULL,
6190                   _clutter_marshal_BOOLEAN__BOXED,
6191                   G_TYPE_BOOLEAN, 1,
6192                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6193   /**
6194    * ClutterActor::key-release-event:
6195    * @actor: the actor which received the event
6196    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6197    *
6198    * The ::key-release-event signal is emitted each time a keyboard button
6199    * is released while @actor has key focus (see
6200    * clutter_stage_set_key_focus()).
6201    *
6202    * Return value: %TRUE if the event has been handled by the actor,
6203    *   or %FALSE to continue the emission.
6204    *
6205    * Since: 0.6
6206    */
6207   actor_signals[KEY_RELEASE_EVENT] =
6208     g_signal_new (I_("key-release-event"),
6209                   G_TYPE_FROM_CLASS (object_class),
6210                   G_SIGNAL_RUN_LAST,
6211                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6212                   _clutter_boolean_handled_accumulator, NULL,
6213                   _clutter_marshal_BOOLEAN__BOXED,
6214                   G_TYPE_BOOLEAN, 1,
6215                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6216   /**
6217    * ClutterActor::motion-event:
6218    * @actor: the actor which received the event
6219    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6220    *
6221    * The ::motion-event signal is emitted each time the mouse pointer is
6222    * moved over @actor.
6223    *
6224    * Return value: %TRUE if the event has been handled by the actor,
6225    *   or %FALSE to continue the emission.
6226    *
6227    * Since: 0.6
6228    */
6229   actor_signals[MOTION_EVENT] =
6230     g_signal_new (I_("motion-event"),
6231                   G_TYPE_FROM_CLASS (object_class),
6232                   G_SIGNAL_RUN_LAST,
6233                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6234                   _clutter_boolean_handled_accumulator, NULL,
6235                   _clutter_marshal_BOOLEAN__BOXED,
6236                   G_TYPE_BOOLEAN, 1,
6237                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6238
6239   /**
6240    * ClutterActor::key-focus-in:
6241    * @actor: the actor which now has key focus
6242    *
6243    * The ::key-focus-in signal is emitted when @actor receives key focus.
6244    *
6245    * Since: 0.6
6246    */
6247   actor_signals[KEY_FOCUS_IN] =
6248     g_signal_new (I_("key-focus-in"),
6249                   G_TYPE_FROM_CLASS (object_class),
6250                   G_SIGNAL_RUN_LAST,
6251                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6252                   NULL, NULL,
6253                   _clutter_marshal_VOID__VOID,
6254                   G_TYPE_NONE, 0);
6255
6256   /**
6257    * ClutterActor::key-focus-out:
6258    * @actor: the actor which now has key focus
6259    *
6260    * The ::key-focus-out signal is emitted when @actor loses key focus.
6261    *
6262    * Since: 0.6
6263    */
6264   actor_signals[KEY_FOCUS_OUT] =
6265     g_signal_new (I_("key-focus-out"),
6266                   G_TYPE_FROM_CLASS (object_class),
6267                   G_SIGNAL_RUN_LAST,
6268                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6269                   NULL, NULL,
6270                   _clutter_marshal_VOID__VOID,
6271                   G_TYPE_NONE, 0);
6272
6273   /**
6274    * ClutterActor::enter-event:
6275    * @actor: the actor which the pointer has entered.
6276    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6277    *
6278    * The ::enter-event signal is emitted when the pointer enters the @actor
6279    *
6280    * Return value: %TRUE if the event has been handled by the actor,
6281    *   or %FALSE to continue the emission.
6282    *
6283    * Since: 0.6
6284    */
6285   actor_signals[ENTER_EVENT] =
6286     g_signal_new (I_("enter-event"),
6287                   G_TYPE_FROM_CLASS (object_class),
6288                   G_SIGNAL_RUN_LAST,
6289                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6290                   _clutter_boolean_handled_accumulator, NULL,
6291                   _clutter_marshal_BOOLEAN__BOXED,
6292                   G_TYPE_BOOLEAN, 1,
6293                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6294
6295   /**
6296    * ClutterActor::leave-event:
6297    * @actor: the actor which the pointer has left
6298    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6299    *
6300    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6301    *
6302    * Return value: %TRUE if the event has been handled by the actor,
6303    *   or %FALSE to continue the emission.
6304    *
6305    * Since: 0.6
6306    */
6307   actor_signals[LEAVE_EVENT] =
6308     g_signal_new (I_("leave-event"),
6309                   G_TYPE_FROM_CLASS (object_class),
6310                   G_SIGNAL_RUN_LAST,
6311                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6312                   _clutter_boolean_handled_accumulator, NULL,
6313                   _clutter_marshal_BOOLEAN__BOXED,
6314                   G_TYPE_BOOLEAN, 1,
6315                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6316
6317   /**
6318    * ClutterActor::captured-event:
6319    * @actor: the actor which received the signal
6320    * @event: a #ClutterEvent
6321    *
6322    * The ::captured-event signal is emitted when an event is captured
6323    * by Clutter. This signal will be emitted starting from the top-level
6324    * container (the #ClutterStage) to the actor which received the event
6325    * going down the hierarchy. This signal can be used to intercept every
6326    * event before the specialized events (like
6327    * ClutterActor::button-press-event or ::key-released-event) are
6328    * emitted.
6329    *
6330    * Return value: %TRUE if the event has been handled by the actor,
6331    *   or %FALSE to continue the emission.
6332    *
6333    * Since: 0.6
6334    */
6335   actor_signals[CAPTURED_EVENT] =
6336     g_signal_new (I_("captured-event"),
6337                   G_TYPE_FROM_CLASS (object_class),
6338                   G_SIGNAL_RUN_LAST,
6339                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6340                   _clutter_boolean_handled_accumulator, NULL,
6341                   _clutter_marshal_BOOLEAN__BOXED,
6342                   G_TYPE_BOOLEAN, 1,
6343                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6344
6345   /**
6346    * ClutterActor::paint:
6347    * @actor: the #ClutterActor that received the signal
6348    *
6349    * The ::paint signal is emitted each time an actor is being painted.
6350    *
6351    * Subclasses of #ClutterActor should override the class signal handler
6352    * and paint themselves in that function.
6353    *
6354    * It is possible to connect a handler to the ::paint signal in order
6355    * to set up some custom aspect of a paint.
6356    *
6357    * Since: 0.8
6358    */
6359   actor_signals[PAINT] =
6360     g_signal_new (I_("paint"),
6361                   G_TYPE_FROM_CLASS (object_class),
6362                   G_SIGNAL_RUN_LAST,
6363                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6364                   NULL, NULL,
6365                   _clutter_marshal_VOID__VOID,
6366                   G_TYPE_NONE, 0);
6367   /**
6368    * ClutterActor::realize:
6369    * @actor: the #ClutterActor that received the signal
6370    *
6371    * The ::realize signal is emitted each time an actor is being
6372    * realized.
6373    *
6374    * Since: 0.8
6375    */
6376   actor_signals[REALIZE] =
6377     g_signal_new (I_("realize"),
6378                   G_TYPE_FROM_CLASS (object_class),
6379                   G_SIGNAL_RUN_LAST,
6380                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6381                   NULL, NULL,
6382                   _clutter_marshal_VOID__VOID,
6383                   G_TYPE_NONE, 0);
6384   /**
6385    * ClutterActor::unrealize:
6386    * @actor: the #ClutterActor that received the signal
6387    *
6388    * The ::unrealize signal is emitted each time an actor is being
6389    * unrealized.
6390    *
6391    * Since: 0.8
6392    */
6393   actor_signals[UNREALIZE] =
6394     g_signal_new (I_("unrealize"),
6395                   G_TYPE_FROM_CLASS (object_class),
6396                   G_SIGNAL_RUN_LAST,
6397                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6398                   NULL, NULL,
6399                   _clutter_marshal_VOID__VOID,
6400                   G_TYPE_NONE, 0);
6401
6402   /**
6403    * ClutterActor::pick:
6404    * @actor: the #ClutterActor that received the signal
6405    * @color: the #ClutterColor to be used when picking
6406    *
6407    * The ::pick signal is emitted each time an actor is being painted
6408    * in "pick mode". The pick mode is used to identify the actor during
6409    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6410    * The actor should paint its shape using the passed @pick_color.
6411    *
6412    * Subclasses of #ClutterActor should override the class signal handler
6413    * and paint themselves in that function.
6414    *
6415    * It is possible to connect a handler to the ::pick signal in order
6416    * to set up some custom aspect of a paint in pick mode.
6417    *
6418    * Since: 1.0
6419    */
6420   actor_signals[PICK] =
6421     g_signal_new (I_("pick"),
6422                   G_TYPE_FROM_CLASS (object_class),
6423                   G_SIGNAL_RUN_LAST,
6424                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6425                   NULL, NULL,
6426                   _clutter_marshal_VOID__BOXED,
6427                   G_TYPE_NONE, 1,
6428                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6429
6430   /**
6431    * ClutterActor::allocation-changed:
6432    * @actor: the #ClutterActor that emitted the signal
6433    * @box: a #ClutterActorBox with the new allocation
6434    * @flags: #ClutterAllocationFlags for the allocation
6435    *
6436    * The ::allocation-changed signal is emitted when the
6437    * #ClutterActor:allocation property changes. Usually, application
6438    * code should just use the notifications for the :allocation property
6439    * but if you want to track the allocation flags as well, for instance
6440    * to know whether the absolute origin of @actor changed, then you might
6441    * want use this signal instead.
6442    *
6443    * Since: 1.0
6444    */
6445   actor_signals[ALLOCATION_CHANGED] =
6446     g_signal_new (I_("allocation-changed"),
6447                   G_TYPE_FROM_CLASS (object_class),
6448                   G_SIGNAL_RUN_LAST,
6449                   0,
6450                   NULL, NULL,
6451                   _clutter_marshal_VOID__BOXED_FLAGS,
6452                   G_TYPE_NONE, 2,
6453                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6454                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6455 }
6456
6457 static void
6458 clutter_actor_init (ClutterActor *self)
6459 {
6460   ClutterActorPrivate *priv;
6461
6462   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6463
6464   priv->id = _clutter_context_acquire_id (self);
6465   priv->pick_id = -1;
6466
6467   priv->opacity = 0xff;
6468   priv->show_on_set_parent = TRUE;
6469
6470   priv->needs_width_request = TRUE;
6471   priv->needs_height_request = TRUE;
6472   priv->needs_allocation = TRUE;
6473
6474   priv->cached_width_age = 1;
6475   priv->cached_height_age = 1;
6476
6477   priv->opacity_override = -1;
6478   priv->enable_model_view_transform = TRUE;
6479
6480   /* Initialize an empty paint volume to start with */
6481   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6482   priv->last_paint_volume_valid = TRUE;
6483
6484   priv->transform_valid = FALSE;
6485 }
6486
6487 /**
6488  * clutter_actor_new:
6489  *
6490  * Creates a new #ClutterActor.
6491  *
6492  * A newly created actor has a floating reference, which will be sunk
6493  * when it is added to another actor.
6494  *
6495  * Return value: (transfer full): the newly created #ClutterActor
6496  *
6497  * Since: 1.10
6498  */
6499 ClutterActor *
6500 clutter_actor_new (void)
6501 {
6502   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6503 }
6504
6505 /**
6506  * clutter_actor_destroy:
6507  * @self: a #ClutterActor
6508  *
6509  * Destroys an actor.  When an actor is destroyed, it will break any
6510  * references it holds to other objects.  If the actor is inside a
6511  * container, the actor will be removed.
6512  *
6513  * When you destroy a container, its children will be destroyed as well.
6514  *
6515  * Note: you cannot destroy the #ClutterStage returned by
6516  * clutter_stage_get_default().
6517  */
6518 void
6519 clutter_actor_destroy (ClutterActor *self)
6520 {
6521   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6522
6523   g_object_ref (self);
6524
6525   /* avoid recursion while destroying */
6526   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6527     {
6528       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6529
6530       g_object_run_dispose (G_OBJECT (self));
6531
6532       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6533     }
6534
6535   g_object_unref (self);
6536 }
6537
6538 void
6539 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6540                                     ClutterPaintVolume *clip)
6541 {
6542   ClutterActorPrivate *priv = self->priv;
6543   ClutterPaintVolume *pv;
6544   gboolean clipped;
6545
6546   /* Remove queue entry early in the process, otherwise a new
6547      queue_redraw() during signal handling could put back this
6548      object in the stage redraw list (but the entry is freed as
6549      soon as we return from this function, causing a segfault
6550      later)
6551   */
6552   priv->queue_redraw_entry = NULL;
6553
6554   /* If we've been explicitly passed a clip volume then there's
6555    * nothing more to calculate, but otherwise the only thing we know
6556    * is that the change is constrained to the given actor.
6557    *
6558    * The idea is that if we know the paint volume for where the actor
6559    * was last drawn (in eye coordinates) and we also have the paint
6560    * volume for where it will be drawn next (in actor coordinates)
6561    * then if we queue a redraw for both these volumes that will cover
6562    * everything that needs to be redrawn to clear the old view and
6563    * show the latest view of the actor.
6564    *
6565    * Don't clip this redraw if we don't know what position we had for
6566    * the previous redraw since we don't know where to set the clip so
6567    * it will clear the actor as it is currently.
6568    */
6569   if (clip)
6570     {
6571       _clutter_actor_set_queue_redraw_clip (self, clip);
6572       clipped = TRUE;
6573     }
6574   else if (G_LIKELY (priv->last_paint_volume_valid))
6575     {
6576       pv = _clutter_actor_get_paint_volume_mutable (self);
6577       if (pv)
6578         {
6579           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6580
6581           /* make sure we redraw the actors old position... */
6582           _clutter_actor_set_queue_redraw_clip (stage,
6583                                                 &priv->last_paint_volume);
6584           _clutter_actor_signal_queue_redraw (stage, stage);
6585           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6586
6587           /* XXX: Ideally the redraw signal would take a clip volume
6588            * argument, but that would be an ABI break. Until we can
6589            * break the ABI we pass the argument out-of-band
6590            */
6591
6592           /* setup the clip for the actors new position... */
6593           _clutter_actor_set_queue_redraw_clip (self, pv);
6594           clipped = TRUE;
6595         }
6596       else
6597         clipped = FALSE;
6598     }
6599   else
6600     clipped = FALSE;
6601
6602   _clutter_actor_signal_queue_redraw (self, self);
6603
6604   /* Just in case anyone is manually firing redraw signals without
6605    * using the public queue_redraw() API we are careful to ensure that
6606    * our out-of-band clip member is cleared before returning...
6607    *
6608    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6609    */
6610   if (G_LIKELY (clipped))
6611     _clutter_actor_set_queue_redraw_clip (self, NULL);
6612 }
6613
6614 static void
6615 _clutter_actor_get_allocation_clip (ClutterActor *self,
6616                                     ClutterActorBox *clip)
6617 {
6618   ClutterActorBox allocation;
6619
6620   /* XXX: we don't care if we get an out of date allocation here
6621    * because clutter_actor_queue_redraw_with_clip knows to ignore
6622    * the clip if the actor's allocation is invalid.
6623    *
6624    * This is noted because clutter_actor_get_allocation_box does some
6625    * unnecessary work to support buggy code with a comment suggesting
6626    * that it could be changed later which would be good for this use
6627    * case!
6628    */
6629   clutter_actor_get_allocation_box (self, &allocation);
6630
6631   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6632    * actor's own coordinate space but the allocation is in parent
6633    * coordinates */
6634   clip->x1 = 0;
6635   clip->y1 = 0;
6636   clip->x2 = allocation.x2 - allocation.x1;
6637   clip->y2 = allocation.y2 - allocation.y1;
6638 }
6639
6640 void
6641 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6642                                   ClutterRedrawFlags  flags,
6643                                   ClutterPaintVolume *volume,
6644                                   ClutterEffect      *effect)
6645 {
6646   ClutterActorPrivate *priv = self->priv;
6647   ClutterPaintVolume allocation_pv;
6648   ClutterPaintVolume *pv;
6649   gboolean should_free_pv;
6650   ClutterActor *stage;
6651
6652   /* Here's an outline of the actor queue redraw mechanism:
6653    *
6654    * The process starts in one of the following two functions which
6655    * are wrappers for this function:
6656    * clutter_actor_queue_redraw
6657    * _clutter_actor_queue_redraw_with_clip
6658    *
6659    * additionally, an effect can queue a redraw by wrapping this
6660    * function in clutter_effect_queue_rerun
6661    *
6662    * This functions queues an entry in a list associated with the
6663    * stage which is a list of actors that queued a redraw while
6664    * updating the timelines, performing layouting and processing other
6665    * mainloop sources before the next paint starts.
6666    *
6667    * We aim to minimize the processing done at this point because
6668    * there is a good chance other events will happen while updating
6669    * the scenegraph that would invalidate any expensive work we might
6670    * otherwise try to do here. For example we don't try and resolve
6671    * the screen space bounding box of an actor at this stage so as to
6672    * minimize how much of the screen redraw because it's possible
6673    * something else will happen which will force a full redraw anyway.
6674    *
6675    * When all updates are complete and we come to paint the stage then
6676    * we iterate this list and actually emit the "queue-redraw" signals
6677    * for each of the listed actors which will bubble up to the stage
6678    * for each actor and at that point we will transform the actors
6679    * paint volume into screen coordinates to determine the clip region
6680    * for what needs to be redrawn in the next paint.
6681    *
6682    * Besides minimizing redundant work another reason for this
6683    * deferred design is that it's more likely we will be able to
6684    * determine the paint volume of an actor once we've finished
6685    * updating the scenegraph because its allocation should be up to
6686    * date. NB: If we can't determine an actors paint volume then we
6687    * can't automatically queue a clipped redraw which can make a big
6688    * difference to performance.
6689    *
6690    * So the control flow goes like this:
6691    * One of clutter_actor_queue_redraw,
6692    *        _clutter_actor_queue_redraw_with_clip
6693    *     or clutter_effect_queue_rerun
6694    *
6695    * then control moves to:
6696    *   _clutter_stage_queue_actor_redraw
6697    *
6698    * later during _clutter_stage_do_update, once relayouting is done
6699    * and the scenegraph has been updated we will call:
6700    * _clutter_stage_finish_queue_redraws
6701    *
6702    * _clutter_stage_finish_queue_redraws will call
6703    * _clutter_actor_finish_queue_redraw for each listed actor.
6704    * Note: actors *are* allowed to queue further redraws during this
6705    * process (considering clone actors or texture_new_from_actor which
6706    * respond to their source queueing a redraw by queuing a redraw
6707    * themselves). We repeat the process until the list is empty.
6708    *
6709    * This will result in the "queue-redraw" signal being fired for
6710    * each actor which will pass control to the default signal handler:
6711    * clutter_actor_real_queue_redraw
6712    *
6713    * This will bubble up to the stages handler:
6714    * clutter_stage_real_queue_redraw
6715    *
6716    * clutter_stage_real_queue_redraw will transform the actors paint
6717    * volume into screen space and add it as a clip region for the next
6718    * paint.
6719    */
6720
6721   /* ignore queueing a redraw for actors being destroyed */
6722   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6723     return;
6724
6725   stage = _clutter_actor_get_stage_internal (self);
6726
6727   /* Ignore queueing a redraw for actors not descended from a stage */
6728   if (stage == NULL)
6729     return;
6730
6731   /* ignore queueing a redraw on stages that are being destroyed */
6732   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6733     return;
6734
6735   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6736     {
6737       ClutterActorBox allocation_clip;
6738       ClutterVertex origin;
6739
6740       /* If the actor doesn't have a valid allocation then we will
6741        * queue a full stage redraw. */
6742       if (priv->needs_allocation)
6743         {
6744           /* NB: NULL denotes an undefined clip which will result in a
6745            * full redraw... */
6746           _clutter_actor_set_queue_redraw_clip (self, NULL);
6747           _clutter_actor_signal_queue_redraw (self, self);
6748           return;
6749         }
6750
6751       _clutter_paint_volume_init_static (&allocation_pv, self);
6752       pv = &allocation_pv;
6753
6754       _clutter_actor_get_allocation_clip (self, &allocation_clip);
6755
6756       origin.x = allocation_clip.x1;
6757       origin.y = allocation_clip.y1;
6758       origin.z = 0;
6759       clutter_paint_volume_set_origin (pv, &origin);
6760       clutter_paint_volume_set_width (pv,
6761                                       allocation_clip.x2 - allocation_clip.x1);
6762       clutter_paint_volume_set_height (pv,
6763                                        allocation_clip.y2 -
6764                                        allocation_clip.y1);
6765       should_free_pv = TRUE;
6766     }
6767   else
6768     {
6769       pv = volume;
6770       should_free_pv = FALSE;
6771     }
6772
6773   self->priv->queue_redraw_entry =
6774     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6775                                        priv->queue_redraw_entry,
6776                                        self,
6777                                        pv);
6778
6779   if (should_free_pv)
6780     clutter_paint_volume_free (pv);
6781
6782   /* If this is the first redraw queued then we can directly use the
6783      effect parameter */
6784   if (!priv->is_dirty)
6785     priv->effect_to_redraw = effect;
6786   /* Otherwise we need to merge it with the existing effect parameter */
6787   else if (effect != NULL)
6788     {
6789       /* If there's already an effect then we need to use whichever is
6790          later in the chain of actors. Otherwise a full redraw has
6791          already been queued on the actor so we need to ignore the
6792          effect parameter */
6793       if (priv->effect_to_redraw != NULL)
6794         {
6795           if (priv->effects == NULL)
6796             g_warning ("Redraw queued with an effect that is "
6797                        "not applied to the actor");
6798           else
6799             {
6800               const GList *l;
6801
6802               for (l = _clutter_meta_group_peek_metas (priv->effects);
6803                    l != NULL;
6804                    l = l->next)
6805                 {
6806                   if (l->data == priv->effect_to_redraw ||
6807                       l->data == effect)
6808                     priv->effect_to_redraw = l->data;
6809                 }
6810             }
6811         }
6812     }
6813   else
6814     {
6815       /* If no effect is specified then we need to redraw the whole
6816          actor */
6817       priv->effect_to_redraw = NULL;
6818     }
6819
6820   priv->is_dirty = TRUE;
6821 }
6822
6823 /**
6824  * clutter_actor_queue_redraw:
6825  * @self: A #ClutterActor
6826  *
6827  * Queues up a redraw of an actor and any children. The redraw occurs
6828  * once the main loop becomes idle (after the current batch of events
6829  * has been processed, roughly).
6830  *
6831  * Applications rarely need to call this, as redraws are handled
6832  * automatically by modification functions.
6833  *
6834  * This function will not do anything if @self is not visible, or
6835  * if the actor is inside an invisible part of the scenegraph.
6836  *
6837  * Also be aware that painting is a NOP for actors with an opacity of
6838  * 0
6839  *
6840  * When you are implementing a custom actor you must queue a redraw
6841  * whenever some private state changes that will affect painting or
6842  * picking of your actor.
6843  */
6844 void
6845 clutter_actor_queue_redraw (ClutterActor *self)
6846 {
6847   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6848
6849   _clutter_actor_queue_redraw_full (self,
6850                                     0, /* flags */
6851                                     NULL, /* clip volume */
6852                                     NULL /* effect */);
6853 }
6854
6855 /*< private >
6856  * _clutter_actor_queue_redraw_with_clip:
6857  * @self: A #ClutterActor
6858  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
6859  *   this queue redraw.
6860  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
6861  *   redrawn or %NULL if you are just using a @flag to state your
6862  *   desired clipping.
6863  *
6864  * Queues up a clipped redraw of an actor and any children. The redraw
6865  * occurs once the main loop becomes idle (after the current batch of
6866  * events has been processed, roughly).
6867  *
6868  * If no flags are given the clip volume is defined by @volume
6869  * specified in actor coordinates and tells Clutter that only content
6870  * within this volume has been changed so Clutter can optionally
6871  * optimize the redraw.
6872  *
6873  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
6874  * should be %NULL and this tells Clutter to use the actor's current
6875  * allocation as a clip box. This flag can only be used for 2D actors,
6876  * because any actor with depth may be projected outside its
6877  * allocation.
6878  *
6879  * Applications rarely need to call this, as redraws are handled
6880  * automatically by modification functions.
6881  *
6882  * This function will not do anything if @self is not visible, or if
6883  * the actor is inside an invisible part of the scenegraph.
6884  *
6885  * Also be aware that painting is a NOP for actors with an opacity of
6886  * 0
6887  *
6888  * When you are implementing a custom actor you must queue a redraw
6889  * whenever some private state changes that will affect painting or
6890  * picking of your actor.
6891  */
6892 void
6893 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
6894                                        ClutterRedrawFlags  flags,
6895                                        ClutterPaintVolume *volume)
6896 {
6897   _clutter_actor_queue_redraw_full (self,
6898                                     flags, /* flags */
6899                                     volume, /* clip volume */
6900                                     NULL /* effect */);
6901 }
6902
6903 static void
6904 _clutter_actor_queue_only_relayout (ClutterActor *self)
6905 {
6906   ClutterActorPrivate *priv = self->priv;
6907
6908   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6909     return;
6910
6911   if (priv->needs_width_request &&
6912       priv->needs_height_request &&
6913       priv->needs_allocation)
6914     return; /* save some cpu cycles */
6915
6916 #if CLUTTER_ENABLE_DEBUG
6917   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
6918     {
6919       g_warning ("The actor '%s' is currently inside an allocation "
6920                  "cycle; calling clutter_actor_queue_relayout() is "
6921                  "not recommended",
6922                  _clutter_actor_get_debug_name (self));
6923     }
6924 #endif /* CLUTTER_ENABLE_DEBUG */
6925
6926   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
6927 }
6928
6929 /**
6930  * clutter_actor_queue_redraw_with_clip:
6931  * @self: a #ClutterActor
6932  * @clip: (allow-none): a rectangular clip region, or %NULL
6933  *
6934  * Queues a redraw on @self limited to a specific, actor-relative
6935  * rectangular area.
6936  *
6937  * If @clip is %NULL this function is equivalent to
6938  * clutter_actor_queue_redraw().
6939  *
6940  * Since: 1.10
6941  */
6942 void
6943 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
6944                                       const cairo_rectangle_int_t *clip)
6945 {
6946   ClutterPaintVolume volume;
6947   ClutterVertex origin;
6948
6949   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6950
6951   if (clip == NULL)
6952     {
6953       clutter_actor_queue_redraw (self);
6954       return;
6955     }
6956
6957   _clutter_paint_volume_init_static (&volume, self);
6958
6959   origin.x = clip->x;
6960   origin.y = clip->y;
6961   origin.z = 0.0f;
6962
6963   clutter_paint_volume_set_origin (&volume, &origin);
6964   clutter_paint_volume_set_width (&volume, clip->width);
6965   clutter_paint_volume_set_height (&volume, clip->height);
6966
6967   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
6968
6969   clutter_paint_volume_free (&volume);
6970 }
6971
6972 /**
6973  * clutter_actor_queue_relayout:
6974  * @self: A #ClutterActor
6975  *
6976  * Indicates that the actor's size request or other layout-affecting
6977  * properties may have changed. This function is used inside #ClutterActor
6978  * subclass implementations, not by applications directly.
6979  *
6980  * Queueing a new layout automatically queues a redraw as well.
6981  *
6982  * Since: 0.8
6983  */
6984 void
6985 clutter_actor_queue_relayout (ClutterActor *self)
6986 {
6987   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6988
6989   _clutter_actor_queue_only_relayout (self);
6990   clutter_actor_queue_redraw (self);
6991 }
6992
6993 /**
6994  * clutter_actor_get_preferred_size:
6995  * @self: a #ClutterActor
6996  * @min_width_p: (out) (allow-none): return location for the minimum
6997  *   width, or %NULL
6998  * @min_height_p: (out) (allow-none): return location for the minimum
6999  *   height, or %NULL
7000  * @natural_width_p: (out) (allow-none): return location for the natural
7001  *   width, or %NULL
7002  * @natural_height_p: (out) (allow-none): return location for the natural
7003  *   height, or %NULL
7004  *
7005  * Computes the preferred minimum and natural size of an actor, taking into
7006  * account the actor's geometry management (either height-for-width
7007  * or width-for-height).
7008  *
7009  * The width and height used to compute the preferred height and preferred
7010  * width are the actor's natural ones.
7011  *
7012  * If you need to control the height for the preferred width, or the width for
7013  * the preferred height, you should use clutter_actor_get_preferred_width()
7014  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7015  * geometry management using the #ClutterActor:request-mode property.
7016  *
7017  * Since: 0.8
7018  */
7019 void
7020 clutter_actor_get_preferred_size (ClutterActor *self,
7021                                   gfloat       *min_width_p,
7022                                   gfloat       *min_height_p,
7023                                   gfloat       *natural_width_p,
7024                                   gfloat       *natural_height_p)
7025 {
7026   ClutterActorPrivate *priv;
7027   gfloat min_width, min_height;
7028   gfloat natural_width, natural_height;
7029
7030   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7031
7032   priv = self->priv;
7033
7034   min_width = min_height = 0;
7035   natural_width = natural_height = 0;
7036
7037   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7038     {
7039       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7040       clutter_actor_get_preferred_width (self, -1,
7041                                          &min_width,
7042                                          &natural_width);
7043       clutter_actor_get_preferred_height (self, natural_width,
7044                                           &min_height,
7045                                           &natural_height);
7046     }
7047   else
7048     {
7049       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7050       clutter_actor_get_preferred_height (self, -1,
7051                                           &min_height,
7052                                           &natural_height);
7053       clutter_actor_get_preferred_width (self, natural_height,
7054                                          &min_width,
7055                                          &natural_width);
7056     }
7057
7058   if (min_width_p)
7059     *min_width_p = min_width;
7060
7061   if (min_height_p)
7062     *min_height_p = min_height;
7063
7064   if (natural_width_p)
7065     *natural_width_p = natural_width;
7066
7067   if (natural_height_p)
7068     *natural_height_p = natural_height;
7069 }
7070
7071 /*< private >
7072  * effective_align:
7073  * @align: a #ClutterActorAlign
7074  * @direction: a #ClutterTextDirection
7075  *
7076  * Retrieves the correct alignment depending on the text direction
7077  *
7078  * Return value: the effective alignment
7079  */
7080 static ClutterActorAlign
7081 effective_align (ClutterActorAlign    align,
7082                  ClutterTextDirection direction)
7083 {
7084   ClutterActorAlign res;
7085
7086   switch (align)
7087     {
7088     case CLUTTER_ACTOR_ALIGN_START:
7089       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7090           ? CLUTTER_ACTOR_ALIGN_END
7091           : CLUTTER_ACTOR_ALIGN_START;
7092       break;
7093
7094     case CLUTTER_ACTOR_ALIGN_END:
7095       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7096           ? CLUTTER_ACTOR_ALIGN_START
7097           : CLUTTER_ACTOR_ALIGN_END;
7098       break;
7099
7100     default:
7101       res = align;
7102       break;
7103     }
7104
7105   return res;
7106 }
7107
7108 static inline void
7109 adjust_for_margin (float  margin_start,
7110                    float  margin_end,
7111                    float *minimum_size,
7112                    float *natural_size,
7113                    float *allocated_start,
7114                    float *allocated_end)
7115 {
7116   *minimum_size -= (margin_start + margin_end);
7117   *natural_size -= (margin_start + margin_end);
7118   *allocated_start += margin_start;
7119   *allocated_end -= margin_end;
7120 }
7121
7122 static inline void
7123 adjust_for_alignment (ClutterActorAlign  alignment,
7124                       float              natural_size,
7125                       float             *allocated_start,
7126                       float             *allocated_end)
7127 {
7128   float allocated_size = *allocated_end - *allocated_start;
7129
7130   switch (alignment)
7131     {
7132     case CLUTTER_ACTOR_ALIGN_FILL:
7133       /* do nothing */
7134       break;
7135
7136     case CLUTTER_ACTOR_ALIGN_START:
7137       /* keep start */
7138       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7139       break;
7140
7141     case CLUTTER_ACTOR_ALIGN_END:
7142       if (allocated_size > natural_size)
7143         {
7144           *allocated_start += (allocated_size - natural_size);
7145           *allocated_end = *allocated_start + natural_size;
7146         }
7147       break;
7148
7149     case CLUTTER_ACTOR_ALIGN_CENTER:
7150       if (allocated_size > natural_size)
7151         {
7152           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7153           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7154         }
7155       break;
7156     }
7157 }
7158
7159 /*< private >
7160  * clutter_actor_adjust_width:
7161  * @self: a #ClutterActor
7162  * @minimum_width: (inout): the actor's preferred minimum width, which
7163  *   will be adjusted depending on the margin
7164  * @natural_width: (inout): the actor's preferred natural width, which
7165  *   will be adjusted depending on the margin
7166  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7167  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7168  *
7169  * Adjusts the preferred and allocated position and size of an actor,
7170  * depending on the margin and alignment properties.
7171  */
7172 static void
7173 clutter_actor_adjust_width (ClutterActor *self,
7174                             gfloat       *minimum_width,
7175                             gfloat       *natural_width,
7176                             gfloat       *adjusted_x1,
7177                             gfloat       *adjusted_x2)
7178 {
7179   ClutterTextDirection text_dir;
7180   const ClutterLayoutInfo *info;
7181
7182   info = _clutter_actor_get_layout_info_or_defaults (self);
7183   text_dir = clutter_actor_get_text_direction (self);
7184
7185   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7186
7187   /* this will tweak natural_width to remove the margin, so that
7188    * adjust_for_alignment() will use the correct size
7189    */
7190   adjust_for_margin (info->margin.left, info->margin.right,
7191                      minimum_width, natural_width,
7192                      adjusted_x1, adjusted_x2);
7193
7194   adjust_for_alignment (effective_align (info->x_align, text_dir),
7195                         *natural_width,
7196                         adjusted_x1, adjusted_x2);
7197 }
7198
7199 /*< private >
7200  * clutter_actor_adjust_height:
7201  * @self: a #ClutterActor
7202  * @minimum_height: (inout): the actor's preferred minimum height, which
7203  *   will be adjusted depending on the margin
7204  * @natural_height: (inout): the actor's preferred natural height, which
7205  *   will be adjusted depending on the margin
7206  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7207  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7208  *
7209  * Adjusts the preferred and allocated position and size of an actor,
7210  * depending on the margin and alignment properties.
7211  */
7212 static void
7213 clutter_actor_adjust_height (ClutterActor *self,
7214                              gfloat       *minimum_height,
7215                              gfloat       *natural_height,
7216                              gfloat       *adjusted_y1,
7217                              gfloat       *adjusted_y2)
7218 {
7219   const ClutterLayoutInfo *info;
7220
7221   info = _clutter_actor_get_layout_info_or_defaults (self);
7222
7223   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7224
7225   /* this will tweak natural_height to remove the margin, so that
7226    * adjust_for_alignment() will use the correct size
7227    */
7228   adjust_for_margin (info->margin.top, info->margin.bottom,
7229                      minimum_height, natural_height,
7230                      adjusted_y1,
7231                      adjusted_y2);
7232
7233   /* we don't use effective_align() here, because text direction
7234    * only affects the horizontal axis
7235    */
7236   adjust_for_alignment (info->y_align,
7237                         *natural_height,
7238                         adjusted_y1,
7239                         adjusted_y2);
7240
7241 }
7242
7243 /* looks for a cached size request for this for_size. If not
7244  * found, returns the oldest entry so it can be overwritten */
7245 static gboolean
7246 _clutter_actor_get_cached_size_request (gfloat         for_size,
7247                                         SizeRequest   *cached_size_requests,
7248                                         SizeRequest  **result)
7249 {
7250   guint i;
7251
7252   *result = &cached_size_requests[0];
7253
7254   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7255     {
7256       SizeRequest *sr;
7257
7258       sr = &cached_size_requests[i];
7259
7260       if (sr->age > 0 &&
7261           sr->for_size == for_size)
7262         {
7263           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7264           *result = sr;
7265           return TRUE;
7266         }
7267       else if (sr->age < (*result)->age)
7268         {
7269           *result = sr;
7270         }
7271     }
7272
7273   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7274
7275   return FALSE;
7276 }
7277
7278 /**
7279  * clutter_actor_get_preferred_width:
7280  * @self: A #ClutterActor
7281  * @for_height: available height when computing the preferred width,
7282  *   or a negative value to indicate that no height is defined
7283  * @min_width_p: (out) (allow-none): return location for minimum width,
7284  *   or %NULL
7285  * @natural_width_p: (out) (allow-none): return location for the natural
7286  *   width, or %NULL
7287  *
7288  * Computes the requested minimum and natural widths for an actor,
7289  * optionally depending on the specified height, or if they are
7290  * already computed, returns the cached values.
7291  *
7292  * An actor may not get its request - depending on the layout
7293  * manager that's in effect.
7294  *
7295  * A request should not incorporate the actor's scale or anchor point;
7296  * those transformations do not affect layout, only rendering.
7297  *
7298  * Since: 0.8
7299  */
7300 void
7301 clutter_actor_get_preferred_width (ClutterActor *self,
7302                                    gfloat        for_height,
7303                                    gfloat       *min_width_p,
7304                                    gfloat       *natural_width_p)
7305 {
7306   float request_min_width, request_natural_width;
7307   SizeRequest *cached_size_request;
7308   const ClutterLayoutInfo *info;
7309   ClutterActorPrivate *priv;
7310   gboolean found_in_cache;
7311
7312   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7313
7314   priv = self->priv;
7315
7316   info = _clutter_actor_get_layout_info_or_defaults (self);
7317
7318   /* we shortcircuit the case of a fixed size set using set_width() */
7319   if (priv->min_width_set && priv->natural_width_set)
7320     {
7321       if (min_width_p != NULL)
7322         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7323
7324       if (natural_width_p != NULL)
7325         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7326
7327       return;
7328     }
7329
7330   /* the remaining cases are:
7331    *
7332    *   - either min_width or natural_width have been set
7333    *   - neither min_width or natural_width have been set
7334    *
7335    * in both cases, we go through the cache (and through the actor in case
7336    * of cache misses) and determine the authoritative value depending on
7337    * the *_set flags.
7338    */
7339
7340   if (!priv->needs_width_request)
7341     {
7342       found_in_cache =
7343         _clutter_actor_get_cached_size_request (for_height,
7344                                                 priv->width_requests,
7345                                                 &cached_size_request);
7346     }
7347   else
7348     {
7349       /* if the actor needs a width request we use the first slot */
7350       found_in_cache = FALSE;
7351       cached_size_request = &priv->width_requests[0];
7352     }
7353
7354   if (!found_in_cache)
7355     {
7356       gfloat minimum_width, natural_width;
7357       ClutterActorClass *klass;
7358
7359       minimum_width = natural_width = 0;
7360
7361       /* adjust for the margin */
7362       if (for_height >= 0)
7363         {
7364           for_height -= (info->margin.top + info->margin.bottom);
7365           if (for_height < 0)
7366             for_height = 0;
7367         }
7368
7369       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7370
7371       klass = CLUTTER_ACTOR_GET_CLASS (self);
7372       klass->get_preferred_width (self, for_height,
7373                                   &minimum_width,
7374                                   &natural_width);
7375
7376       /* adjust for the margin */
7377       minimum_width += (info->margin.left + info->margin.right);
7378       natural_width += (info->margin.left + info->margin.right);
7379
7380       /* Due to accumulated float errors, it's better not to warn
7381        * on this, but just fix it.
7382        */
7383       if (natural_width < minimum_width)
7384         natural_width = minimum_width;
7385
7386       cached_size_request->min_size = minimum_width;
7387       cached_size_request->natural_size = natural_width;
7388       cached_size_request->for_size = for_height;
7389       cached_size_request->age = priv->cached_width_age;
7390
7391       priv->cached_width_age += 1;
7392       priv->needs_width_request = FALSE;
7393     }
7394
7395   if (!priv->min_width_set)
7396     request_min_width = cached_size_request->min_size;
7397   else
7398     request_min_width = info->min_width;
7399
7400   if (!priv->natural_width_set)
7401     request_natural_width = cached_size_request->natural_size;
7402   else
7403     request_natural_width = info->natural_width;
7404
7405   if (min_width_p)
7406     *min_width_p = request_min_width;
7407
7408   if (natural_width_p)
7409     *natural_width_p = request_natural_width;
7410 }
7411
7412 /**
7413  * clutter_actor_get_preferred_height:
7414  * @self: A #ClutterActor
7415  * @for_width: available width to assume in computing desired height,
7416  *   or a negative value to indicate that no width is defined
7417  * @min_height_p: (out) (allow-none): return location for minimum height,
7418  *   or %NULL
7419  * @natural_height_p: (out) (allow-none): return location for natural
7420  *   height, or %NULL
7421  *
7422  * Computes the requested minimum and natural heights for an actor,
7423  * or if they are already computed, returns the cached values.
7424  *
7425  * An actor may not get its request - depending on the layout
7426  * manager that's in effect.
7427  *
7428  * A request should not incorporate the actor's scale or anchor point;
7429  * those transformations do not affect layout, only rendering.
7430  *
7431  * Since: 0.8
7432  */
7433 void
7434 clutter_actor_get_preferred_height (ClutterActor *self,
7435                                     gfloat        for_width,
7436                                     gfloat       *min_height_p,
7437                                     gfloat       *natural_height_p)
7438 {
7439   float request_min_height, request_natural_height;
7440   SizeRequest *cached_size_request;
7441   const ClutterLayoutInfo *info;
7442   ClutterActorPrivate *priv;
7443   gboolean found_in_cache;
7444
7445   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7446
7447   priv = self->priv;
7448
7449   info = _clutter_actor_get_layout_info_or_defaults (self);
7450
7451   /* we shortcircuit the case of a fixed size set using set_height() */
7452   if (priv->min_height_set && priv->natural_height_set)
7453     {
7454       if (min_height_p != NULL)
7455         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7456
7457       if (natural_height_p != NULL)
7458         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7459
7460       return;
7461     }
7462
7463   /* the remaining cases are:
7464    *
7465    *   - either min_height or natural_height have been set
7466    *   - neither min_height or natural_height have been set
7467    *
7468    * in both cases, we go through the cache (and through the actor in case
7469    * of cache misses) and determine the authoritative value depending on
7470    * the *_set flags.
7471    */
7472
7473   if (!priv->needs_height_request)
7474     {
7475       found_in_cache =
7476         _clutter_actor_get_cached_size_request (for_width,
7477                                                 priv->height_requests,
7478                                                 &cached_size_request);
7479     }
7480   else
7481     {
7482       found_in_cache = FALSE;
7483       cached_size_request = &priv->height_requests[0];
7484     }
7485
7486   if (!found_in_cache)
7487     {
7488       gfloat minimum_height, natural_height;
7489       ClutterActorClass *klass;
7490
7491       minimum_height = natural_height = 0;
7492
7493       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7494
7495       /* adjust for margin */
7496       if (for_width >= 0)
7497         {
7498           for_width -= (info->margin.left + info->margin.right);
7499           if (for_width < 0)
7500             for_width = 0;
7501         }
7502
7503       klass = CLUTTER_ACTOR_GET_CLASS (self);
7504       klass->get_preferred_height (self, for_width,
7505                                    &minimum_height,
7506                                    &natural_height);
7507
7508       /* adjust for margin */
7509       minimum_height += (info->margin.top + info->margin.bottom);
7510       natural_height += (info->margin.top + info->margin.bottom);
7511
7512       /* Due to accumulated float errors, it's better not to warn
7513        * on this, but just fix it.
7514        */
7515       if (natural_height < minimum_height)
7516         natural_height = minimum_height;
7517
7518       cached_size_request->min_size = minimum_height;
7519       cached_size_request->natural_size = natural_height;
7520       cached_size_request->for_size = for_width;
7521       cached_size_request->age = priv->cached_height_age;
7522
7523       priv->cached_height_age += 1;
7524       priv->needs_height_request = FALSE;
7525     }
7526
7527   if (!priv->min_height_set)
7528     request_min_height = cached_size_request->min_size;
7529   else
7530     request_min_height = info->min_height;
7531
7532   if (!priv->natural_height_set)
7533     request_natural_height = cached_size_request->natural_size;
7534   else
7535     request_natural_height = info->natural_height;
7536
7537   if (min_height_p)
7538     *min_height_p = request_min_height;
7539
7540   if (natural_height_p)
7541     *natural_height_p = request_natural_height;
7542 }
7543
7544 /**
7545  * clutter_actor_get_allocation_box:
7546  * @self: A #ClutterActor
7547  * @box: (out): the function fills this in with the actor's allocation
7548  *
7549  * Gets the layout box an actor has been assigned. The allocation can
7550  * only be assumed valid inside a paint() method; anywhere else, it
7551  * may be out-of-date.
7552  *
7553  * An allocation does not incorporate the actor's scale or anchor point;
7554  * those transformations do not affect layout, only rendering.
7555  *
7556  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7557  * of functions inside the implementation of the get_preferred_width()
7558  * or get_preferred_height() virtual functions.</note>
7559  *
7560  * Since: 0.8
7561  */
7562 void
7563 clutter_actor_get_allocation_box (ClutterActor    *self,
7564                                   ClutterActorBox *box)
7565 {
7566   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7567
7568   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7569    * which limits calling get_allocation to inside paint() basically; or
7570    * we can 2) force a layout, which could be expensive if someone calls
7571    * get_allocation somewhere silly; or we can 3) just return the latest
7572    * value, allowing it to be out-of-date, and assume people know what
7573    * they are doing.
7574    *
7575    * The least-surprises approach that keeps existing code working is
7576    * likely to be 2). People can end up doing some inefficient things,
7577    * though, and in general code that requires 2) is probably broken.
7578    */
7579
7580   /* this implements 2) */
7581   if (G_UNLIKELY (self->priv->needs_allocation))
7582     {
7583       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7584
7585       /* do not queue a relayout on an unparented actor */
7586       if (stage)
7587         _clutter_stage_maybe_relayout (stage);
7588     }
7589
7590   /* commenting out the code above and just keeping this assigment
7591    * implements 3)
7592    */
7593   *box = self->priv->allocation;
7594 }
7595
7596 /**
7597  * clutter_actor_get_allocation_geometry:
7598  * @self: A #ClutterActor
7599  * @geom: (out): allocation geometry in pixels
7600  *
7601  * Gets the layout box an actor has been assigned.  The allocation can
7602  * only be assumed valid inside a paint() method; anywhere else, it
7603  * may be out-of-date.
7604  *
7605  * An allocation does not incorporate the actor's scale or anchor point;
7606  * those transformations do not affect layout, only rendering.
7607  *
7608  * The returned rectangle is in pixels.
7609  *
7610  * Since: 0.8
7611  */
7612 void
7613 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7614                                        ClutterGeometry *geom)
7615 {
7616   ClutterActorBox box;
7617
7618   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7619   g_return_if_fail (geom != NULL);
7620
7621   clutter_actor_get_allocation_box (self, &box);
7622
7623   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7624   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7625   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7626   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7627 }
7628
7629 static void
7630 clutter_actor_update_constraints (ClutterActor    *self,
7631                                   ClutterActorBox *allocation)
7632 {
7633   ClutterActorPrivate *priv = self->priv;
7634   const GList *constraints, *l;
7635
7636   if (priv->constraints == NULL)
7637     return;
7638
7639   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7640   for (l = constraints; l != NULL; l = l->next)
7641     {
7642       ClutterConstraint *constraint = l->data;
7643       ClutterActorMeta *meta = l->data;
7644
7645       if (clutter_actor_meta_get_enabled (meta))
7646         {
7647           _clutter_constraint_update_allocation (constraint,
7648                                                  self,
7649                                                  allocation);
7650         }
7651     }
7652 }
7653
7654 /*< private >
7655  * clutter_actor_adjust_allocation:
7656  * @self: a #ClutterActor
7657  * @allocation: (inout): the allocation to adjust
7658  *
7659  * Adjusts the passed allocation box taking into account the actor's
7660  * layout information, like alignment, expansion, and margin.
7661  */
7662 static void
7663 clutter_actor_adjust_allocation (ClutterActor    *self,
7664                                  ClutterActorBox *allocation)
7665 {
7666   ClutterActorBox adj_allocation;
7667   float alloc_width, alloc_height;
7668   float min_width, min_height;
7669   float nat_width, nat_height;
7670   ClutterRequestMode req_mode;
7671
7672   adj_allocation = *allocation;
7673
7674   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7675
7676   /* we want to hit the cache, so we use the public API */
7677   req_mode = clutter_actor_get_request_mode (self);
7678
7679   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7680     {
7681       clutter_actor_get_preferred_width (self, -1,
7682                                          &min_width,
7683                                          &nat_width);
7684       clutter_actor_get_preferred_height (self, alloc_width,
7685                                           &min_height,
7686                                           &nat_height);
7687     }
7688   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7689     {
7690       clutter_actor_get_preferred_height (self, -1,
7691                                           &min_height,
7692                                           &nat_height);
7693       clutter_actor_get_preferred_height (self, alloc_height,
7694                                           &min_width,
7695                                           &nat_width);
7696     }
7697
7698 #ifdef CLUTTER_ENABLE_DEBUG
7699   /* warn about underallocations */
7700   if (_clutter_diagnostic_enabled () &&
7701       (floorf (min_width - alloc_width) > 0 ||
7702        floorf (min_height - alloc_height) > 0))
7703     {
7704       ClutterActor *parent = clutter_actor_get_parent (self);
7705
7706       /* the only actors that are allowed to be underallocated are the Stage,
7707        * as it doesn't have an implicit size, and Actors that specifically
7708        * told us that they want to opt-out from layout control mechanisms
7709        * through the NO_LAYOUT escape hatch.
7710        */
7711       if (parent != NULL &&
7712           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7713         {
7714           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7715                      "of %.2f x %.2f from its parent actor '%s', but its "
7716                      "requested minimum size is of %.2f x %.2f",
7717                      _clutter_actor_get_debug_name (self),
7718                      alloc_width, alloc_height,
7719                      _clutter_actor_get_debug_name (parent),
7720                      min_width, min_height);
7721         }
7722     }
7723 #endif
7724
7725   clutter_actor_adjust_width (self,
7726                               &min_width,
7727                               &nat_width,
7728                               &adj_allocation.x1,
7729                               &adj_allocation.x2);
7730
7731   clutter_actor_adjust_height (self,
7732                                &min_height,
7733                                &nat_height,
7734                                &adj_allocation.y1,
7735                                &adj_allocation.y2);
7736
7737   /* we maintain the invariant that an allocation cannot be adjusted
7738    * to be outside the parent-given box
7739    */
7740   if (adj_allocation.x1 < allocation->x1 ||
7741       adj_allocation.y1 < allocation->y1 ||
7742       adj_allocation.x2 > allocation->x2 ||
7743       adj_allocation.y2 > allocation->y2)
7744     {
7745       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7746                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7747                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7748                  _clutter_actor_get_debug_name (self),
7749                  adj_allocation.x1, adj_allocation.y1,
7750                  adj_allocation.x2 - adj_allocation.x1,
7751                  adj_allocation.y2 - adj_allocation.y1,
7752                  allocation->x1, allocation->y1,
7753                  allocation->x2 - allocation->x1,
7754                  allocation->y2 - allocation->y1);
7755       return;
7756     }
7757
7758   *allocation = adj_allocation;
7759 }
7760
7761 /**
7762  * clutter_actor_allocate:
7763  * @self: A #ClutterActor
7764  * @box: new allocation of the actor, in parent-relative coordinates
7765  * @flags: flags that control the allocation
7766  *
7767  * Called by the parent of an actor to assign the actor its size.
7768  * Should never be called by applications (except when implementing
7769  * a container or layout manager).
7770  *
7771  * Actors can know from their allocation box whether they have moved
7772  * with respect to their parent actor. The @flags parameter describes
7773  * additional information about the allocation, for instance whether
7774  * the parent has moved with respect to the stage, for example because
7775  * a grandparent's origin has moved.
7776  *
7777  * Since: 0.8
7778  */
7779 void
7780 clutter_actor_allocate (ClutterActor           *self,
7781                         const ClutterActorBox  *box,
7782                         ClutterAllocationFlags  flags)
7783 {
7784   ClutterActorPrivate *priv;
7785   ClutterActorClass *klass;
7786   ClutterActorBox old_allocation, real_allocation;
7787   gboolean origin_changed, child_moved, size_changed;
7788   gboolean stage_allocation_changed;
7789
7790   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7791   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
7792     {
7793       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
7794                  "which isn't a descendent of the stage!\n",
7795                  self, _clutter_actor_get_debug_name (self));
7796       return;
7797     }
7798
7799   priv = self->priv;
7800
7801   old_allocation = priv->allocation;
7802   real_allocation = *box;
7803
7804   /* constraints are allowed to modify the allocation only here; we do
7805    * this prior to all the other checks so that we can bail out if the
7806    * allocation did not change
7807    */
7808   clutter_actor_update_constraints (self, &real_allocation);
7809
7810   /* adjust the allocation depending on the align/margin properties */
7811   clutter_actor_adjust_allocation (self, &real_allocation);
7812
7813   if (real_allocation.x2 < real_allocation.x1 ||
7814       real_allocation.y2 < real_allocation.y1)
7815     {
7816       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
7817                  _clutter_actor_get_debug_name (self),
7818                  real_allocation.x2 - real_allocation.x1,
7819                  real_allocation.y2 - real_allocation.y1);
7820     }
7821
7822   /* we allow 0-sized actors, but not negative-sized ones */
7823   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
7824   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
7825
7826   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
7827
7828   child_moved = (real_allocation.x1 != old_allocation.x1 ||
7829                  real_allocation.y1 != old_allocation.y1);
7830
7831   size_changed = (real_allocation.x2 != old_allocation.x2 ||
7832                   real_allocation.y2 != old_allocation.y2);
7833
7834   if (origin_changed || child_moved || size_changed)
7835     stage_allocation_changed = TRUE;
7836   else
7837     stage_allocation_changed = FALSE;
7838
7839   /* If we get an allocation "out of the blue"
7840    * (we did not queue relayout), then we want to
7841    * ignore it. But if we have needs_allocation set,
7842    * we want to guarantee that allocate() virtual
7843    * method is always called, i.e. that queue_relayout()
7844    * always results in an allocate() invocation on
7845    * an actor.
7846    *
7847    * The optimization here is to avoid re-allocating
7848    * actors that did not queue relayout and were
7849    * not moved.
7850    */
7851   if (!priv->needs_allocation && !stage_allocation_changed)
7852     {
7853       CLUTTER_NOTE (LAYOUT, "No allocation needed");
7854       return;
7855     }
7856
7857   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
7858    * clutter_actor_allocate(), it indicates whether the parent has its
7859    * absolute origin moved; when passed in to ClutterActor::allocate()
7860    * virtual method though, it indicates whether the child has its
7861    * absolute origin moved.  So we set it when child_moved is TRUE
7862    */
7863   if (child_moved)
7864     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
7865
7866   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7867
7868   klass = CLUTTER_ACTOR_GET_CLASS (self);
7869   klass->allocate (self, &real_allocation, flags);
7870
7871   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7872
7873   if (stage_allocation_changed)
7874     clutter_actor_queue_redraw (self);
7875 }
7876
7877 /**
7878  * clutter_actor_set_allocation:
7879  * @self: a #ClutterActor
7880  * @box: a #ClutterActorBox
7881  * @flags: allocation flags
7882  *
7883  * Stores the allocation of @self as defined by @box.
7884  *
7885  * This function can only be called from within the implementation of
7886  * the #ClutterActorClass.allocate() virtual function.
7887  *
7888  * The allocation should have been adjusted to take into account constraints,
7889  * alignment, and margin properties. If you are implementing a #ClutterActor
7890  * subclass that provides its own layout management policy for its children
7891  * instead of using a #ClutterLayoutManager delegate, you should not call
7892  * this function on the children of @self; instead, you should call
7893  * clutter_actor_allocate(), which will adjust the allocation box for
7894  * you.
7895  *
7896  * This function should only be used by subclasses of #ClutterActor
7897  * that wish to store their allocation but cannot chain up to the
7898  * parent's implementation; the default implementation of the
7899  * #ClutterActorClass.allocate() virtual function will call this
7900  * function.
7901  *
7902  * It is important to note that, while chaining up was the recommended
7903  * behaviour for #ClutterActor subclasses prior to the introduction of
7904  * this function, it is recommended to call clutter_actor_set_allocation()
7905  * instead.
7906  *
7907  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
7908  * to handle the allocation of its children, this function will call
7909  * the clutter_layout_manager_allocate() function only if the
7910  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
7911  * expected that the subclass will call clutter_layout_manager_allocate()
7912  * by itself. For instance, the following code:
7913  *
7914  * |[
7915  * static void
7916  * my_actor_allocate (ClutterActor *actor,
7917  *                    const ClutterActorBox *allocation,
7918  *                    ClutterAllocationFlags flags)
7919  * {
7920  *   ClutterActorBox new_alloc;
7921  *   ClutterAllocationFlags new_flags;
7922  *
7923  *   adjust_allocation (allocation, &amp;new_alloc);
7924  *
7925  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
7926  *
7927  *   /&ast; this will use the layout manager set on the actor &ast;/
7928  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
7929  * }
7930  * ]|
7931  *
7932  * is equivalent to this:
7933  *
7934  * |[
7935  * static void
7936  * my_actor_allocate (ClutterActor *actor,
7937  *                    const ClutterActorBox *allocation,
7938  *                    ClutterAllocationFlags flags)
7939  * {
7940  *   ClutterLayoutManager *layout;
7941  *   ClutterActorBox new_alloc;
7942  *
7943  *   adjust_allocation (allocation, &amp;new_alloc);
7944  *
7945  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
7946  *
7947  *   layout = clutter_actor_get_layout_manager (actor);
7948  *   clutter_layout_manager_allocate (layout,
7949  *                                    CLUTTER_CONTAINER (actor),
7950  *                                    &amp;new_alloc,
7951  *                                    flags);
7952  * }
7953  * ]|
7954  *
7955  * Since: 1.10
7956  */
7957 void
7958 clutter_actor_set_allocation (ClutterActor           *self,
7959                               const ClutterActorBox  *box,
7960                               ClutterAllocationFlags  flags)
7961 {
7962   ClutterActorPrivate *priv;
7963   gboolean changed;
7964
7965   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7966   g_return_if_fail (box != NULL);
7967
7968   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
7969     {
7970       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
7971                   "can only be called from within the implementation of "
7972                   "the ClutterActor::allocate() virtual function.");
7973       return;
7974     }
7975
7976   priv = self->priv;
7977
7978   g_object_freeze_notify (G_OBJECT (self));
7979
7980   changed = clutter_actor_set_allocation_internal (self, box, flags);
7981
7982   /* we allocate our children before we notify changes in our geometry,
7983    * so that people connecting to properties will be able to get valid
7984    * data out of the sub-tree of the scene graph that has this actor at
7985    * the root.
7986    */
7987   clutter_actor_maybe_layout_children (self, box, flags);
7988
7989   if (changed)
7990     {
7991       ClutterActorBox signal_box = priv->allocation;
7992       ClutterAllocationFlags signal_flags = priv->allocation_flags;
7993
7994       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
7995                      &signal_box,
7996                      signal_flags);
7997     }
7998
7999   g_object_thaw_notify (G_OBJECT (self));
8000 }
8001
8002 /**
8003  * clutter_actor_set_geometry:
8004  * @self: A #ClutterActor
8005  * @geometry: A #ClutterGeometry
8006  *
8007  * Sets the actor's fixed position and forces its minimum and natural
8008  * size, in pixels. This means the untransformed actor will have the
8009  * given geometry. This is the same as calling clutter_actor_set_position()
8010  * and clutter_actor_set_size().
8011  *
8012  * Deprecated: 1.10: Use clutter_actor_set_position() and
8013  *   clutter_actor_set_size() instead.
8014  */
8015 void
8016 clutter_actor_set_geometry (ClutterActor          *self,
8017                             const ClutterGeometry *geometry)
8018 {
8019   g_object_freeze_notify (G_OBJECT (self));
8020
8021   clutter_actor_set_position (self, geometry->x, geometry->y);
8022   clutter_actor_set_size (self, geometry->width, geometry->height);
8023
8024   g_object_thaw_notify (G_OBJECT (self));
8025 }
8026
8027 /**
8028  * clutter_actor_get_geometry:
8029  * @self: A #ClutterActor
8030  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8031  *
8032  * Gets the size and position of an actor relative to its parent
8033  * actor. This is the same as calling clutter_actor_get_position() and
8034  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8035  * requested size and position if the actor's allocation is invalid.
8036  *
8037  * Deprecated: 1.10: Use clutter_actor_get_position() and
8038  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8039  *   instead.
8040  */
8041 void
8042 clutter_actor_get_geometry (ClutterActor    *self,
8043                             ClutterGeometry *geometry)
8044 {
8045   gfloat x, y, width, height;
8046
8047   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8048   g_return_if_fail (geometry != NULL);
8049
8050   clutter_actor_get_position (self, &x, &y);
8051   clutter_actor_get_size (self, &width, &height);
8052
8053   geometry->x = (int) x;
8054   geometry->y = (int) y;
8055   geometry->width = (int) width;
8056   geometry->height = (int) height;
8057 }
8058
8059 /**
8060  * clutter_actor_set_position:
8061  * @self: A #ClutterActor
8062  * @x: New left position of actor in pixels.
8063  * @y: New top position of actor in pixels.
8064  *
8065  * Sets the actor's fixed position in pixels relative to any parent
8066  * actor.
8067  *
8068  * If a layout manager is in use, this position will override the
8069  * layout manager and force a fixed position.
8070  */
8071 void
8072 clutter_actor_set_position (ClutterActor *self,
8073                             gfloat        x,
8074                             gfloat        y)
8075 {
8076   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8077
8078   g_object_freeze_notify (G_OBJECT (self));
8079
8080   clutter_actor_set_x (self, x);
8081   clutter_actor_set_y (self, y);
8082
8083   g_object_thaw_notify (G_OBJECT (self));
8084 }
8085
8086 /**
8087  * clutter_actor_get_fixed_position_set:
8088  * @self: A #ClutterActor
8089  *
8090  * Checks whether an actor has a fixed position set (and will thus be
8091  * unaffected by any layout manager).
8092  *
8093  * Return value: %TRUE if the fixed position is set on the actor
8094  *
8095  * Since: 0.8
8096  */
8097 gboolean
8098 clutter_actor_get_fixed_position_set (ClutterActor *self)
8099 {
8100   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8101
8102   return self->priv->position_set;
8103 }
8104
8105 /**
8106  * clutter_actor_set_fixed_position_set:
8107  * @self: A #ClutterActor
8108  * @is_set: whether to use fixed position
8109  *
8110  * Sets whether an actor has a fixed position set (and will thus be
8111  * unaffected by any layout manager).
8112  *
8113  * Since: 0.8
8114  */
8115 void
8116 clutter_actor_set_fixed_position_set (ClutterActor *self,
8117                                       gboolean      is_set)
8118 {
8119   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8120
8121   if (self->priv->position_set == (is_set != FALSE))
8122     return;
8123
8124   self->priv->position_set = is_set != FALSE;
8125   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8126
8127   clutter_actor_queue_relayout (self);
8128 }
8129
8130 /**
8131  * clutter_actor_move_by:
8132  * @self: A #ClutterActor
8133  * @dx: Distance to move Actor on X axis.
8134  * @dy: Distance to move Actor on Y axis.
8135  *
8136  * Moves an actor by the specified distance relative to its current
8137  * position in pixels.
8138  *
8139  * This function modifies the fixed position of an actor and thus removes
8140  * it from any layout management. Another way to move an actor is with an
8141  * anchor point, see clutter_actor_set_anchor_point().
8142  *
8143  * Since: 0.2
8144  */
8145 void
8146 clutter_actor_move_by (ClutterActor *self,
8147                        gfloat        dx,
8148                        gfloat        dy)
8149 {
8150   const ClutterLayoutInfo *info;
8151   gfloat x, y;
8152
8153   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8154
8155   info = _clutter_actor_get_layout_info_or_defaults (self);
8156   x = info->fixed_x;
8157   y = info->fixed_y;
8158
8159   clutter_actor_set_position (self, x + dx, y + dy);
8160 }
8161
8162 static void
8163 clutter_actor_set_min_width (ClutterActor *self,
8164                              gfloat        min_width)
8165 {
8166   ClutterActorPrivate *priv = self->priv;
8167   ClutterActorBox old = { 0, };
8168   ClutterLayoutInfo *info;
8169
8170   /* if we are setting the size on a top-level actor and the
8171    * backend only supports static top-levels (e.g. framebuffers)
8172    * then we ignore the passed value and we override it with
8173    * the stage implementation's preferred size.
8174    */
8175   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8176       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8177     return;
8178
8179   info = _clutter_actor_get_layout_info (self);
8180
8181   if (priv->min_width_set && min_width == info->min_width)
8182     return;
8183
8184   g_object_freeze_notify (G_OBJECT (self));
8185
8186   clutter_actor_store_old_geometry (self, &old);
8187
8188   info->min_width = min_width;
8189   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8190   clutter_actor_set_min_width_set (self, TRUE);
8191
8192   clutter_actor_notify_if_geometry_changed (self, &old);
8193
8194   g_object_thaw_notify (G_OBJECT (self));
8195
8196   clutter_actor_queue_relayout (self);
8197 }
8198
8199 static void
8200 clutter_actor_set_min_height (ClutterActor *self,
8201                               gfloat        min_height)
8202
8203 {
8204   ClutterActorPrivate *priv = self->priv;
8205   ClutterActorBox old = { 0, };
8206   ClutterLayoutInfo *info;
8207
8208   /* if we are setting the size on a top-level actor and the
8209    * backend only supports static top-levels (e.g. framebuffers)
8210    * then we ignore the passed value and we override it with
8211    * the stage implementation's preferred size.
8212    */
8213   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8214       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8215     return;
8216
8217   info = _clutter_actor_get_layout_info (self);
8218
8219   if (priv->min_height_set && min_height == info->min_height)
8220     return;
8221
8222   g_object_freeze_notify (G_OBJECT (self));
8223
8224   clutter_actor_store_old_geometry (self, &old);
8225
8226   info->min_height = min_height;
8227   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8228   clutter_actor_set_min_height_set (self, TRUE);
8229
8230   clutter_actor_notify_if_geometry_changed (self, &old);
8231
8232   g_object_thaw_notify (G_OBJECT (self));
8233
8234   clutter_actor_queue_relayout (self);
8235 }
8236
8237 static void
8238 clutter_actor_set_natural_width (ClutterActor *self,
8239                                  gfloat        natural_width)
8240 {
8241   ClutterActorPrivate *priv = self->priv;
8242   ClutterActorBox old = { 0, };
8243   ClutterLayoutInfo *info;
8244
8245   /* if we are setting the size on a top-level actor and the
8246    * backend only supports static top-levels (e.g. framebuffers)
8247    * then we ignore the passed value and we override it with
8248    * the stage implementation's preferred size.
8249    */
8250   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8251       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8252     return;
8253
8254   info = _clutter_actor_get_layout_info (self);
8255
8256   if (priv->natural_width_set && natural_width == info->natural_width)
8257     return;
8258
8259   g_object_freeze_notify (G_OBJECT (self));
8260
8261   clutter_actor_store_old_geometry (self, &old);
8262
8263   info->natural_width = natural_width;
8264   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8265   clutter_actor_set_natural_width_set (self, TRUE);
8266
8267   clutter_actor_notify_if_geometry_changed (self, &old);
8268
8269   g_object_thaw_notify (G_OBJECT (self));
8270
8271   clutter_actor_queue_relayout (self);
8272 }
8273
8274 static void
8275 clutter_actor_set_natural_height (ClutterActor *self,
8276                                   gfloat        natural_height)
8277 {
8278   ClutterActorPrivate *priv = self->priv;
8279   ClutterActorBox old = { 0, };
8280   ClutterLayoutInfo *info;
8281
8282   /* if we are setting the size on a top-level actor and the
8283    * backend only supports static top-levels (e.g. framebuffers)
8284    * then we ignore the passed value and we override it with
8285    * the stage implementation's preferred size.
8286    */
8287   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8288       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8289     return;
8290
8291   info = _clutter_actor_get_layout_info (self);
8292
8293   if (priv->natural_height_set && natural_height == info->natural_height)
8294     return;
8295
8296   g_object_freeze_notify (G_OBJECT (self));
8297
8298   clutter_actor_store_old_geometry (self, &old);
8299
8300   info->natural_height = natural_height;
8301   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8302   clutter_actor_set_natural_height_set (self, TRUE);
8303
8304   clutter_actor_notify_if_geometry_changed (self, &old);
8305
8306   g_object_thaw_notify (G_OBJECT (self));
8307
8308   clutter_actor_queue_relayout (self);
8309 }
8310
8311 static void
8312 clutter_actor_set_min_width_set (ClutterActor *self,
8313                                  gboolean      use_min_width)
8314 {
8315   ClutterActorPrivate *priv = self->priv;
8316   ClutterActorBox old = { 0, };
8317
8318   if (priv->min_width_set == (use_min_width != FALSE))
8319     return;
8320
8321   clutter_actor_store_old_geometry (self, &old);
8322
8323   priv->min_width_set = use_min_width != FALSE;
8324   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8325
8326   clutter_actor_notify_if_geometry_changed (self, &old);
8327
8328   clutter_actor_queue_relayout (self);
8329 }
8330
8331 static void
8332 clutter_actor_set_min_height_set (ClutterActor *self,
8333                                   gboolean      use_min_height)
8334 {
8335   ClutterActorPrivate *priv = self->priv;
8336   ClutterActorBox old = { 0, };
8337
8338   if (priv->min_height_set == (use_min_height != FALSE))
8339     return;
8340
8341   clutter_actor_store_old_geometry (self, &old);
8342
8343   priv->min_height_set = use_min_height != FALSE;
8344   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8345
8346   clutter_actor_notify_if_geometry_changed (self, &old);
8347
8348   clutter_actor_queue_relayout (self);
8349 }
8350
8351 static void
8352 clutter_actor_set_natural_width_set (ClutterActor *self,
8353                                      gboolean      use_natural_width)
8354 {
8355   ClutterActorPrivate *priv = self->priv;
8356   ClutterActorBox old = { 0, };
8357
8358   if (priv->natural_width_set == (use_natural_width != FALSE))
8359     return;
8360
8361   clutter_actor_store_old_geometry (self, &old);
8362
8363   priv->natural_width_set = use_natural_width != FALSE;
8364   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8365
8366   clutter_actor_notify_if_geometry_changed (self, &old);
8367
8368   clutter_actor_queue_relayout (self);
8369 }
8370
8371 static void
8372 clutter_actor_set_natural_height_set (ClutterActor *self,
8373                                       gboolean      use_natural_height)
8374 {
8375   ClutterActorPrivate *priv = self->priv;
8376   ClutterActorBox old = { 0, };
8377
8378   if (priv->natural_height_set == (use_natural_height != FALSE))
8379     return;
8380
8381   clutter_actor_store_old_geometry (self, &old);
8382
8383   priv->natural_height_set = use_natural_height != FALSE;
8384   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8385
8386   clutter_actor_notify_if_geometry_changed (self, &old);
8387
8388   clutter_actor_queue_relayout (self);
8389 }
8390
8391 /**
8392  * clutter_actor_set_request_mode:
8393  * @self: a #ClutterActor
8394  * @mode: the request mode
8395  *
8396  * Sets the geometry request mode of @self.
8397  *
8398  * The @mode determines the order for invoking
8399  * clutter_actor_get_preferred_width() and
8400  * clutter_actor_get_preferred_height()
8401  *
8402  * Since: 1.2
8403  */
8404 void
8405 clutter_actor_set_request_mode (ClutterActor       *self,
8406                                 ClutterRequestMode  mode)
8407 {
8408   ClutterActorPrivate *priv;
8409
8410   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8411
8412   priv = self->priv;
8413
8414   if (priv->request_mode == mode)
8415     return;
8416
8417   priv->request_mode = mode;
8418
8419   priv->needs_width_request = TRUE;
8420   priv->needs_height_request = TRUE;
8421
8422   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8423
8424   clutter_actor_queue_relayout (self);
8425 }
8426
8427 /**
8428  * clutter_actor_get_request_mode:
8429  * @self: a #ClutterActor
8430  *
8431  * Retrieves the geometry request mode of @self
8432  *
8433  * Return value: the request mode for the actor
8434  *
8435  * Since: 1.2
8436  */
8437 ClutterRequestMode
8438 clutter_actor_get_request_mode (ClutterActor *self)
8439 {
8440   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8441                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8442
8443   return self->priv->request_mode;
8444 }
8445
8446 /* variant of set_width() without checks and without notification
8447  * freeze+thaw, for internal usage only
8448  */
8449 static inline void
8450 clutter_actor_set_width_internal (ClutterActor *self,
8451                                   gfloat        width)
8452 {
8453   if (width >= 0)
8454     {
8455       /* the Stage will use the :min-width to control the minimum
8456        * width to be resized to, so we should not be setting it
8457        * along with the :natural-width
8458        */
8459       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8460         clutter_actor_set_min_width (self, width);
8461
8462       clutter_actor_set_natural_width (self, width);
8463     }
8464   else
8465     {
8466       /* we only unset the :natural-width for the Stage */
8467       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8468         clutter_actor_set_min_width_set (self, FALSE);
8469
8470       clutter_actor_set_natural_width_set (self, FALSE);
8471     }
8472 }
8473
8474 /* variant of set_height() without checks and without notification
8475  * freeze+thaw, for internal usage only
8476  */
8477 static inline void
8478 clutter_actor_set_height_internal (ClutterActor *self,
8479                                    gfloat        height)
8480 {
8481   if (height >= 0)
8482     {
8483       /* see the comment above in set_width_internal() */
8484       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8485         clutter_actor_set_min_height (self, height);
8486
8487       clutter_actor_set_natural_height (self, height);
8488     }
8489   else
8490     {
8491       /* see the comment above in set_width_internal() */
8492       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8493         clutter_actor_set_min_height_set (self, FALSE);
8494
8495       clutter_actor_set_natural_height_set (self, FALSE);
8496     }
8497 }
8498
8499 /**
8500  * clutter_actor_set_size:
8501  * @self: A #ClutterActor
8502  * @width: New width of actor in pixels, or -1
8503  * @height: New height of actor in pixels, or -1
8504  *
8505  * Sets the actor's size request in pixels. This overrides any
8506  * "normal" size request the actor would have. For example
8507  * a text actor might normally request the size of the text;
8508  * this function would force a specific size instead.
8509  *
8510  * If @width and/or @height are -1 the actor will use its
8511  * "normal" size request instead of overriding it, i.e.
8512  * you can "unset" the size with -1.
8513  *
8514  * This function sets or unsets both the minimum and natural size.
8515  */
8516 void
8517 clutter_actor_set_size (ClutterActor *self,
8518                         gfloat        width,
8519                         gfloat        height)
8520 {
8521   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8522
8523   g_object_freeze_notify (G_OBJECT (self));
8524
8525   clutter_actor_set_width_internal (self, width);
8526   clutter_actor_set_height_internal (self, height);
8527
8528   g_object_thaw_notify (G_OBJECT (self));
8529 }
8530
8531 /**
8532  * clutter_actor_get_size:
8533  * @self: A #ClutterActor
8534  * @width: (out) (allow-none): return location for the width, or %NULL.
8535  * @height: (out) (allow-none): return location for the height, or %NULL.
8536  *
8537  * This function tries to "do what you mean" and return
8538  * the size an actor will have. If the actor has a valid
8539  * allocation, the allocation will be returned; otherwise,
8540  * the actors natural size request will be returned.
8541  *
8542  * If you care whether you get the request vs. the allocation, you
8543  * should probably call a different function like
8544  * clutter_actor_get_allocation_box() or
8545  * clutter_actor_get_preferred_width().
8546  *
8547  * Since: 0.2
8548  */
8549 void
8550 clutter_actor_get_size (ClutterActor *self,
8551                         gfloat       *width,
8552                         gfloat       *height)
8553 {
8554   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8555
8556   if (width)
8557     *width = clutter_actor_get_width (self);
8558
8559   if (height)
8560     *height = clutter_actor_get_height (self);
8561 }
8562
8563 /**
8564  * clutter_actor_get_position:
8565  * @self: a #ClutterActor
8566  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8567  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8568  *
8569  * This function tries to "do what you mean" and tell you where the
8570  * actor is, prior to any transformations. Retrieves the fixed
8571  * position of an actor in pixels, if one has been set; otherwise, if
8572  * the allocation is valid, returns the actor's allocated position;
8573  * otherwise, returns 0,0.
8574  *
8575  * The returned position is in pixels.
8576  *
8577  * Since: 0.6
8578  */
8579 void
8580 clutter_actor_get_position (ClutterActor *self,
8581                             gfloat       *x,
8582                             gfloat       *y)
8583 {
8584   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8585
8586   if (x)
8587     *x = clutter_actor_get_x (self);
8588
8589   if (y)
8590     *y = clutter_actor_get_y (self);
8591 }
8592
8593 /**
8594  * clutter_actor_get_transformed_position:
8595  * @self: A #ClutterActor
8596  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8597  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8598  *
8599  * Gets the absolute position of an actor, in pixels relative to the stage.
8600  *
8601  * Since: 0.8
8602  */
8603 void
8604 clutter_actor_get_transformed_position (ClutterActor *self,
8605                                         gfloat       *x,
8606                                         gfloat       *y)
8607 {
8608   ClutterVertex v1;
8609   ClutterVertex v2;
8610
8611   v1.x = v1.y = v1.z = 0;
8612   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8613
8614   if (x)
8615     *x = v2.x;
8616
8617   if (y)
8618     *y = v2.y;
8619 }
8620
8621 /**
8622  * clutter_actor_get_transformed_size:
8623  * @self: A #ClutterActor
8624  * @width: (out) (allow-none): return location for the width, or %NULL
8625  * @height: (out) (allow-none): return location for the height, or %NULL
8626  *
8627  * Gets the absolute size of an actor in pixels, taking into account the
8628  * scaling factors.
8629  *
8630  * If the actor has a valid allocation, the allocated size will be used.
8631  * If the actor has not a valid allocation then the preferred size will
8632  * be transformed and returned.
8633  *
8634  * If you want the transformed allocation, see
8635  * clutter_actor_get_abs_allocation_vertices() instead.
8636  *
8637  * <note>When the actor (or one of its ancestors) is rotated around the
8638  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8639  * as a generic quadrangle; in that case this function returns the size
8640  * of the smallest rectangle that encapsulates the entire quad. Please
8641  * note that in this case no assumptions can be made about the relative
8642  * position of this envelope to the absolute position of the actor, as
8643  * returned by clutter_actor_get_transformed_position(); if you need this
8644  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8645  * to get the coords of the actual quadrangle.</note>
8646  *
8647  * Since: 0.8
8648  */
8649 void
8650 clutter_actor_get_transformed_size (ClutterActor *self,
8651                                     gfloat       *width,
8652                                     gfloat       *height)
8653 {
8654   ClutterActorPrivate *priv;
8655   ClutterVertex v[4];
8656   gfloat x_min, x_max, y_min, y_max;
8657   gint i;
8658
8659   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8660
8661   priv = self->priv;
8662
8663   /* if the actor hasn't been allocated yet, get the preferred
8664    * size and transform that
8665    */
8666   if (priv->needs_allocation)
8667     {
8668       gfloat natural_width, natural_height;
8669       ClutterActorBox box;
8670
8671       /* Make a fake allocation to transform.
8672        *
8673        * NB: _clutter_actor_transform_and_project_box expects a box in
8674        * the actor's coordinate space... */
8675
8676       box.x1 = 0;
8677       box.y1 = 0;
8678
8679       natural_width = natural_height = 0;
8680       clutter_actor_get_preferred_size (self, NULL, NULL,
8681                                         &natural_width,
8682                                         &natural_height);
8683
8684       box.x2 = natural_width;
8685       box.y2 = natural_height;
8686
8687       _clutter_actor_transform_and_project_box (self, &box, v);
8688     }
8689   else
8690     clutter_actor_get_abs_allocation_vertices (self, v);
8691
8692   x_min = x_max = v[0].x;
8693   y_min = y_max = v[0].y;
8694
8695   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8696     {
8697       if (v[i].x < x_min)
8698         x_min = v[i].x;
8699
8700       if (v[i].x > x_max)
8701         x_max = v[i].x;
8702
8703       if (v[i].y < y_min)
8704         y_min = v[i].y;
8705
8706       if (v[i].y > y_max)
8707         y_max = v[i].y;
8708     }
8709
8710   if (width)
8711     *width  = x_max - x_min;
8712
8713   if (height)
8714     *height = y_max - y_min;
8715 }
8716
8717 /**
8718  * clutter_actor_get_width:
8719  * @self: A #ClutterActor
8720  *
8721  * Retrieves the width of a #ClutterActor.
8722  *
8723  * If the actor has a valid allocation, this function will return the
8724  * width of the allocated area given to the actor.
8725  *
8726  * If the actor does not have a valid allocation, this function will
8727  * return the actor's natural width, that is the preferred width of
8728  * the actor.
8729  *
8730  * If you care whether you get the preferred width or the width that
8731  * has been assigned to the actor, you should probably call a different
8732  * function like clutter_actor_get_allocation_box() to retrieve the
8733  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8734  * preferred width.
8735  *
8736  * If an actor has a fixed width, for instance a width that has been
8737  * assigned using clutter_actor_set_width(), the width returned will
8738  * be the same value.
8739  *
8740  * Return value: the width of the actor, in pixels
8741  */
8742 gfloat
8743 clutter_actor_get_width (ClutterActor *self)
8744 {
8745   ClutterActorPrivate *priv;
8746
8747   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8748
8749   priv = self->priv;
8750
8751   if (priv->needs_allocation)
8752     {
8753       gfloat natural_width = 0;
8754
8755       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8756         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8757       else
8758         {
8759           gfloat natural_height = 0;
8760
8761           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8762           clutter_actor_get_preferred_width (self, natural_height,
8763                                              NULL,
8764                                              &natural_width);
8765         }
8766
8767       return natural_width;
8768     }
8769   else
8770     return priv->allocation.x2 - priv->allocation.x1;
8771 }
8772
8773 /**
8774  * clutter_actor_get_height:
8775  * @self: A #ClutterActor
8776  *
8777  * Retrieves the height of a #ClutterActor.
8778  *
8779  * If the actor has a valid allocation, this function will return the
8780  * height of the allocated area given to the actor.
8781  *
8782  * If the actor does not have a valid allocation, this function will
8783  * return the actor's natural height, that is the preferred height of
8784  * the actor.
8785  *
8786  * If you care whether you get the preferred height or the height that
8787  * has been assigned to the actor, you should probably call a different
8788  * function like clutter_actor_get_allocation_box() to retrieve the
8789  * allocated size or clutter_actor_get_preferred_height() to retrieve the
8790  * preferred height.
8791  *
8792  * If an actor has a fixed height, for instance a height that has been
8793  * assigned using clutter_actor_set_height(), the height returned will
8794  * be the same value.
8795  *
8796  * Return value: the height of the actor, in pixels
8797  */
8798 gfloat
8799 clutter_actor_get_height (ClutterActor *self)
8800 {
8801   ClutterActorPrivate *priv;
8802
8803   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8804
8805   priv = self->priv;
8806
8807   if (priv->needs_allocation)
8808     {
8809       gfloat natural_height = 0;
8810
8811       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8812         {
8813           gfloat natural_width = 0;
8814
8815           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8816           clutter_actor_get_preferred_height (self, natural_width,
8817                                               NULL, &natural_height);
8818         }
8819       else
8820         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8821
8822       return natural_height;
8823     }
8824   else
8825     return priv->allocation.y2 - priv->allocation.y1;
8826 }
8827
8828 /**
8829  * clutter_actor_set_width:
8830  * @self: A #ClutterActor
8831  * @width: Requested new width for the actor, in pixels, or -1
8832  *
8833  * Forces a width on an actor, causing the actor's preferred width
8834  * and height (if any) to be ignored.
8835  *
8836  * If @width is -1 the actor will use its preferred width request
8837  * instead of overriding it, i.e. you can "unset" the width with -1.
8838  *
8839  * This function sets both the minimum and natural size of the actor.
8840  *
8841  * since: 0.2
8842  */
8843 void
8844 clutter_actor_set_width (ClutterActor *self,
8845                          gfloat        width)
8846 {
8847   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8848
8849   g_object_freeze_notify (G_OBJECT (self));
8850
8851   clutter_actor_set_width_internal (self, width);
8852
8853   g_object_thaw_notify (G_OBJECT (self));
8854 }
8855
8856 /**
8857  * clutter_actor_set_height:
8858  * @self: A #ClutterActor
8859  * @height: Requested new height for the actor, in pixels, or -1
8860  *
8861  * Forces a height on an actor, causing the actor's preferred width
8862  * and height (if any) to be ignored.
8863  *
8864  * If @height is -1 the actor will use its preferred height instead of
8865  * overriding it, i.e. you can "unset" the height with -1.
8866  *
8867  * This function sets both the minimum and natural size of the actor.
8868  *
8869  * since: 0.2
8870  */
8871 void
8872 clutter_actor_set_height (ClutterActor *self,
8873                           gfloat        height)
8874 {
8875   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8876
8877   g_object_freeze_notify (G_OBJECT (self));
8878
8879   clutter_actor_set_height_internal (self, height);
8880
8881   g_object_thaw_notify (G_OBJECT (self));
8882 }
8883
8884 /**
8885  * clutter_actor_set_x:
8886  * @self: a #ClutterActor
8887  * @x: the actor's position on the X axis
8888  *
8889  * Sets the actor's X coordinate, relative to its parent, in pixels.
8890  *
8891  * Overrides any layout manager and forces a fixed position for
8892  * the actor.
8893  *
8894  * Since: 0.6
8895  */
8896 void
8897 clutter_actor_set_x (ClutterActor *self,
8898                      gfloat        x)
8899 {
8900   ClutterActorBox old = { 0, };
8901   ClutterActorPrivate *priv;
8902   ClutterLayoutInfo *info;
8903
8904   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8905
8906   priv = self->priv;
8907
8908   info = _clutter_actor_get_layout_info (self);
8909
8910   if (priv->position_set && info->fixed_x == x)
8911     return;
8912
8913   clutter_actor_store_old_geometry (self, &old);
8914
8915   info->fixed_x = x;
8916   clutter_actor_set_fixed_position_set (self, TRUE);
8917
8918   clutter_actor_notify_if_geometry_changed (self, &old);
8919
8920   clutter_actor_queue_relayout (self);
8921 }
8922
8923 /**
8924  * clutter_actor_set_y:
8925  * @self: a #ClutterActor
8926  * @y: the actor's position on the Y axis
8927  *
8928  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
8929  *
8930  * Overrides any layout manager and forces a fixed position for
8931  * the actor.
8932  *
8933  * Since: 0.6
8934  */
8935 void
8936 clutter_actor_set_y (ClutterActor *self,
8937                      gfloat        y)
8938 {
8939   ClutterActorBox old = { 0, };
8940   ClutterActorPrivate *priv;
8941   ClutterLayoutInfo *info;
8942
8943   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8944
8945   priv = self->priv;
8946
8947   info = _clutter_actor_get_layout_info (self);
8948
8949   if (priv->position_set && info->fixed_y == y)
8950     return;
8951
8952   clutter_actor_store_old_geometry (self, &old);
8953
8954   info->fixed_y = y;
8955   clutter_actor_set_fixed_position_set (self, TRUE);
8956
8957   clutter_actor_notify_if_geometry_changed (self, &old);
8958
8959   clutter_actor_queue_relayout (self);
8960 }
8961
8962 /**
8963  * clutter_actor_get_x:
8964  * @self: A #ClutterActor
8965  *
8966  * Retrieves the X coordinate of a #ClutterActor.
8967  *
8968  * This function tries to "do what you mean", by returning the
8969  * correct value depending on the actor's state.
8970  *
8971  * If the actor has a valid allocation, this function will return
8972  * the X coordinate of the origin of the allocation box.
8973  *
8974  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
8975  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8976  * function will return that coordinate.
8977  *
8978  * If both the allocation and a fixed position are missing, this function
8979  * will return 0.
8980  *
8981  * Return value: the X coordinate, in pixels, ignoring any
8982  *   transformation (i.e. scaling, rotation)
8983  */
8984 gfloat
8985 clutter_actor_get_x (ClutterActor *self)
8986 {
8987   ClutterActorPrivate *priv;
8988
8989   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8990
8991   priv = self->priv;
8992
8993   if (priv->needs_allocation)
8994     {
8995       if (priv->position_set)
8996         {
8997           const ClutterLayoutInfo *info;
8998
8999           info = _clutter_actor_get_layout_info_or_defaults (self);
9000
9001           return info->fixed_x;
9002         }
9003       else
9004         return 0;
9005     }
9006   else
9007     return priv->allocation.x1;
9008 }
9009
9010 /**
9011  * clutter_actor_get_y:
9012  * @self: A #ClutterActor
9013  *
9014  * Retrieves the Y coordinate of a #ClutterActor.
9015  *
9016  * This function tries to "do what you mean", by returning the
9017  * correct value depending on the actor's state.
9018  *
9019  * If the actor has a valid allocation, this function will return
9020  * the Y coordinate of the origin of the allocation box.
9021  *
9022  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9023  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9024  * function will return that coordinate.
9025  *
9026  * If both the allocation and a fixed position are missing, this function
9027  * will return 0.
9028  *
9029  * Return value: the Y coordinate, in pixels, ignoring any
9030  *   transformation (i.e. scaling, rotation)
9031  */
9032 gfloat
9033 clutter_actor_get_y (ClutterActor *self)
9034 {
9035   ClutterActorPrivate *priv;
9036
9037   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9038
9039   priv = self->priv;
9040
9041   if (priv->needs_allocation)
9042     {
9043       if (priv->position_set)
9044         {
9045           const ClutterLayoutInfo *info;
9046
9047           info = _clutter_actor_get_layout_info_or_defaults (self);
9048
9049           return info->fixed_y;
9050         }
9051       else
9052         return 0;
9053     }
9054   else
9055     return priv->allocation.y1;
9056 }
9057
9058 /**
9059  * clutter_actor_set_scale:
9060  * @self: A #ClutterActor
9061  * @scale_x: double factor to scale actor by horizontally.
9062  * @scale_y: double factor to scale actor by vertically.
9063  *
9064  * Scales an actor with the given factors. The scaling is relative to
9065  * the scale center and the anchor point. The scale center is
9066  * unchanged by this function and defaults to 0,0.
9067  *
9068  * Since: 0.2
9069  */
9070 void
9071 clutter_actor_set_scale (ClutterActor *self,
9072                          gdouble       scale_x,
9073                          gdouble       scale_y)
9074 {
9075   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9076
9077   g_object_freeze_notify (G_OBJECT (self));
9078
9079   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9080   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9081
9082   g_object_thaw_notify (G_OBJECT (self));
9083 }
9084
9085 /**
9086  * clutter_actor_set_scale_full:
9087  * @self: A #ClutterActor
9088  * @scale_x: double factor to scale actor by horizontally.
9089  * @scale_y: double factor to scale actor by vertically.
9090  * @center_x: X coordinate of the center of the scale.
9091  * @center_y: Y coordinate of the center of the scale
9092  *
9093  * Scales an actor with the given factors around the given center
9094  * point. The center point is specified in pixels relative to the
9095  * anchor point (usually the top left corner of the actor).
9096  *
9097  * Since: 1.0
9098  */
9099 void
9100 clutter_actor_set_scale_full (ClutterActor *self,
9101                               gdouble       scale_x,
9102                               gdouble       scale_y,
9103                               gfloat        center_x,
9104                               gfloat        center_y)
9105 {
9106   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9107
9108   g_object_freeze_notify (G_OBJECT (self));
9109
9110   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9111   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9112   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9113   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9114
9115   g_object_thaw_notify (G_OBJECT (self));
9116 }
9117
9118 /**
9119  * clutter_actor_set_scale_with_gravity:
9120  * @self: A #ClutterActor
9121  * @scale_x: double factor to scale actor by horizontally.
9122  * @scale_y: double factor to scale actor by vertically.
9123  * @gravity: the location of the scale center expressed as a compass
9124  * direction.
9125  *
9126  * Scales an actor with the given factors around the given
9127  * center point. The center point is specified as one of the compass
9128  * directions in #ClutterGravity. For example, setting it to north
9129  * will cause the top of the actor to remain unchanged and the rest of
9130  * the actor to expand left, right and downwards.
9131  *
9132  * Since: 1.0
9133  */
9134 void
9135 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9136                                       gdouble         scale_x,
9137                                       gdouble         scale_y,
9138                                       ClutterGravity  gravity)
9139 {
9140   ClutterTransformInfo *info;
9141   GObject *obj;
9142
9143   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9144
9145   obj = G_OBJECT (self);
9146
9147   g_object_freeze_notify (obj);
9148
9149   info = _clutter_actor_get_transform_info (self);
9150   info->scale_x = scale_x;
9151   info->scale_y = scale_y;
9152
9153   if (gravity == CLUTTER_GRAVITY_NONE)
9154     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9155   else
9156     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9157
9158   self->priv->transform_valid = FALSE;
9159
9160   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9161   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9162   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9163   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9164   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9165
9166   clutter_actor_queue_redraw (self);
9167
9168   g_object_thaw_notify (obj);
9169 }
9170
9171 /**
9172  * clutter_actor_get_scale:
9173  * @self: A #ClutterActor
9174  * @scale_x: (out) (allow-none): Location to store horizonal
9175  *   scale factor, or %NULL.
9176  * @scale_y: (out) (allow-none): Location to store vertical
9177  *   scale factor, or %NULL.
9178  *
9179  * Retrieves an actors scale factors.
9180  *
9181  * Since: 0.2
9182  */
9183 void
9184 clutter_actor_get_scale (ClutterActor *self,
9185                          gdouble      *scale_x,
9186                          gdouble      *scale_y)
9187 {
9188   const ClutterTransformInfo *info;
9189
9190   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9191
9192   info = _clutter_actor_get_transform_info_or_defaults (self);
9193
9194   if (scale_x)
9195     *scale_x = info->scale_x;
9196
9197   if (scale_y)
9198     *scale_y = info->scale_y;
9199 }
9200
9201 /**
9202  * clutter_actor_get_scale_center:
9203  * @self: A #ClutterActor
9204  * @center_x: (out) (allow-none): Location to store the X position
9205  *   of the scale center, or %NULL.
9206  * @center_y: (out) (allow-none): Location to store the Y position
9207  *   of the scale center, or %NULL.
9208  *
9209  * Retrieves the scale center coordinate in pixels relative to the top
9210  * left corner of the actor. If the scale center was specified using a
9211  * #ClutterGravity this will calculate the pixel offset using the
9212  * current size of the actor.
9213  *
9214  * Since: 1.0
9215  */
9216 void
9217 clutter_actor_get_scale_center (ClutterActor *self,
9218                                 gfloat       *center_x,
9219                                 gfloat       *center_y)
9220 {
9221   const ClutterTransformInfo *info;
9222
9223   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9224
9225   info = _clutter_actor_get_transform_info_or_defaults (self);
9226
9227   clutter_anchor_coord_get_units (self, &info->scale_center,
9228                                   center_x,
9229                                   center_y,
9230                                   NULL);
9231 }
9232
9233 /**
9234  * clutter_actor_get_scale_gravity:
9235  * @self: A #ClutterActor
9236  *
9237  * Retrieves the scale center as a compass direction. If the scale
9238  * center was specified in pixels or units this will return
9239  * %CLUTTER_GRAVITY_NONE.
9240  *
9241  * Return value: the scale gravity
9242  *
9243  * Since: 1.0
9244  */
9245 ClutterGravity
9246 clutter_actor_get_scale_gravity (ClutterActor *self)
9247 {
9248   const ClutterTransformInfo *info;
9249
9250   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9251
9252   info = _clutter_actor_get_transform_info_or_defaults (self);
9253
9254   return clutter_anchor_coord_get_gravity (&info->scale_center);
9255 }
9256
9257 /**
9258  * clutter_actor_set_opacity:
9259  * @self: A #ClutterActor
9260  * @opacity: New opacity value for the actor.
9261  *
9262  * Sets the actor's opacity, with zero being completely transparent and
9263  * 255 (0xff) being fully opaque.
9264  */
9265 void
9266 clutter_actor_set_opacity (ClutterActor *self,
9267                            guint8        opacity)
9268 {
9269   ClutterActorPrivate *priv;
9270
9271   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9272
9273   priv = self->priv;
9274
9275   if (priv->opacity != opacity)
9276     {
9277       priv->opacity = opacity;
9278
9279       /* Queue a redraw from the flatten effect so that it can use
9280          its cached image if available instead of having to redraw the
9281          actual actor. If it doesn't end up using the FBO then the
9282          effect is still able to continue the paint anyway. If there
9283          is no flatten effect yet then this is equivalent to queueing
9284          a full redraw */
9285       _clutter_actor_queue_redraw_full (self,
9286                                         0, /* flags */
9287                                         NULL, /* clip */
9288                                         priv->flatten_effect);
9289
9290       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9291     }
9292 }
9293
9294 /*
9295  * clutter_actor_get_paint_opacity_internal:
9296  * @self: a #ClutterActor
9297  *
9298  * Retrieves the absolute opacity of the actor, as it appears on the stage
9299  *
9300  * This function does not do type checks
9301  *
9302  * Return value: the absolute opacity of the actor
9303  */
9304 static guint8
9305 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9306 {
9307   ClutterActorPrivate *priv = self->priv;
9308   ClutterActor *parent;
9309
9310   /* override the top-level opacity to always be 255; even in
9311    * case of ClutterStage:use-alpha being TRUE we want the rest
9312    * of the scene to be painted
9313    */
9314   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9315     return 255;
9316
9317   if (priv->opacity_override >= 0)
9318     return priv->opacity_override;
9319
9320   parent = priv->parent;
9321
9322   /* Factor in the actual actors opacity with parents */
9323   if (parent != NULL)
9324     {
9325       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9326
9327       if (opacity != 0xff)
9328         return (opacity * priv->opacity) / 0xff;
9329     }
9330
9331   return priv->opacity;
9332
9333 }
9334
9335 /**
9336  * clutter_actor_get_paint_opacity:
9337  * @self: A #ClutterActor
9338  *
9339  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9340  *
9341  * This function traverses the hierarchy chain and composites the opacity of
9342  * the actor with that of its parents.
9343  *
9344  * This function is intended for subclasses to use in the paint virtual
9345  * function, to paint themselves with the correct opacity.
9346  *
9347  * Return value: The actor opacity value.
9348  *
9349  * Since: 0.8
9350  */
9351 guint8
9352 clutter_actor_get_paint_opacity (ClutterActor *self)
9353 {
9354   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9355
9356   return clutter_actor_get_paint_opacity_internal (self);
9357 }
9358
9359 /**
9360  * clutter_actor_get_opacity:
9361  * @self: a #ClutterActor
9362  *
9363  * Retrieves the opacity value of an actor, as set by
9364  * clutter_actor_set_opacity().
9365  *
9366  * For retrieving the absolute opacity of the actor inside a paint
9367  * virtual function, see clutter_actor_get_paint_opacity().
9368  *
9369  * Return value: the opacity of the actor
9370  */
9371 guint8
9372 clutter_actor_get_opacity (ClutterActor *self)
9373 {
9374   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9375
9376   return self->priv->opacity;
9377 }
9378
9379 /**
9380  * clutter_actor_set_offscreen_redirect:
9381  * @self: A #ClutterActor
9382  * @redirect: New offscreen redirect flags for the actor.
9383  *
9384  * Defines the circumstances where the actor should be redirected into
9385  * an offscreen image. The offscreen image is used to flatten the
9386  * actor into a single image while painting for two main reasons.
9387  * Firstly, when the actor is painted a second time without any of its
9388  * contents changing it can simply repaint the cached image without
9389  * descending further down the actor hierarchy. Secondly, it will make
9390  * the opacity look correct even if there are overlapping primitives
9391  * in the actor.
9392  *
9393  * Caching the actor could in some cases be a performance win and in
9394  * some cases be a performance lose so it is important to determine
9395  * which value is right for an actor before modifying this value. For
9396  * example, there is never any reason to flatten an actor that is just
9397  * a single texture (such as a #ClutterTexture) because it is
9398  * effectively already cached in an image so the offscreen would be
9399  * redundant. Also if the actor contains primitives that are far apart
9400  * with a large transparent area in the middle (such as a large
9401  * CluterGroup with a small actor in the top left and a small actor in
9402  * the bottom right) then the cached image will contain the entire
9403  * image of the large area and the paint will waste time blending all
9404  * of the transparent pixels in the middle.
9405  *
9406  * The default method of implementing opacity on a container simply
9407  * forwards on the opacity to all of the children. If the children are
9408  * overlapping then it will appear as if they are two separate glassy
9409  * objects and there will be a break in the color where they
9410  * overlap. By redirecting to an offscreen buffer it will be as if the
9411  * two opaque objects are combined into one and then made transparent
9412  * which is usually what is expected.
9413  *
9414  * The image below demonstrates the difference between redirecting and
9415  * not. The image shows two Clutter groups, each containing a red and
9416  * a green rectangle which overlap. The opacity on the group is set to
9417  * 128 (which is 50%). When the offscreen redirect is not used, the
9418  * red rectangle can be seen through the blue rectangle as if the two
9419  * rectangles were separately transparent. When the redirect is used
9420  * the group as a whole is transparent instead so the red rectangle is
9421  * not visible where they overlap.
9422  *
9423  * <figure id="offscreen-redirect">
9424  *   <title>Sample of using an offscreen redirect for transparency</title>
9425  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9426  * </figure>
9427  *
9428  * The default value for this property is 0, so we effectively will
9429  * never redirect an actor offscreen by default. This means that there
9430  * are times that transparent actors may look glassy as described
9431  * above. The reason this is the default is because there is a
9432  * performance trade off between quality and performance here. In many
9433  * cases the default form of glassy opacity looks good enough, but if
9434  * it's not you will need to set the
9435  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9436  * redirection for opacity.
9437  *
9438  * Custom actors that don't contain any overlapping primitives are
9439  * recommended to override the has_overlaps() virtual to return %FALSE
9440  * for maximum efficiency.
9441  *
9442  * Since: 1.8
9443  */
9444 void
9445 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9446                                       ClutterOffscreenRedirect redirect)
9447 {
9448   ClutterActorPrivate *priv;
9449
9450   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9451
9452   priv = self->priv;
9453
9454   if (priv->offscreen_redirect != redirect)
9455     {
9456       priv->offscreen_redirect = redirect;
9457
9458       /* Queue a redraw from the effect so that it can use its cached
9459          image if available instead of having to redraw the actual
9460          actor. If it doesn't end up using the FBO then the effect is
9461          still able to continue the paint anyway. If there is no
9462          effect then this is equivalent to queuing a full redraw */
9463       _clutter_actor_queue_redraw_full (self,
9464                                         0, /* flags */
9465                                         NULL, /* clip */
9466                                         priv->flatten_effect);
9467
9468       g_object_notify_by_pspec (G_OBJECT (self),
9469                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9470     }
9471 }
9472
9473 /**
9474  * clutter_actor_get_offscreen_redirect:
9475  * @self: a #ClutterActor
9476  *
9477  * Retrieves whether to redirect the actor to an offscreen buffer, as
9478  * set by clutter_actor_set_offscreen_redirect().
9479  *
9480  * Return value: the value of the offscreen-redirect property of the actor
9481  *
9482  * Since: 1.8
9483  */
9484 ClutterOffscreenRedirect
9485 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9486 {
9487   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9488
9489   return self->priv->offscreen_redirect;
9490 }
9491
9492 /**
9493  * clutter_actor_set_name:
9494  * @self: A #ClutterActor
9495  * @name: Textual tag to apply to actor
9496  *
9497  * Sets the given name to @self. The name can be used to identify
9498  * a #ClutterActor.
9499  */
9500 void
9501 clutter_actor_set_name (ClutterActor *self,
9502                         const gchar  *name)
9503 {
9504   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9505
9506   g_free (self->priv->name);
9507   self->priv->name = g_strdup (name);
9508
9509   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9510 }
9511
9512 /**
9513  * clutter_actor_get_name:
9514  * @self: A #ClutterActor
9515  *
9516  * Retrieves the name of @self.
9517  *
9518  * Return value: the name of the actor, or %NULL. The returned string is
9519  *   owned by the actor and should not be modified or freed.
9520  */
9521 const gchar *
9522 clutter_actor_get_name (ClutterActor *self)
9523 {
9524   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9525
9526   return self->priv->name;
9527 }
9528
9529 /**
9530  * clutter_actor_get_gid:
9531  * @self: A #ClutterActor
9532  *
9533  * Retrieves the unique id for @self.
9534  *
9535  * Return value: Globally unique value for this object instance.
9536  *
9537  * Since: 0.6
9538  *
9539  * Deprecated: 1.8: The id is not used any longer.
9540  */
9541 guint32
9542 clutter_actor_get_gid (ClutterActor *self)
9543 {
9544   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9545
9546   return self->priv->id;
9547 }
9548
9549 /**
9550  * clutter_actor_set_depth:
9551  * @self: a #ClutterActor
9552  * @depth: Z co-ord
9553  *
9554  * Sets the Z coordinate of @self to @depth.
9555  *
9556  * The unit used by @depth is dependant on the perspective setup. See
9557  * also clutter_stage_set_perspective().
9558  */
9559 void
9560 clutter_actor_set_depth (ClutterActor *self,
9561                          gfloat        depth)
9562 {
9563   ClutterActorPrivate *priv;
9564
9565   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9566
9567   priv = self->priv;
9568
9569   if (priv->z != depth)
9570     {
9571       /* Sets Z value - XXX 2.0: should we invert? */
9572       priv->z = depth;
9573
9574       priv->transform_valid = FALSE;
9575
9576       /* FIXME - remove this crap; sadly, there are still containers
9577        * in Clutter that depend on this utter brain damage
9578        */
9579       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9580
9581       clutter_actor_queue_redraw (self);
9582
9583       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9584     }
9585 }
9586
9587 /**
9588  * clutter_actor_get_depth:
9589  * @self: a #ClutterActor
9590  *
9591  * Retrieves the depth of @self.
9592  *
9593  * Return value: the depth of the actor
9594  */
9595 gfloat
9596 clutter_actor_get_depth (ClutterActor *self)
9597 {
9598   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
9599
9600   return self->priv->z;
9601 }
9602
9603 /**
9604  * clutter_actor_set_rotation:
9605  * @self: a #ClutterActor
9606  * @axis: the axis of rotation
9607  * @angle: the angle of rotation
9608  * @x: X coordinate of the rotation center
9609  * @y: Y coordinate of the rotation center
9610  * @z: Z coordinate of the rotation center
9611  *
9612  * Sets the rotation angle of @self around the given axis.
9613  *
9614  * The rotation center coordinates used depend on the value of @axis:
9615  * <itemizedlist>
9616  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
9617  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
9618  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
9619  * </itemizedlist>
9620  *
9621  * The rotation coordinates are relative to the anchor point of the
9622  * actor, set using clutter_actor_set_anchor_point(). If no anchor
9623  * point is set, the upper left corner is assumed as the origin.
9624  *
9625  * Since: 0.8
9626  */
9627 void
9628 clutter_actor_set_rotation (ClutterActor      *self,
9629                             ClutterRotateAxis  axis,
9630                             gdouble            angle,
9631                             gfloat             x,
9632                             gfloat             y,
9633                             gfloat             z)
9634 {
9635   ClutterVertex v;
9636
9637   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9638
9639   v.x = x;
9640   v.y = y;
9641   v.z = z;
9642
9643   g_object_freeze_notify (G_OBJECT (self));
9644
9645   clutter_actor_set_rotation_angle_internal (self, axis, angle);
9646   clutter_actor_set_rotation_center_internal (self, axis, &v);
9647
9648   g_object_thaw_notify (G_OBJECT (self));
9649 }
9650
9651 /**
9652  * clutter_actor_set_z_rotation_from_gravity:
9653  * @self: a #ClutterActor
9654  * @angle: the angle of rotation
9655  * @gravity: the center point of the rotation
9656  *
9657  * Sets the rotation angle of @self around the Z axis using the center
9658  * point specified as a compass point. For example to rotate such that
9659  * the center of the actor remains static you can use
9660  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
9661  * will move accordingly.
9662  *
9663  * Since: 1.0
9664  */
9665 void
9666 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
9667                                            gdouble         angle,
9668                                            ClutterGravity  gravity)
9669 {
9670   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9671
9672   if (gravity == CLUTTER_GRAVITY_NONE)
9673     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
9674   else
9675     {
9676       GObject *obj = G_OBJECT (self);
9677       ClutterTransformInfo *info;
9678
9679       info = _clutter_actor_get_transform_info (self);
9680
9681       g_object_freeze_notify (obj);
9682
9683       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
9684
9685       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
9686       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
9687       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
9688
9689       g_object_thaw_notify (obj);
9690     }
9691 }
9692
9693 /**
9694  * clutter_actor_get_rotation:
9695  * @self: a #ClutterActor
9696  * @axis: the axis of rotation
9697  * @x: (out): return value for the X coordinate of the center of rotation
9698  * @y: (out): return value for the Y coordinate of the center of rotation
9699  * @z: (out): return value for the Z coordinate of the center of rotation
9700  *
9701  * Retrieves the angle and center of rotation on the given axis,
9702  * set using clutter_actor_set_rotation().
9703  *
9704  * Return value: the angle of rotation
9705  *
9706  * Since: 0.8
9707  */
9708 gdouble
9709 clutter_actor_get_rotation (ClutterActor      *self,
9710                             ClutterRotateAxis  axis,
9711                             gfloat            *x,
9712                             gfloat            *y,
9713                             gfloat            *z)
9714 {
9715   const ClutterTransformInfo *info;
9716   const AnchorCoord *anchor_coord;
9717   gdouble retval = 0;
9718
9719   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9720
9721   info = _clutter_actor_get_transform_info_or_defaults (self);
9722
9723   switch (axis)
9724     {
9725     case CLUTTER_X_AXIS:
9726       anchor_coord = &info->rx_center;
9727       retval = info->rx_angle;
9728       break;
9729
9730     case CLUTTER_Y_AXIS:
9731       anchor_coord = &info->ry_center;
9732       retval = info->ry_angle;
9733       break;
9734
9735     case CLUTTER_Z_AXIS:
9736       anchor_coord = &info->rz_center;
9737       retval = info->rz_angle;
9738       break;
9739
9740     default:
9741       anchor_coord = NULL;
9742       retval = 0.0;
9743       break;
9744     }
9745
9746   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
9747
9748   return retval;
9749 }
9750
9751 /**
9752  * clutter_actor_get_z_rotation_gravity:
9753  * @self: A #ClutterActor
9754  *
9755  * Retrieves the center for the rotation around the Z axis as a
9756  * compass direction. If the center was specified in pixels or units
9757  * this will return %CLUTTER_GRAVITY_NONE.
9758  *
9759  * Return value: the Z rotation center
9760  *
9761  * Since: 1.0
9762  */
9763 ClutterGravity
9764 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
9765 {
9766   const ClutterTransformInfo *info;
9767
9768   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9769
9770   info = _clutter_actor_get_transform_info_or_defaults (self);
9771
9772   return clutter_anchor_coord_get_gravity (&info->rz_center);
9773 }
9774
9775 /**
9776  * clutter_actor_set_clip:
9777  * @self: A #ClutterActor
9778  * @xoff: X offset of the clip rectangle
9779  * @yoff: Y offset of the clip rectangle
9780  * @width: Width of the clip rectangle
9781  * @height: Height of the clip rectangle
9782  *
9783  * Sets clip area for @self. The clip area is always computed from the
9784  * upper left corner of the actor, even if the anchor point is set
9785  * otherwise.
9786  *
9787  * Since: 0.6
9788  */
9789 void
9790 clutter_actor_set_clip (ClutterActor *self,
9791                         gfloat        xoff,
9792                         gfloat        yoff,
9793                         gfloat        width,
9794                         gfloat        height)
9795 {
9796   ClutterActorPrivate *priv;
9797
9798   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9799
9800   priv = self->priv;
9801
9802   if (priv->has_clip &&
9803       priv->clip.x == xoff &&
9804       priv->clip.y == yoff &&
9805       priv->clip.width == width &&
9806       priv->clip.height == height)
9807     return;
9808
9809   priv->clip.x = xoff;
9810   priv->clip.y = yoff;
9811   priv->clip.width = width;
9812   priv->clip.height = height;
9813
9814   priv->has_clip = TRUE;
9815
9816   clutter_actor_queue_redraw (self);
9817
9818   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9819   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
9820 }
9821
9822 /**
9823  * clutter_actor_remove_clip:
9824  * @self: A #ClutterActor
9825  *
9826  * Removes clip area from @self.
9827  */
9828 void
9829 clutter_actor_remove_clip (ClutterActor *self)
9830 {
9831   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9832
9833   if (!self->priv->has_clip)
9834     return;
9835
9836   self->priv->has_clip = FALSE;
9837
9838   clutter_actor_queue_redraw (self);
9839
9840   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9841 }
9842
9843 /**
9844  * clutter_actor_has_clip:
9845  * @self: a #ClutterActor
9846  *
9847  * Determines whether the actor has a clip area set or not.
9848  *
9849  * Return value: %TRUE if the actor has a clip area set.
9850  *
9851  * Since: 0.1.1
9852  */
9853 gboolean
9854 clutter_actor_has_clip (ClutterActor *self)
9855 {
9856   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9857
9858   return self->priv->has_clip;
9859 }
9860
9861 /**
9862  * clutter_actor_get_clip:
9863  * @self: a #ClutterActor
9864  * @xoff: (out) (allow-none): return location for the X offset of
9865  *   the clip rectangle, or %NULL
9866  * @yoff: (out) (allow-none): return location for the Y offset of
9867  *   the clip rectangle, or %NULL
9868  * @width: (out) (allow-none): return location for the width of
9869  *   the clip rectangle, or %NULL
9870  * @height: (out) (allow-none): return location for the height of
9871  *   the clip rectangle, or %NULL
9872  *
9873  * Gets the clip area for @self, if any is set
9874  *
9875  * Since: 0.6
9876  */
9877 void
9878 clutter_actor_get_clip (ClutterActor *self,
9879                         gfloat       *xoff,
9880                         gfloat       *yoff,
9881                         gfloat       *width,
9882                         gfloat       *height)
9883 {
9884   ClutterActorPrivate *priv;
9885
9886   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9887
9888   priv = self->priv;
9889
9890   if (!priv->has_clip)
9891     return;
9892
9893   if (xoff != NULL)
9894     *xoff = priv->clip.x;
9895
9896   if (yoff != NULL)
9897     *yoff = priv->clip.y;
9898
9899   if (width != NULL)
9900     *width = priv->clip.width;
9901
9902   if (height != NULL)
9903     *height = priv->clip.height;
9904 }
9905
9906 /**
9907  * clutter_actor_get_children:
9908  * @self: a #ClutterActor
9909  *
9910  * Retrieves the list of children of @self.
9911  *
9912  * Return value: (transfer container) (element-type ClutterActor): A newly
9913  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
9914  *   done.
9915  *
9916  * Since: 1.10
9917  */
9918 GList *
9919 clutter_actor_get_children (ClutterActor *self)
9920 {
9921   ClutterActor *iter;
9922   GList *res;
9923
9924   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9925
9926   /* we walk the list backward so that we can use prepend(),
9927    * which is O(1)
9928    */
9929   for (iter = self->priv->last_child, res = NULL;
9930        iter != NULL;
9931        iter = iter->priv->prev_sibling)
9932     {
9933       res = g_list_prepend (res, iter);
9934     }
9935
9936   return res;
9937 }
9938
9939 /*< private >
9940  * insert_child_at_depth:
9941  * @self: a #ClutterActor
9942  * @child: a #ClutterActor
9943  *
9944  * Inserts @child inside the list of children held by @self, using
9945  * the depth as the insertion criteria.
9946  *
9947  * This sadly makes the insertion not O(1), but we can keep the
9948  * list sorted so that the painters algorithm we use for painting
9949  * the children will work correctly.
9950  */
9951 static void
9952 insert_child_at_depth (ClutterActor *self,
9953                        ClutterActor *child,
9954                        gpointer      dummy G_GNUC_UNUSED)
9955 {
9956   ClutterActor *iter;
9957
9958   child->priv->parent = self;
9959
9960   /* special-case the first child */
9961   if (self->priv->n_children == 0)
9962     {
9963       self->priv->first_child = child;
9964       self->priv->last_child = child;
9965
9966       child->priv->next_sibling = NULL;
9967       child->priv->prev_sibling = NULL;
9968
9969       return;
9970     }
9971
9972   /* Find the right place to insert the child so that it will still be
9973      sorted and the child will be after all of the actors at the same
9974      dept */
9975   for (iter = self->priv->first_child;
9976        iter != NULL;
9977        iter = iter->priv->next_sibling)
9978     {
9979       if (iter->priv->z > child->priv->z)
9980         break;
9981     }
9982
9983   if (iter != NULL)
9984     {
9985       ClutterActor *tmp = iter->priv->prev_sibling;
9986
9987       if (tmp != NULL)
9988         tmp->priv->next_sibling = child;
9989
9990       /* Insert the node before the found one */
9991       child->priv->prev_sibling = iter->priv->prev_sibling;
9992       child->priv->next_sibling = iter;
9993       iter->priv->prev_sibling = child;
9994     }
9995   else
9996     {
9997       ClutterActor *tmp = self->priv->last_child;
9998
9999       if (tmp != NULL)
10000         tmp->priv->next_sibling = child;
10001
10002       /* insert the node at the end of the list */
10003       child->priv->prev_sibling = self->priv->last_child;
10004       child->priv->next_sibling = NULL;
10005     }
10006
10007   if (child->priv->prev_sibling == NULL)
10008     self->priv->first_child = child;
10009
10010   if (child->priv->next_sibling == NULL)
10011     self->priv->last_child = child;
10012 }
10013
10014 static void
10015 insert_child_at_index (ClutterActor *self,
10016                        ClutterActor *child,
10017                        gpointer      data_)
10018 {
10019   gint index_ = GPOINTER_TO_INT (data_);
10020
10021   child->priv->parent = self;
10022
10023   if (index_ == 0)
10024     {
10025       ClutterActor *tmp = self->priv->first_child;
10026
10027       if (tmp != NULL)
10028         tmp->priv->prev_sibling = child;
10029
10030       child->priv->prev_sibling = NULL;
10031       child->priv->next_sibling = tmp;
10032     }
10033   else if (index_ < 0 || index_ >= self->priv->n_children)
10034     {
10035       ClutterActor *tmp = self->priv->last_child;
10036
10037       if (tmp != NULL)
10038         tmp->priv->next_sibling = child;
10039
10040       child->priv->prev_sibling = tmp;
10041       child->priv->next_sibling = NULL;
10042     }
10043   else
10044     {
10045       ClutterActor *iter;
10046       int i;
10047
10048       for (iter = self->priv->first_child, i = 0;
10049            iter != NULL;
10050            iter = iter->priv->next_sibling, i += 1)
10051         {
10052           if (index_ == i)
10053             {
10054               ClutterActor *tmp = iter->priv->prev_sibling;
10055
10056               child->priv->prev_sibling = tmp;
10057               child->priv->next_sibling = iter;
10058
10059               iter->priv->prev_sibling = child;
10060
10061               if (tmp != NULL)
10062                 tmp->priv->next_sibling = child;
10063
10064               break;
10065             }
10066         }
10067     }
10068
10069   if (child->priv->prev_sibling == NULL)
10070     self->priv->first_child = child;
10071
10072   if (child->priv->next_sibling == NULL)
10073     self->priv->last_child = child;
10074 }
10075
10076 static void
10077 insert_child_above (ClutterActor *self,
10078                     ClutterActor *child,
10079                     gpointer      data)
10080 {
10081   ClutterActor *sibling = data;
10082
10083   child->priv->parent = self;
10084
10085   if (sibling == NULL)
10086     sibling = self->priv->last_child;
10087
10088   child->priv->prev_sibling = sibling;
10089
10090   if (sibling != NULL)
10091     {
10092       ClutterActor *tmp = sibling->priv->next_sibling;
10093
10094       child->priv->next_sibling = tmp;
10095
10096       if (tmp != NULL)
10097         tmp->priv->prev_sibling = child;
10098
10099       sibling->priv->next_sibling = child;
10100     }
10101   else
10102     child->priv->next_sibling = NULL;
10103
10104   if (child->priv->prev_sibling == NULL)
10105     self->priv->first_child = child;
10106
10107   if (child->priv->next_sibling == NULL)
10108     self->priv->last_child = child;
10109 }
10110
10111 static void
10112 insert_child_below (ClutterActor *self,
10113                     ClutterActor *child,
10114                     gpointer      data)
10115 {
10116   ClutterActor *sibling = data;
10117
10118   child->priv->parent = self;
10119
10120   if (sibling == NULL)
10121     sibling = self->priv->first_child;
10122
10123   child->priv->next_sibling = sibling;
10124
10125   if (sibling != NULL)
10126     {
10127       ClutterActor *tmp = sibling->priv->prev_sibling;
10128
10129       child->priv->prev_sibling = tmp;
10130
10131       if (tmp != NULL)
10132         tmp->priv->next_sibling = child;
10133
10134       sibling->priv->prev_sibling = child;
10135     }
10136   else
10137     child->priv->prev_sibling = NULL;
10138
10139   if (child->priv->prev_sibling == NULL)
10140     self->priv->first_child = child;
10141
10142   if (child->priv->next_sibling == NULL)
10143     self->priv->last_child = child;
10144 }
10145
10146 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10147                                            ClutterActor *child,
10148                                            gpointer      data);
10149
10150 typedef enum {
10151   ADD_CHILD_CREATE_META       = 1 << 0,
10152   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10153   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10154   ADD_CHILD_CHECK_STATE       = 1 << 3,
10155   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10156
10157   /* default flags for public API */
10158   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10159                                ADD_CHILD_EMIT_PARENT_SET |
10160                                ADD_CHILD_EMIT_ACTOR_ADDED |
10161                                ADD_CHILD_CHECK_STATE |
10162                                ADD_CHILD_NOTIFY_FIRST_LAST,
10163
10164   /* flags for legacy/deprecated API */
10165   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10166                                ADD_CHILD_CHECK_STATE |
10167                                ADD_CHILD_NOTIFY_FIRST_LAST
10168 } ClutterActorAddChildFlags;
10169
10170 /*< private >
10171  * clutter_actor_add_child_internal:
10172  * @self: a #ClutterActor
10173  * @child: a #ClutterActor
10174  * @flags: control flags for actions
10175  * @add_func: delegate function
10176  * @data: (closure): data to pass to @add_func
10177  *
10178  * Adds @child to the list of children of @self.
10179  *
10180  * The actual insertion inside the list is delegated to @add_func: this
10181  * function will just set up the state, perform basic checks, and emit
10182  * signals.
10183  *
10184  * The @flags argument is used to perform additional operations.
10185  */
10186 static inline void
10187 clutter_actor_add_child_internal (ClutterActor              *self,
10188                                   ClutterActor              *child,
10189                                   ClutterActorAddChildFlags  flags,
10190                                   ClutterActorAddChildFunc   add_func,
10191                                   gpointer                   data)
10192 {
10193   ClutterTextDirection text_dir;
10194   gboolean create_meta;
10195   gboolean emit_parent_set, emit_actor_added;
10196   gboolean check_state;
10197   gboolean notify_first_last;
10198   ClutterActor *old_first_child, *old_last_child;
10199
10200   if (child->priv->parent != NULL)
10201     {
10202       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10203                  "use clutter_actor_remove_child() first.",
10204                  _clutter_actor_get_debug_name (child),
10205                  _clutter_actor_get_debug_name (child->priv->parent));
10206       return;
10207     }
10208
10209   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10210     {
10211       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10212                  "a child of another actor.",
10213                  _clutter_actor_get_debug_name (child));
10214       return;
10215     }
10216
10217 #if 0
10218   /* XXX - this check disallows calling methods that change the stacking
10219    * order within the destruction sequence, by triggering a critical
10220    * warning first, and leaving the actor in an undefined state, which
10221    * then ends up being caught by an assertion.
10222    *
10223    * the reproducible sequence is:
10224    *
10225    *   - actor gets destroyed;
10226    *   - another actor, linked to the first, will try to change the
10227    *     stacking order of the first actor;
10228    *   - changing the stacking order is a composite operation composed
10229    *     by the following steps:
10230    *     1. ref() the child;
10231    *     2. remove_child_internal(), which removes the reference;
10232    *     3. add_child_internal(), which adds a reference;
10233    *   - the state of the actor is not changed between (2) and (3), as
10234    *     it could be an expensive recomputation;
10235    *   - if (3) bails out, then the actor is in an undefined state, but
10236    *     still alive;
10237    *   - the destruction sequence terminates, but the actor is unparented
10238    *     while its state indicates being parented instead.
10239    *   - assertion failure.
10240    *
10241    * the obvious fix would be to decompose each set_child_*_sibling()
10242    * method into proper remove_child()/add_child(), with state validation;
10243    * this may cause excessive work, though, and trigger a cascade of other
10244    * bugs in code that assumes that a change in the stacking order is an
10245    * atomic operation.
10246    *
10247    * another potential fix is to just remove this check here, and let
10248    * code doing stacking order changes inside the destruction sequence
10249    * of an actor continue doing the work.
10250    *
10251    * the third fix is to silently bail out early from every
10252    * set_child_*_sibling() and set_child_at_index() method, and avoid
10253    * doing work.
10254    *
10255    * I have a preference for the second solution, since it involves the
10256    * least amount of work, and the least amount of code duplication.
10257    *
10258    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10259    */
10260   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10261     {
10262       g_warning ("The actor '%s' is currently being destroyed, and "
10263                  "cannot be added as a child of another actor.",
10264                  _clutter_actor_get_debug_name (child));
10265       return;
10266     }
10267 #endif
10268
10269   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10270   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10271   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10272   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10273   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10274
10275   old_first_child = self->priv->first_child;
10276   old_last_child = self->priv->last_child;
10277
10278   g_object_freeze_notify (G_OBJECT (self));
10279
10280   if (create_meta)
10281     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10282
10283   g_object_ref_sink (child);
10284   child->priv->parent = NULL;
10285   child->priv->next_sibling = NULL;
10286   child->priv->prev_sibling = NULL;
10287
10288   /* delegate the actual insertion */
10289   add_func (self, child, data);
10290
10291   g_assert (child->priv->parent == self);
10292
10293   self->priv->n_children += 1;
10294
10295   self->priv->age += 1;
10296
10297   /* if push_internal() has been called then we automatically set
10298    * the flag on the actor
10299    */
10300   if (self->priv->internal_child)
10301     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10302
10303   /* clutter_actor_reparent() will emit ::parent-set for us */
10304   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10305     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10306
10307   if (check_state)
10308     {
10309       /* If parent is mapped or realized, we need to also be mapped or
10310        * realized once we're inside the parent.
10311        */
10312       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10313
10314       /* propagate the parent's text direction to the child */
10315       text_dir = clutter_actor_get_text_direction (self);
10316       clutter_actor_set_text_direction (child, text_dir);
10317     }
10318
10319   if (child->priv->show_on_set_parent)
10320     clutter_actor_show (child);
10321
10322   if (CLUTTER_ACTOR_IS_MAPPED (child))
10323     clutter_actor_queue_redraw (child);
10324
10325   /* maintain the invariant that if an actor needs layout,
10326    * its parents do as well
10327    */
10328   if (child->priv->needs_width_request ||
10329       child->priv->needs_height_request ||
10330       child->priv->needs_allocation)
10331     {
10332       /* we work around the short-circuiting we do
10333        * in clutter_actor_queue_relayout() since we
10334        * want to force a relayout
10335        */
10336       child->priv->needs_width_request = TRUE;
10337       child->priv->needs_height_request = TRUE;
10338       child->priv->needs_allocation = TRUE;
10339
10340       clutter_actor_queue_relayout (child->priv->parent);
10341     }
10342
10343   if (emit_actor_added)
10344     g_signal_emit_by_name (self, "actor-added", child);
10345
10346   if (notify_first_last)
10347     {
10348       if (old_first_child != self->priv->first_child)
10349         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10350
10351       if (old_last_child != self->priv->last_child)
10352         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10353     }
10354
10355   g_object_thaw_notify (G_OBJECT (self));
10356 }
10357
10358 /**
10359  * clutter_actor_add_child:
10360  * @self: a #ClutterActor
10361  * @child: a #ClutterActor
10362  *
10363  * Adds @child to the children of @self.
10364  *
10365  * This function will acquire a reference on @child that will only
10366  * be released when calling clutter_actor_remove_child().
10367  *
10368  * This function will take into consideration the #ClutterActor:depth
10369  * of @child, and will keep the list of children sorted.
10370  *
10371  * This function will emit the #ClutterContainer::actor-added signal
10372  * on @self.
10373  *
10374  * Since: 1.10
10375  */
10376 void
10377 clutter_actor_add_child (ClutterActor *self,
10378                          ClutterActor *child)
10379 {
10380   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10381   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10382   g_return_if_fail (self != child);
10383   g_return_if_fail (child->priv->parent == NULL);
10384
10385   clutter_actor_add_child_internal (self, child,
10386                                     ADD_CHILD_DEFAULT_FLAGS,
10387                                     insert_child_at_depth,
10388                                     NULL);
10389 }
10390
10391 /**
10392  * clutter_actor_insert_child_at_index:
10393  * @self: a #ClutterActor
10394  * @child: a #ClutterActor
10395  * @index_: the index
10396  *
10397  * Inserts @child into the list of children of @self, using the
10398  * given @index_. If @index_ is greater than the number of children
10399  * in @self, or is less than 0, then the new child is added at the end.
10400  *
10401  * This function will acquire a reference on @child that will only
10402  * be released when calling clutter_actor_remove_child().
10403  *
10404  * This function will not take into consideration the #ClutterActor:depth
10405  * of @child.
10406  *
10407  * This function will emit the #ClutterContainer::actor-added signal
10408  * on @self.
10409  *
10410  * Since: 1.10
10411  */
10412 void
10413 clutter_actor_insert_child_at_index (ClutterActor *self,
10414                                      ClutterActor *child,
10415                                      gint          index_)
10416 {
10417   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10418   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10419   g_return_if_fail (self != child);
10420   g_return_if_fail (child->priv->parent == NULL);
10421
10422   clutter_actor_add_child_internal (self, child,
10423                                     ADD_CHILD_DEFAULT_FLAGS,
10424                                     insert_child_at_index,
10425                                     GINT_TO_POINTER (index_));
10426 }
10427
10428 /**
10429  * clutter_actor_insert_child_above:
10430  * @self: a #ClutterActor
10431  * @child: a #ClutterActor
10432  * @sibling: (allow-none): a child of @self, or %NULL
10433  *
10434  * Inserts @child into the list of children of @self, above another
10435  * child of @self or, if @sibling is %NULL, above all the children
10436  * of @self.
10437  *
10438  * This function will acquire a reference on @child that will only
10439  * be released when calling clutter_actor_remove_child().
10440  *
10441  * This function will not take into consideration the #ClutterActor:depth
10442  * of @child.
10443  *
10444  * This function will emit the #ClutterContainer::actor-added signal
10445  * on @self.
10446  *
10447  * Since: 1.10
10448  */
10449 void
10450 clutter_actor_insert_child_above (ClutterActor *self,
10451                                   ClutterActor *child,
10452                                   ClutterActor *sibling)
10453 {
10454   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10455   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10456   g_return_if_fail (self != child);
10457   g_return_if_fail (child != sibling);
10458   g_return_if_fail (child->priv->parent == NULL);
10459   g_return_if_fail (sibling == NULL ||
10460                     (CLUTTER_IS_ACTOR (sibling) &&
10461                      sibling->priv->parent == self));
10462
10463   clutter_actor_add_child_internal (self, child,
10464                                     ADD_CHILD_DEFAULT_FLAGS,
10465                                     insert_child_above,
10466                                     sibling);
10467 }
10468
10469 /**
10470  * clutter_actor_insert_child_below:
10471  * @self: a #ClutterActor
10472  * @child: a #ClutterActor
10473  * @sibling: (allow-none): a child of @self, or %NULL
10474  *
10475  * Inserts @child into the list of children of @self, below another
10476  * child of @self or, if @sibling is %NULL, below all the children
10477  * of @self.
10478  *
10479  * This function will acquire a reference on @child that will only
10480  * be released when calling clutter_actor_remove_child().
10481  *
10482  * This function will not take into consideration the #ClutterActor:depth
10483  * of @child.
10484  *
10485  * This function will emit the #ClutterContainer::actor-added signal
10486  * on @self.
10487  *
10488  * Since: 1.10
10489  */
10490 void
10491 clutter_actor_insert_child_below (ClutterActor *self,
10492                                   ClutterActor *child,
10493                                   ClutterActor *sibling)
10494 {
10495   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10496   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10497   g_return_if_fail (self != child);
10498   g_return_if_fail (child != sibling);
10499   g_return_if_fail (child->priv->parent == NULL);
10500   g_return_if_fail (sibling == NULL ||
10501                     (CLUTTER_IS_ACTOR (sibling) &&
10502                      sibling->priv->parent == self));
10503
10504   clutter_actor_add_child_internal (self, child,
10505                                     ADD_CHILD_DEFAULT_FLAGS,
10506                                     insert_child_below,
10507                                     sibling);
10508 }
10509
10510 /**
10511  * clutter_actor_set_parent:
10512  * @self: A #ClutterActor
10513  * @parent: A new #ClutterActor parent
10514  *
10515  * Sets the parent of @self to @parent.
10516  *
10517  * This function will result in @parent acquiring a reference on @self,
10518  * eventually by sinking its floating reference first. The reference
10519  * will be released by clutter_actor_unparent().
10520  *
10521  * This function should only be called by legacy #ClutterActor<!-- -->s
10522  * implementing the #ClutterContainer interface.
10523  *
10524  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10525  */
10526 void
10527 clutter_actor_set_parent (ClutterActor *self,
10528                           ClutterActor *parent)
10529 {
10530   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10531   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10532   g_return_if_fail (self != parent);
10533   g_return_if_fail (self->priv->parent == NULL);
10534
10535   /* as this function will be called inside ClutterContainer::add
10536    * implementations or when building up a composite actor, we have
10537    * to preserve the old behaviour, and not create child meta or
10538    * emit the ::actor-added signal, to avoid recursion or double
10539    * emissions
10540    */
10541   clutter_actor_add_child_internal (parent, self,
10542                                     ADD_CHILD_LEGACY_FLAGS,
10543                                     insert_child_at_depth,
10544                                     NULL);
10545 }
10546
10547 /**
10548  * clutter_actor_get_parent:
10549  * @self: A #ClutterActor
10550  *
10551  * Retrieves the parent of @self.
10552  *
10553  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10554  *  if no parent is set
10555  */
10556 ClutterActor *
10557 clutter_actor_get_parent (ClutterActor *self)
10558 {
10559   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10560
10561   return self->priv->parent;
10562 }
10563
10564 /**
10565  * clutter_actor_get_paint_visibility:
10566  * @self: A #ClutterActor
10567  *
10568  * Retrieves the 'paint' visibility of an actor recursively checking for non
10569  * visible parents.
10570  *
10571  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10572  *
10573  * Return Value: %TRUE if the actor is visibile and will be painted.
10574  *
10575  * Since: 0.8.4
10576  */
10577 gboolean
10578 clutter_actor_get_paint_visibility (ClutterActor *actor)
10579 {
10580   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10581
10582   return CLUTTER_ACTOR_IS_MAPPED (actor);
10583 }
10584
10585 /**
10586  * clutter_actor_remove_child:
10587  * @self: a #ClutterActor
10588  * @child: a #ClutterActor
10589  *
10590  * Removes @child from the children of @self.
10591  *
10592  * This function will release the reference added by
10593  * clutter_actor_add_child(), so if you want to keep using @child
10594  * you will have to acquire a referenced on it before calling this
10595  * function.
10596  *
10597  * This function will emit the #ClutterContainer::actor-removed
10598  * signal on @self.
10599  *
10600  * Since: 1.10
10601  */
10602 void
10603 clutter_actor_remove_child (ClutterActor *self,
10604                             ClutterActor *child)
10605 {
10606   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10607   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10608   g_return_if_fail (self != child);
10609   g_return_if_fail (child->priv->parent != NULL);
10610   g_return_if_fail (child->priv->parent == self);
10611
10612   clutter_actor_remove_child_internal (self, child,
10613                                        REMOVE_CHILD_DEFAULT_FLAGS);
10614 }
10615
10616 /**
10617  * clutter_actor_remove_all_children:
10618  * @self: a #ClutterActor
10619  *
10620  * Removes all children of @self.
10621  *
10622  * This function releases the reference added by inserting a child actor
10623  * in the list of children of @self.
10624  *
10625  * If the reference count of a child drops to zero, the child will be
10626  * destroyed. If you want to ensure the destruction of all the children
10627  * of @self, use clutter_actor_destroy_all_children().
10628  *
10629  * Since: 1.10
10630  */
10631 void
10632 clutter_actor_remove_all_children (ClutterActor *self)
10633 {
10634   ClutterActorIter iter;
10635
10636   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10637
10638   if (self->priv->n_children == 0)
10639     return;
10640
10641   g_object_freeze_notify (G_OBJECT (self));
10642
10643   clutter_actor_iter_init (&iter, self);
10644   while (clutter_actor_iter_next (&iter, NULL))
10645     clutter_actor_iter_remove (&iter);
10646
10647   g_object_thaw_notify (G_OBJECT (self));
10648
10649   /* sanity check */
10650   g_assert (self->priv->first_child == NULL);
10651   g_assert (self->priv->last_child == NULL);
10652   g_assert (self->priv->n_children == 0);
10653 }
10654
10655 /**
10656  * clutter_actor_destroy_all_children:
10657  * @self: a #ClutterActor
10658  *
10659  * Destroys all children of @self.
10660  *
10661  * This function releases the reference added by inserting a child
10662  * actor in the list of children of @self, and ensures that the
10663  * #ClutterActor::destroy signal is emitted on each child of the
10664  * actor.
10665  *
10666  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
10667  * when its reference count drops to 0; the default handler of the
10668  * #ClutterActor::destroy signal will destroy all the children of an
10669  * actor. This function ensures that all children are destroyed, instead
10670  * of just removed from @self, unlike clutter_actor_remove_all_children()
10671  * which will merely release the reference and remove each child.
10672  *
10673  * Unless you acquired an additional reference on each child of @self
10674  * prior to calling clutter_actor_remove_all_children() and want to reuse
10675  * the actors, you should use clutter_actor_destroy_all_children() in
10676  * order to make sure that children are destroyed and signal handlers
10677  * are disconnected even in cases where circular references prevent this
10678  * from automatically happening through reference counting alone.
10679  *
10680  * Since: 1.10
10681  */
10682 void
10683 clutter_actor_destroy_all_children (ClutterActor *self)
10684 {
10685   ClutterActorIter iter;
10686
10687   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10688
10689   if (self->priv->n_children == 0)
10690     return;
10691
10692   g_object_freeze_notify (G_OBJECT (self));
10693
10694   clutter_actor_iter_init (&iter, self);
10695   while (clutter_actor_iter_next (&iter, NULL))
10696     clutter_actor_iter_destroy (&iter);
10697
10698   g_object_thaw_notify (G_OBJECT (self));
10699
10700   /* sanity check */
10701   g_assert (self->priv->first_child == NULL);
10702   g_assert (self->priv->last_child == NULL);
10703   g_assert (self->priv->n_children == 0);
10704 }
10705
10706 typedef struct _InsertBetweenData {
10707   ClutterActor *prev_sibling;
10708   ClutterActor *next_sibling;
10709 } InsertBetweenData;
10710
10711 static void
10712 insert_child_between (ClutterActor *self,
10713                       ClutterActor *child,
10714                       gpointer      data_)
10715 {
10716   InsertBetweenData *data = data_;
10717   ClutterActor *prev_sibling = data->prev_sibling;
10718   ClutterActor *next_sibling = data->next_sibling;
10719
10720   child->priv->parent = self;
10721   child->priv->prev_sibling = prev_sibling;
10722   child->priv->next_sibling = next_sibling;
10723
10724   if (prev_sibling != NULL)
10725     prev_sibling->priv->next_sibling = child;
10726
10727   if (next_sibling != NULL)
10728     next_sibling->priv->prev_sibling = child;
10729
10730   if (child->priv->prev_sibling == NULL)
10731     self->priv->first_child = child;
10732
10733   if (child->priv->next_sibling == NULL)
10734     self->priv->last_child = child;
10735 }
10736
10737 /**
10738  * clutter_actor_replace_child:
10739  * @self: a #ClutterActor
10740  * @old_child: the child of @self to replace
10741  * @new_child: the #ClutterActor to replace @old_child
10742  *
10743  * Replaces @old_child with @new_child in the list of children of @self.
10744  *
10745  * Since: 1.10
10746  */
10747 void
10748 clutter_actor_replace_child (ClutterActor *self,
10749                              ClutterActor *old_child,
10750                              ClutterActor *new_child)
10751 {
10752   ClutterActor *prev_sibling, *next_sibling;
10753   InsertBetweenData clos;
10754
10755   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10756   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
10757   g_return_if_fail (old_child->priv->parent == self);
10758   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
10759   g_return_if_fail (old_child != new_child);
10760   g_return_if_fail (new_child != self);
10761   g_return_if_fail (new_child->priv->parent == NULL);
10762
10763   prev_sibling = old_child->priv->prev_sibling;
10764   next_sibling = old_child->priv->next_sibling;
10765   clutter_actor_remove_child_internal (self, old_child,
10766                                        REMOVE_CHILD_DEFAULT_FLAGS);
10767
10768   clos.prev_sibling = prev_sibling;
10769   clos.next_sibling = next_sibling;
10770   clutter_actor_add_child_internal (self, new_child,
10771                                     ADD_CHILD_DEFAULT_FLAGS,
10772                                     insert_child_between,
10773                                     &clos);
10774 }
10775
10776 /**
10777  * clutter_actor_unparent:
10778  * @self: a #ClutterActor
10779  *
10780  * Removes the parent of @self.
10781  *
10782  * This will cause the parent of @self to release the reference
10783  * acquired when calling clutter_actor_set_parent(), so if you
10784  * want to keep @self you will have to acquire a reference of
10785  * your own, through g_object_ref().
10786  *
10787  * This function should only be called by legacy #ClutterActor<!-- -->s
10788  * implementing the #ClutterContainer interface.
10789  *
10790  * Since: 0.1.1
10791  *
10792  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
10793  */
10794 void
10795 clutter_actor_unparent (ClutterActor *self)
10796 {
10797   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10798
10799   if (self->priv->parent == NULL)
10800     return;
10801
10802   clutter_actor_remove_child_internal (self->priv->parent, self,
10803                                        REMOVE_CHILD_LEGACY_FLAGS);
10804 }
10805
10806 /**
10807  * clutter_actor_reparent:
10808  * @self: a #ClutterActor
10809  * @new_parent: the new #ClutterActor parent
10810  *
10811  * Resets the parent actor of @self.
10812  *
10813  * This function is logically equivalent to calling clutter_actor_unparent()
10814  * and clutter_actor_set_parent(), but more efficiently implemented, as it
10815  * ensures the child is not finalized when unparented, and emits the
10816  * #ClutterActor::parent-set signal only once.
10817  *
10818  * In reality, calling this function is less useful than it sounds, as some
10819  * application code may rely on changes in the intermediate state between
10820  * removal and addition of the actor from its old parent to the @new_parent.
10821  * Thus, it is strongly encouraged to avoid using this function in application
10822  * code.
10823  *
10824  * Since: 0.2
10825  *
10826  * Deprecated: 1.10: Use clutter_actor_remove_child() and
10827  *   clutter_actor_add_child() instead; remember to take a reference on
10828  *   the actor being removed before calling clutter_actor_remove_child()
10829  *   to avoid the reference count dropping to zero and the actor being
10830  *   destroyed.
10831  */
10832 void
10833 clutter_actor_reparent (ClutterActor *self,
10834                         ClutterActor *new_parent)
10835 {
10836   ClutterActorPrivate *priv;
10837
10838   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10839   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
10840   g_return_if_fail (self != new_parent);
10841
10842   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10843     {
10844       g_warning ("Cannot set a parent on a toplevel actor");
10845       return;
10846     }
10847
10848   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
10849     {
10850       g_warning ("Cannot set a parent currently being destroyed");
10851       return;
10852     }
10853
10854   priv = self->priv;
10855
10856   if (priv->parent != new_parent)
10857     {
10858       ClutterActor *old_parent;
10859
10860       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10861
10862       old_parent = priv->parent;
10863
10864       g_object_ref (self);
10865
10866       if (old_parent != NULL)
10867         {
10868          /* go through the Container implementation if this is a regular
10869           * child and not an internal one
10870           */
10871          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10872            {
10873              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
10874
10875              /* this will have to call unparent() */
10876              clutter_container_remove_actor (parent, self);
10877            }
10878          else
10879            clutter_actor_remove_child_internal (old_parent, self,
10880                                                 REMOVE_CHILD_LEGACY_FLAGS);
10881         }
10882
10883       /* Note, will call set_parent() */
10884       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10885         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
10886       else
10887         clutter_actor_add_child_internal (new_parent, self,
10888                                           ADD_CHILD_LEGACY_FLAGS,
10889                                           insert_child_at_depth,
10890                                           NULL);
10891
10892       /* we emit the ::parent-set signal once */
10893       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
10894
10895       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10896
10897       /* the IN_REPARENT flag suspends state updates */
10898       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
10899
10900       g_object_unref (self);
10901    }
10902 }
10903
10904 /**
10905  * clutter_actor_contains:
10906  * @self: A #ClutterActor
10907  * @descendant: A #ClutterActor, possibly contained in @self
10908  *
10909  * Determines if @descendant is contained inside @self (either as an
10910  * immediate child, or as a deeper descendant). If @self and
10911  * @descendant point to the same actor then it will also return %TRUE.
10912  *
10913  * Return value: whether @descendent is contained within @self
10914  *
10915  * Since: 1.4
10916  */
10917 gboolean
10918 clutter_actor_contains (ClutterActor *self,
10919                         ClutterActor *descendant)
10920 {
10921   ClutterActor *actor;
10922
10923   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10924   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
10925
10926   for (actor = descendant; actor; actor = actor->priv->parent)
10927     if (actor == self)
10928       return TRUE;
10929
10930   return FALSE;
10931 }
10932
10933 /**
10934  * clutter_actor_set_child_above_sibling:
10935  * @self: a #ClutterActor
10936  * @child: a #ClutterActor child of @self
10937  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10938  *
10939  * Sets @child to be above @sibling in the list of children of @self.
10940  *
10941  * If @sibling is %NULL, @child will be the new last child of @self.
10942  *
10943  * This function is logically equivalent to removing @child and using
10944  * clutter_actor_insert_child_above(), but it will not emit signals
10945  * or change state on @child.
10946  *
10947  * Since: 1.10
10948  */
10949 void
10950 clutter_actor_set_child_above_sibling (ClutterActor *self,
10951                                        ClutterActor *child,
10952                                        ClutterActor *sibling)
10953 {
10954   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10955   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10956   g_return_if_fail (child->priv->parent == self);
10957   g_return_if_fail (child != sibling);
10958   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10959
10960   if (sibling != NULL)
10961     g_return_if_fail (sibling->priv->parent == self);
10962
10963   /* we don't want to change the state of child, or emit signals, or
10964    * regenerate ChildMeta instances here, but we still want to follow
10965    * the correct sequence of steps encoded in remove_child() and
10966    * add_child(), so that correctness is ensured, and we only go
10967    * through one known code path.
10968    */
10969   g_object_ref (child);
10970   clutter_actor_remove_child_internal (self, child, 0);
10971   clutter_actor_add_child_internal (self, child,
10972                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10973                                     insert_child_above,
10974                                     sibling);
10975
10976   clutter_actor_queue_relayout (self);
10977 }
10978
10979 /**
10980  * clutter_actor_set_child_below_sibling:
10981  * @self: a #ClutterActor
10982  * @child: a #ClutterActor child of @self
10983  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10984  *
10985  * Sets @child to be below @sibling in the list of children of @self.
10986  *
10987  * If @sibling is %NULL, @child will be the new first child of @self.
10988  *
10989  * This function is logically equivalent to removing @self and using
10990  * clutter_actor_insert_child_below(), but it will not emit signals
10991  * or change state on @child.
10992  *
10993  * Since: 1.10
10994  */
10995 void
10996 clutter_actor_set_child_below_sibling (ClutterActor *self,
10997                                        ClutterActor *child,
10998                                        ClutterActor *sibling)
10999 {
11000   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11001   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11002   g_return_if_fail (child->priv->parent == self);
11003   g_return_if_fail (child != sibling);
11004   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11005
11006   if (sibling != NULL)
11007     g_return_if_fail (sibling->priv->parent == self);
11008
11009   /* see the comment in set_child_above_sibling() */
11010   g_object_ref (child);
11011   clutter_actor_remove_child_internal (self, child, 0);
11012   clutter_actor_add_child_internal (self, child,
11013                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11014                                     insert_child_below,
11015                                     sibling);
11016
11017   clutter_actor_queue_relayout (self);
11018 }
11019
11020 /**
11021  * clutter_actor_set_child_at_index:
11022  * @self: a #ClutterActor
11023  * @child: a #ClutterActor child of @self
11024  * @index_: the new index for @child
11025  *
11026  * Changes the index of @child in the list of children of @self.
11027  *
11028  * This function is logically equivalent to removing @child and
11029  * calling clutter_actor_insert_child_at_index(), but it will not
11030  * emit signals or change state on @child.
11031  *
11032  * Since: 1.10
11033  */
11034 void
11035 clutter_actor_set_child_at_index (ClutterActor *self,
11036                                   ClutterActor *child,
11037                                   gint          index_)
11038 {
11039   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11040   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11041   g_return_if_fail (child->priv->parent == self);
11042   g_return_if_fail (index_ <= self->priv->n_children);
11043
11044   g_object_ref (child);
11045   clutter_actor_remove_child_internal (self, child, 0);
11046   clutter_actor_add_child_internal (self, child,
11047                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11048                                     insert_child_at_index,
11049                                     GINT_TO_POINTER (index_));
11050
11051   clutter_actor_queue_relayout (self);
11052 }
11053
11054 /**
11055  * clutter_actor_raise:
11056  * @self: A #ClutterActor
11057  * @below: (allow-none): A #ClutterActor to raise above.
11058  *
11059  * Puts @self above @below.
11060  *
11061  * Both actors must have the same parent, and the parent must implement
11062  * the #ClutterContainer interface
11063  *
11064  * This function calls clutter_container_raise_child() internally.
11065  *
11066  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11067  */
11068 void
11069 clutter_actor_raise (ClutterActor *self,
11070                      ClutterActor *below)
11071 {
11072   ClutterActor *parent;
11073
11074   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11075
11076   parent = clutter_actor_get_parent (self);
11077   if (parent == NULL)
11078     {
11079       g_warning ("%s: Actor '%s' is not inside a container",
11080                  G_STRFUNC,
11081                  _clutter_actor_get_debug_name (self));
11082       return;
11083     }
11084
11085   if (below != NULL)
11086     {
11087       if (parent != clutter_actor_get_parent (below))
11088         {
11089           g_warning ("%s Actor '%s' is not in the same container as "
11090                      "actor '%s'",
11091                      G_STRFUNC,
11092                      _clutter_actor_get_debug_name (self),
11093                      _clutter_actor_get_debug_name (below));
11094           return;
11095         }
11096     }
11097
11098   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11099 }
11100
11101 /**
11102  * clutter_actor_lower:
11103  * @self: A #ClutterActor
11104  * @above: (allow-none): A #ClutterActor to lower below
11105  *
11106  * Puts @self below @above.
11107  *
11108  * Both actors must have the same parent, and the parent must implement
11109  * the #ClutterContainer interface.
11110  *
11111  * This function calls clutter_container_lower_child() internally.
11112  *
11113  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11114  */
11115 void
11116 clutter_actor_lower (ClutterActor *self,
11117                      ClutterActor *above)
11118 {
11119   ClutterActor *parent;
11120
11121   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11122
11123   parent = clutter_actor_get_parent (self);
11124   if (parent == NULL)
11125     {
11126       g_warning ("%s: Actor of type %s is not inside a container",
11127                  G_STRFUNC,
11128                  _clutter_actor_get_debug_name (self));
11129       return;
11130     }
11131
11132   if (above)
11133     {
11134       if (parent != clutter_actor_get_parent (above))
11135         {
11136           g_warning ("%s: Actor '%s' is not in the same container as "
11137                      "actor '%s'",
11138                      G_STRFUNC,
11139                      _clutter_actor_get_debug_name (self),
11140                      _clutter_actor_get_debug_name (above));
11141           return;
11142         }
11143     }
11144
11145   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11146 }
11147
11148 /**
11149  * clutter_actor_raise_top:
11150  * @self: A #ClutterActor
11151  *
11152  * Raises @self to the top.
11153  *
11154  * This function calls clutter_actor_raise() internally.
11155  *
11156  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11157  *   a %NULL sibling, instead.
11158  */
11159 void
11160 clutter_actor_raise_top (ClutterActor *self)
11161 {
11162   clutter_actor_raise (self, NULL);
11163 }
11164
11165 /**
11166  * clutter_actor_lower_bottom:
11167  * @self: A #ClutterActor
11168  *
11169  * Lowers @self to the bottom.
11170  *
11171  * This function calls clutter_actor_lower() internally.
11172  *
11173  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11174  *   a %NULL sibling, instead.
11175  */
11176 void
11177 clutter_actor_lower_bottom (ClutterActor *self)
11178 {
11179   clutter_actor_lower (self, NULL);
11180 }
11181
11182 /*
11183  * Event handling
11184  */
11185
11186 /**
11187  * clutter_actor_event:
11188  * @actor: a #ClutterActor
11189  * @event: a #ClutterEvent
11190  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11191  *
11192  * This function is used to emit an event on the main stage.
11193  * You should rarely need to use this function, except for
11194  * synthetising events.
11195  *
11196  * Return value: the return value from the signal emission: %TRUE
11197  *   if the actor handled the event, or %FALSE if the event was
11198  *   not handled
11199  *
11200  * Since: 0.6
11201  */
11202 gboolean
11203 clutter_actor_event (ClutterActor *actor,
11204                      ClutterEvent *event,
11205                      gboolean      capture)
11206 {
11207   gboolean retval = FALSE;
11208   gint signal_num = -1;
11209
11210   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11211   g_return_val_if_fail (event != NULL, FALSE);
11212
11213   g_object_ref (actor);
11214
11215   if (capture)
11216     {
11217       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11218                      event,
11219                      &retval);
11220       goto out;
11221     }
11222
11223   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11224
11225   if (!retval)
11226     {
11227       switch (event->type)
11228         {
11229         case CLUTTER_NOTHING:
11230           break;
11231         case CLUTTER_BUTTON_PRESS:
11232           signal_num = BUTTON_PRESS_EVENT;
11233           break;
11234         case CLUTTER_BUTTON_RELEASE:
11235           signal_num = BUTTON_RELEASE_EVENT;
11236           break;
11237         case CLUTTER_SCROLL:
11238           signal_num = SCROLL_EVENT;
11239           break;
11240         case CLUTTER_KEY_PRESS:
11241           signal_num = KEY_PRESS_EVENT;
11242           break;
11243         case CLUTTER_KEY_RELEASE:
11244           signal_num = KEY_RELEASE_EVENT;
11245           break;
11246         case CLUTTER_MOTION:
11247           signal_num = MOTION_EVENT;
11248           break;
11249         case CLUTTER_ENTER:
11250           signal_num = ENTER_EVENT;
11251           break;
11252         case CLUTTER_LEAVE:
11253           signal_num = LEAVE_EVENT;
11254           break;
11255         case CLUTTER_DELETE:
11256         case CLUTTER_DESTROY_NOTIFY:
11257         case CLUTTER_CLIENT_MESSAGE:
11258         default:
11259           signal_num = -1;
11260           break;
11261         }
11262
11263       if (signal_num != -1)
11264         g_signal_emit (actor, actor_signals[signal_num], 0,
11265                        event, &retval);
11266     }
11267
11268 out:
11269   g_object_unref (actor);
11270
11271   return retval;
11272 }
11273
11274 /**
11275  * clutter_actor_set_reactive:
11276  * @actor: a #ClutterActor
11277  * @reactive: whether the actor should be reactive to events
11278  *
11279  * Sets @actor as reactive. Reactive actors will receive events.
11280  *
11281  * Since: 0.6
11282  */
11283 void
11284 clutter_actor_set_reactive (ClutterActor *actor,
11285                             gboolean      reactive)
11286 {
11287   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11288
11289   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11290     return;
11291
11292   if (reactive)
11293     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11294   else
11295     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11296
11297   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11298 }
11299
11300 /**
11301  * clutter_actor_get_reactive:
11302  * @actor: a #ClutterActor
11303  *
11304  * Checks whether @actor is marked as reactive.
11305  *
11306  * Return value: %TRUE if the actor is reactive
11307  *
11308  * Since: 0.6
11309  */
11310 gboolean
11311 clutter_actor_get_reactive (ClutterActor *actor)
11312 {
11313   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11314
11315   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11316 }
11317
11318 /**
11319  * clutter_actor_get_anchor_point:
11320  * @self: a #ClutterActor
11321  * @anchor_x: (out): return location for the X coordinate of the anchor point
11322  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11323  *
11324  * Gets the current anchor point of the @actor in pixels.
11325  *
11326  * Since: 0.6
11327  */
11328 void
11329 clutter_actor_get_anchor_point (ClutterActor *self,
11330                                 gfloat       *anchor_x,
11331                                 gfloat       *anchor_y)
11332 {
11333   const ClutterTransformInfo *info;
11334
11335   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11336
11337   info = _clutter_actor_get_transform_info_or_defaults (self);
11338   clutter_anchor_coord_get_units (self, &info->anchor,
11339                                   anchor_x,
11340                                   anchor_y,
11341                                   NULL);
11342 }
11343
11344 /**
11345  * clutter_actor_set_anchor_point:
11346  * @self: a #ClutterActor
11347  * @anchor_x: X coordinate of the anchor point
11348  * @anchor_y: Y coordinate of the anchor point
11349  *
11350  * Sets an anchor point for @self. The anchor point is a point in the
11351  * coordinate space of an actor to which the actor position within its
11352  * parent is relative; the default is (0, 0), i.e. the top-left corner
11353  * of the actor.
11354  *
11355  * Since: 0.6
11356  */
11357 void
11358 clutter_actor_set_anchor_point (ClutterActor *self,
11359                                 gfloat        anchor_x,
11360                                 gfloat        anchor_y)
11361 {
11362   ClutterTransformInfo *info;
11363   ClutterActorPrivate *priv;
11364   gboolean changed = FALSE;
11365   gfloat old_anchor_x, old_anchor_y;
11366   GObject *obj;
11367
11368   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11369
11370   obj = G_OBJECT (self);
11371   priv = self->priv;
11372   info = _clutter_actor_get_transform_info (self);
11373
11374   g_object_freeze_notify (obj);
11375
11376   clutter_anchor_coord_get_units (self, &info->anchor,
11377                                   &old_anchor_x,
11378                                   &old_anchor_y,
11379                                   NULL);
11380
11381   if (info->anchor.is_fractional)
11382     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11383
11384   if (old_anchor_x != anchor_x)
11385     {
11386       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11387       changed = TRUE;
11388     }
11389
11390   if (old_anchor_y != anchor_y)
11391     {
11392       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11393       changed = TRUE;
11394     }
11395
11396   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11397
11398   if (changed)
11399     {
11400       priv->transform_valid = FALSE;
11401       clutter_actor_queue_redraw (self);
11402     }
11403
11404   g_object_thaw_notify (obj);
11405 }
11406
11407 /**
11408  * clutter_actor_get_anchor_point_gravity:
11409  * @self: a #ClutterActor
11410  *
11411  * Retrieves the anchor position expressed as a #ClutterGravity. If
11412  * the anchor point was specified using pixels or units this will
11413  * return %CLUTTER_GRAVITY_NONE.
11414  *
11415  * Return value: the #ClutterGravity used by the anchor point
11416  *
11417  * Since: 1.0
11418  */
11419 ClutterGravity
11420 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11421 {
11422   const ClutterTransformInfo *info;
11423
11424   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11425
11426   info = _clutter_actor_get_transform_info_or_defaults (self);
11427
11428   return clutter_anchor_coord_get_gravity (&info->anchor);
11429 }
11430
11431 /**
11432  * clutter_actor_move_anchor_point:
11433  * @self: a #ClutterActor
11434  * @anchor_x: X coordinate of the anchor point
11435  * @anchor_y: Y coordinate of the anchor point
11436  *
11437  * Sets an anchor point for the actor, and adjusts the actor postion so that
11438  * the relative position of the actor toward its parent remains the same.
11439  *
11440  * Since: 0.6
11441  */
11442 void
11443 clutter_actor_move_anchor_point (ClutterActor *self,
11444                                  gfloat        anchor_x,
11445                                  gfloat        anchor_y)
11446 {
11447   gfloat old_anchor_x, old_anchor_y;
11448   const ClutterTransformInfo *info;
11449
11450   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11451
11452   info = _clutter_actor_get_transform_info (self);
11453   clutter_anchor_coord_get_units (self, &info->anchor,
11454                                   &old_anchor_x,
11455                                   &old_anchor_y,
11456                                   NULL);
11457
11458   g_object_freeze_notify (G_OBJECT (self));
11459
11460   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11461
11462   if (self->priv->position_set)
11463     clutter_actor_move_by (self,
11464                            anchor_x - old_anchor_x,
11465                            anchor_y - old_anchor_y);
11466
11467   g_object_thaw_notify (G_OBJECT (self));
11468 }
11469
11470 /**
11471  * clutter_actor_move_anchor_point_from_gravity:
11472  * @self: a #ClutterActor
11473  * @gravity: #ClutterGravity.
11474  *
11475  * Sets an anchor point on the actor based on the given gravity, adjusting the
11476  * actor postion so that its relative position within its parent remains
11477  * unchanged.
11478  *
11479  * Since version 1.0 the anchor point will be stored as a gravity so
11480  * that if the actor changes size then the anchor point will move. For
11481  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11482  * and later double the size of the actor, the anchor point will move
11483  * to the bottom right.
11484  *
11485  * Since: 0.6
11486  */
11487 void
11488 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11489                                               ClutterGravity  gravity)
11490 {
11491   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11492   const ClutterTransformInfo *info;
11493   ClutterActorPrivate *priv;
11494
11495   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11496
11497   priv = self->priv;
11498   info = _clutter_actor_get_transform_info (self);
11499
11500   g_object_freeze_notify (G_OBJECT (self));
11501
11502   clutter_anchor_coord_get_units (self, &info->anchor,
11503                                   &old_anchor_x,
11504                                   &old_anchor_y,
11505                                   NULL);
11506   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11507   clutter_anchor_coord_get_units (self, &info->anchor,
11508                                   &new_anchor_x,
11509                                   &new_anchor_y,
11510                                   NULL);
11511
11512   if (priv->position_set)
11513     clutter_actor_move_by (self,
11514                            new_anchor_x - old_anchor_x,
11515                            new_anchor_y - old_anchor_y);
11516
11517   g_object_thaw_notify (G_OBJECT (self));
11518 }
11519
11520 /**
11521  * clutter_actor_set_anchor_point_from_gravity:
11522  * @self: a #ClutterActor
11523  * @gravity: #ClutterGravity.
11524  *
11525  * Sets an anchor point on the actor, based on the given gravity (this is a
11526  * convenience function wrapping clutter_actor_set_anchor_point()).
11527  *
11528  * Since version 1.0 the anchor point will be stored as a gravity so
11529  * that if the actor changes size then the anchor point will move. For
11530  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11531  * and later double the size of the actor, the anchor point will move
11532  * to the bottom right.
11533  *
11534  * Since: 0.6
11535  */
11536 void
11537 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11538                                              ClutterGravity  gravity)
11539 {
11540   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11541
11542   if (gravity == CLUTTER_GRAVITY_NONE)
11543     clutter_actor_set_anchor_point (self, 0, 0);
11544   else
11545     {
11546       GObject *obj = G_OBJECT (self);
11547       ClutterTransformInfo *info;
11548
11549       g_object_freeze_notify (obj);
11550
11551       info = _clutter_actor_get_transform_info (self);
11552       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11553
11554       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11555       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11556       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11557
11558       self->priv->transform_valid = FALSE;
11559
11560       clutter_actor_queue_redraw (self);
11561
11562       g_object_thaw_notify (obj);
11563     }
11564 }
11565
11566 static void
11567 clutter_container_iface_init (ClutterContainerIface *iface)
11568 {
11569   /* we don't override anything, as ClutterContainer already has a default
11570    * implementation that we can use, and which calls into our own API.
11571    */
11572 }
11573
11574 typedef enum
11575 {
11576   PARSE_X,
11577   PARSE_Y,
11578   PARSE_WIDTH,
11579   PARSE_HEIGHT,
11580   PARSE_ANCHOR_X,
11581   PARSE_ANCHOR_Y
11582 } ParseDimension;
11583
11584 static gfloat
11585 parse_units (ClutterActor   *self,
11586              ParseDimension  dimension,
11587              JsonNode       *node)
11588 {
11589   GValue value = { 0, };
11590   gfloat retval = 0;
11591
11592   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11593     return 0;
11594
11595   json_node_get_value (node, &value);
11596
11597   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11598     {
11599       retval = (gfloat) g_value_get_int64 (&value);
11600     }
11601   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
11602     {
11603       retval = g_value_get_double (&value);
11604     }
11605   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
11606     {
11607       ClutterUnits units;
11608       gboolean res;
11609
11610       res = clutter_units_from_string (&units, g_value_get_string (&value));
11611       if (res)
11612         retval = clutter_units_to_pixels (&units);
11613       else
11614         {
11615           g_warning ("Invalid value '%s': integers, strings or floating point "
11616                      "values can be used for the x, y, width and height "
11617                      "properties. Valid modifiers for strings are 'px', 'mm', "
11618                      "'pt' and 'em'.",
11619                      g_value_get_string (&value));
11620           retval = 0;
11621         }
11622     }
11623   else
11624     {
11625       g_warning ("Invalid value of type '%s': integers, strings of floating "
11626                  "point values can be used for the x, y, width, height "
11627                  "anchor-x and anchor-y properties.",
11628                  g_type_name (G_VALUE_TYPE (&value)));
11629     }
11630
11631   g_value_unset (&value);
11632
11633   return retval;
11634 }
11635
11636 typedef struct {
11637   ClutterRotateAxis axis;
11638
11639   gdouble angle;
11640
11641   gfloat center_x;
11642   gfloat center_y;
11643   gfloat center_z;
11644 } RotationInfo;
11645
11646 static inline gboolean
11647 parse_rotation_array (ClutterActor *actor,
11648                       JsonArray    *array,
11649                       RotationInfo *info)
11650 {
11651   JsonNode *element;
11652
11653   if (json_array_get_length (array) != 2)
11654     return FALSE;
11655
11656   /* angle */
11657   element = json_array_get_element (array, 0);
11658   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
11659     info->angle = json_node_get_double (element);
11660   else
11661     return FALSE;
11662
11663   /* center */
11664   element = json_array_get_element (array, 1);
11665   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
11666     {
11667       JsonArray *center = json_node_get_array (element);
11668
11669       if (json_array_get_length (center) != 2)
11670         return FALSE;
11671
11672       switch (info->axis)
11673         {
11674         case CLUTTER_X_AXIS:
11675           info->center_y = parse_units (actor, PARSE_Y,
11676                                         json_array_get_element (center, 0));
11677           info->center_z = parse_units (actor, PARSE_Y,
11678                                         json_array_get_element (center, 1));
11679           return TRUE;
11680
11681         case CLUTTER_Y_AXIS:
11682           info->center_x = parse_units (actor, PARSE_X,
11683                                         json_array_get_element (center, 0));
11684           info->center_z = parse_units (actor, PARSE_X,
11685                                         json_array_get_element (center, 1));
11686           return TRUE;
11687
11688         case CLUTTER_Z_AXIS:
11689           info->center_x = parse_units (actor, PARSE_X,
11690                                         json_array_get_element (center, 0));
11691           info->center_y = parse_units (actor, PARSE_Y,
11692                                         json_array_get_element (center, 1));
11693           return TRUE;
11694         }
11695     }
11696
11697   return FALSE;
11698 }
11699
11700 static gboolean
11701 parse_rotation (ClutterActor *actor,
11702                 JsonNode     *node,
11703                 RotationInfo *info)
11704 {
11705   JsonArray *array;
11706   guint len, i;
11707   gboolean retval = FALSE;
11708
11709   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
11710     {
11711       g_warning ("Invalid node of type '%s' found, expecting an array",
11712                  json_node_type_name (node));
11713       return FALSE;
11714     }
11715
11716   array = json_node_get_array (node);
11717   len = json_array_get_length (array);
11718
11719   for (i = 0; i < len; i++)
11720     {
11721       JsonNode *element = json_array_get_element (array, i);
11722       JsonObject *object;
11723       JsonNode *member;
11724
11725       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
11726         {
11727           g_warning ("Invalid node of type '%s' found, expecting an object",
11728                      json_node_type_name (element));
11729           return FALSE;
11730         }
11731
11732       object = json_node_get_object (element);
11733
11734       if (json_object_has_member (object, "x-axis"))
11735         {
11736           member = json_object_get_member (object, "x-axis");
11737
11738           info->axis = CLUTTER_X_AXIS;
11739
11740           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11741             {
11742               info->angle = json_node_get_double (member);
11743               retval = TRUE;
11744             }
11745           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11746             retval = parse_rotation_array (actor,
11747                                            json_node_get_array (member),
11748                                            info);
11749           else
11750             retval = FALSE;
11751         }
11752       else if (json_object_has_member (object, "y-axis"))
11753         {
11754           member = json_object_get_member (object, "y-axis");
11755
11756           info->axis = CLUTTER_Y_AXIS;
11757
11758           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11759             {
11760               info->angle = json_node_get_double (member);
11761               retval = TRUE;
11762             }
11763           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11764             retval = parse_rotation_array (actor,
11765                                            json_node_get_array (member),
11766                                            info);
11767           else
11768             retval = FALSE;
11769         }
11770       else if (json_object_has_member (object, "z-axis"))
11771         {
11772           member = json_object_get_member (object, "z-axis");
11773
11774           info->axis = CLUTTER_Z_AXIS;
11775
11776           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11777             {
11778               info->angle = json_node_get_double (member);
11779               retval = TRUE;
11780             }
11781           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11782             retval = parse_rotation_array (actor,
11783                                            json_node_get_array (member),
11784                                            info);
11785           else
11786             retval = FALSE;
11787         }
11788     }
11789
11790   return retval;
11791 }
11792
11793 static GSList *
11794 parse_actor_metas (ClutterScript *script,
11795                    ClutterActor  *actor,
11796                    JsonNode      *node)
11797 {
11798   GList *elements, *l;
11799   GSList *retval = NULL;
11800
11801   if (!JSON_NODE_HOLDS_ARRAY (node))
11802     return NULL;
11803
11804   elements = json_array_get_elements (json_node_get_array (node));
11805
11806   for (l = elements; l != NULL; l = l->next)
11807     {
11808       JsonNode *element = l->data;
11809       const gchar *id_ = _clutter_script_get_id_from_node (element);
11810       GObject *meta;
11811
11812       if (id_ == NULL || *id_ == '\0')
11813         continue;
11814
11815       meta = clutter_script_get_object (script, id_);
11816       if (meta == NULL)
11817         continue;
11818
11819       retval = g_slist_prepend (retval, meta);
11820     }
11821
11822   g_list_free (elements);
11823
11824   return g_slist_reverse (retval);
11825 }
11826
11827 static GSList *
11828 parse_behaviours (ClutterScript *script,
11829                   ClutterActor  *actor,
11830                   JsonNode      *node)
11831 {
11832   GList *elements, *l;
11833   GSList *retval = NULL;
11834
11835   if (!JSON_NODE_HOLDS_ARRAY (node))
11836     return NULL;
11837
11838   elements = json_array_get_elements (json_node_get_array (node));
11839
11840   for (l = elements; l != NULL; l = l->next)
11841     {
11842       JsonNode *element = l->data;
11843       const gchar *id_ = _clutter_script_get_id_from_node (element);
11844       GObject *behaviour;
11845
11846       if (id_ == NULL || *id_ == '\0')
11847         continue;
11848
11849       behaviour = clutter_script_get_object (script, id_);
11850       if (behaviour == NULL)
11851         continue;
11852
11853       retval = g_slist_prepend (retval, behaviour);
11854     }
11855
11856   g_list_free (elements);
11857
11858   return g_slist_reverse (retval);
11859 }
11860
11861 static gboolean
11862 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
11863                                  ClutterScript     *script,
11864                                  GValue            *value,
11865                                  const gchar       *name,
11866                                  JsonNode          *node)
11867 {
11868   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11869   gboolean retval = FALSE;
11870
11871   if ((name[0] == 'x' && name[1] == '\0') ||
11872       (name[0] == 'y' && name[1] == '\0') ||
11873       (strcmp (name, "width") == 0) ||
11874       (strcmp (name, "height") == 0) ||
11875       (strcmp (name, "anchor_x") == 0) ||
11876       (strcmp (name, "anchor_y") == 0))
11877     {
11878       ParseDimension dimension;
11879       gfloat units;
11880
11881       if (name[0] == 'x')
11882         dimension = PARSE_X;
11883       else if (name[0] == 'y')
11884         dimension = PARSE_Y;
11885       else if (name[0] == 'w')
11886         dimension = PARSE_WIDTH;
11887       else if (name[0] == 'h')
11888         dimension = PARSE_HEIGHT;
11889       else if (name[0] == 'a' && name[7] == 'x')
11890         dimension = PARSE_ANCHOR_X;
11891       else if (name[0] == 'a' && name[7] == 'y')
11892         dimension = PARSE_ANCHOR_Y;
11893       else
11894         return FALSE;
11895
11896       units = parse_units (actor, dimension, node);
11897
11898       /* convert back to pixels: all properties are pixel-based */
11899       g_value_init (value, G_TYPE_FLOAT);
11900       g_value_set_float (value, units);
11901
11902       retval = TRUE;
11903     }
11904   else if (strcmp (name, "rotation") == 0)
11905     {
11906       RotationInfo *info;
11907
11908       info = g_slice_new0 (RotationInfo);
11909       retval = parse_rotation (actor, node, info);
11910
11911       if (retval)
11912         {
11913           g_value_init (value, G_TYPE_POINTER);
11914           g_value_set_pointer (value, info);
11915         }
11916       else
11917         g_slice_free (RotationInfo, info);
11918     }
11919   else if (strcmp (name, "behaviours") == 0)
11920     {
11921       GSList *l;
11922
11923 #ifdef CLUTTER_ENABLE_DEBUG
11924       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
11925         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
11926                                      "and it should not be used in newly "
11927                                      "written ClutterScript definitions.");
11928 #endif
11929
11930       l = parse_behaviours (script, actor, node);
11931
11932       g_value_init (value, G_TYPE_POINTER);
11933       g_value_set_pointer (value, l);
11934
11935       retval = TRUE;
11936     }
11937   else if (strcmp (name, "actions") == 0 ||
11938            strcmp (name, "constraints") == 0 ||
11939            strcmp (name, "effects") == 0)
11940     {
11941       GSList *l;
11942
11943       l = parse_actor_metas (script, actor, node);
11944
11945       g_value_init (value, G_TYPE_POINTER);
11946       g_value_set_pointer (value, l);
11947
11948       retval = TRUE;
11949     }
11950
11951   return retval;
11952 }
11953
11954 static void
11955 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
11956                                    ClutterScript     *script,
11957                                    const gchar       *name,
11958                                    const GValue      *value)
11959 {
11960   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11961
11962 #ifdef CLUTTER_ENABLE_DEBUG
11963   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
11964     {
11965       gchar *tmp = g_strdup_value_contents (value);
11966
11967       CLUTTER_NOTE (SCRIPT,
11968                     "in ClutterActor::set_custom_property('%s') = %s",
11969                     name,
11970                     tmp);
11971
11972       g_free (tmp);
11973     }
11974 #endif /* CLUTTER_ENABLE_DEBUG */
11975
11976   if (strcmp (name, "rotation") == 0)
11977     {
11978       RotationInfo *info;
11979
11980       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11981         return;
11982
11983       info = g_value_get_pointer (value);
11984
11985       clutter_actor_set_rotation (actor,
11986                                   info->axis, info->angle,
11987                                   info->center_x,
11988                                   info->center_y,
11989                                   info->center_z);
11990
11991       g_slice_free (RotationInfo, info);
11992
11993       return;
11994     }
11995
11996   if (strcmp (name, "behaviours") == 0)
11997     {
11998       GSList *behaviours, *l;
11999
12000       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12001         return;
12002
12003       behaviours = g_value_get_pointer (value);
12004       for (l = behaviours; l != NULL; l = l->next)
12005         {
12006           ClutterBehaviour *behaviour = l->data;
12007
12008           clutter_behaviour_apply (behaviour, actor);
12009         }
12010
12011       g_slist_free (behaviours);
12012
12013       return;
12014     }
12015
12016   if (strcmp (name, "actions") == 0 ||
12017       strcmp (name, "constraints") == 0 ||
12018       strcmp (name, "effects") == 0)
12019     {
12020       GSList *metas, *l;
12021
12022       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12023         return;
12024
12025       metas = g_value_get_pointer (value);
12026       for (l = metas; l != NULL; l = l->next)
12027         {
12028           if (name[0] == 'a')
12029             clutter_actor_add_action (actor, l->data);
12030
12031           if (name[0] == 'c')
12032             clutter_actor_add_constraint (actor, l->data);
12033
12034           if (name[0] == 'e')
12035             clutter_actor_add_effect (actor, l->data);
12036         }
12037
12038       g_slist_free (metas);
12039
12040       return;
12041     }
12042
12043   g_object_set_property (G_OBJECT (scriptable), name, value);
12044 }
12045
12046 static void
12047 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12048 {
12049   iface->parse_custom_node = clutter_actor_parse_custom_node;
12050   iface->set_custom_property = clutter_actor_set_custom_property;
12051 }
12052
12053 static ClutterActorMeta *
12054 get_meta_from_animation_property (ClutterActor  *actor,
12055                                   const gchar   *name,
12056                                   gchar        **name_p)
12057 {
12058   ClutterActorPrivate *priv = actor->priv;
12059   ClutterActorMeta *meta = NULL;
12060   gchar **tokens;
12061
12062   /* if this is not a special property, fall through */
12063   if (name[0] != '@')
12064     return NULL;
12065
12066   /* detect the properties named using the following spec:
12067    *
12068    *   @<section>.<meta-name>.<property-name>
12069    *
12070    * where <section> can be one of the following:
12071    *
12072    *   - actions
12073    *   - constraints
12074    *   - effects
12075    *
12076    * and <meta-name> is the name set on a specific ActorMeta
12077    */
12078
12079   tokens = g_strsplit (name + 1, ".", -1);
12080   if (tokens == NULL || g_strv_length (tokens) != 3)
12081     {
12082       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12083                     name + 1);
12084       g_strfreev (tokens);
12085       return NULL;
12086     }
12087
12088   if (strcmp (tokens[0], "actions") == 0)
12089     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12090
12091   if (strcmp (tokens[0], "constraints") == 0)
12092     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12093
12094   if (strcmp (tokens[0], "effects") == 0)
12095     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12096
12097   if (name_p != NULL)
12098     *name_p = g_strdup (tokens[2]);
12099
12100   CLUTTER_NOTE (ANIMATION,
12101                 "Looking for property '%s' of object '%s' in section '%s'",
12102                 tokens[2],
12103                 tokens[1],
12104                 tokens[0]);
12105
12106   g_strfreev (tokens);
12107
12108   return meta;
12109 }
12110
12111 static GParamSpec *
12112 clutter_actor_find_property (ClutterAnimatable *animatable,
12113                              const gchar       *property_name)
12114 {
12115   ClutterActorMeta *meta = NULL;
12116   GObjectClass *klass = NULL;
12117   GParamSpec *pspec = NULL;
12118   gchar *p_name = NULL;
12119
12120   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12121                                            property_name,
12122                                            &p_name);
12123
12124   if (meta != NULL)
12125     {
12126       klass = G_OBJECT_GET_CLASS (meta);
12127
12128       pspec = g_object_class_find_property (klass, p_name);
12129     }
12130   else
12131     {
12132       klass = G_OBJECT_GET_CLASS (animatable);
12133
12134       pspec = g_object_class_find_property (klass, property_name);
12135     }
12136
12137   g_free (p_name);
12138
12139   return pspec;
12140 }
12141
12142 static void
12143 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12144                                  const gchar       *property_name,
12145                                  GValue            *initial)
12146 {
12147   ClutterActorMeta *meta = NULL;
12148   gchar *p_name = NULL;
12149
12150   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12151                                            property_name,
12152                                            &p_name);
12153
12154   if (meta != NULL)
12155     g_object_get_property (G_OBJECT (meta), p_name, initial);
12156   else
12157     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12158
12159   g_free (p_name);
12160 }
12161
12162 static void
12163 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12164                                const gchar       *property_name,
12165                                const GValue      *final)
12166 {
12167   ClutterActorMeta *meta = NULL;
12168   gchar *p_name = NULL;
12169
12170   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12171                                            property_name,
12172                                            &p_name);
12173   if (meta != NULL)
12174     g_object_set_property (G_OBJECT (meta), p_name, final);
12175   else
12176     g_object_set_property (G_OBJECT (animatable), property_name, final);
12177
12178   g_free (p_name);
12179 }
12180
12181 static void
12182 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12183 {
12184   iface->find_property = clutter_actor_find_property;
12185   iface->get_initial_state = clutter_actor_get_initial_state;
12186   iface->set_final_state = clutter_actor_set_final_state;
12187 }
12188
12189 /**
12190  * clutter_actor_transform_stage_point:
12191  * @self: A #ClutterActor
12192  * @x: (in): x screen coordinate of the point to unproject
12193  * @y: (in): y screen coordinate of the point to unproject
12194  * @x_out: (out): return location for the unprojected x coordinance
12195  * @y_out: (out): return location for the unprojected y coordinance
12196  *
12197  * This function translates screen coordinates (@x, @y) to
12198  * coordinates relative to the actor. For example, it can be used to translate
12199  * screen events from global screen coordinates into actor-local coordinates.
12200  *
12201  * The conversion can fail, notably if the transform stack results in the
12202  * actor being projected on the screen as a mere line.
12203  *
12204  * The conversion should not be expected to be pixel-perfect due to the
12205  * nature of the operation. In general the error grows when the skewing
12206  * of the actor rectangle on screen increases.
12207  *
12208  * <note><para>This function can be computationally intensive.</para></note>
12209  *
12210  * <note><para>This function only works when the allocation is up-to-date,
12211  * i.e. inside of paint().</para></note>
12212  *
12213  * Return value: %TRUE if conversion was successful.
12214  *
12215  * Since: 0.6
12216  */
12217 gboolean
12218 clutter_actor_transform_stage_point (ClutterActor *self,
12219                                      gfloat        x,
12220                                      gfloat        y,
12221                                      gfloat       *x_out,
12222                                      gfloat       *y_out)
12223 {
12224   ClutterVertex v[4];
12225   float ST[3][3];
12226   float RQ[3][3];
12227   int du, dv, xi, yi;
12228   float px, py;
12229   float xf, yf, wf, det;
12230   ClutterActorPrivate *priv;
12231
12232   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12233
12234   priv = self->priv;
12235
12236   /* This implementation is based on the quad -> quad projection algorithm
12237    * described by Paul Heckbert in:
12238    *
12239    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12240    *
12241    * and the sample implementation at:
12242    *
12243    *   http://www.cs.cmu.edu/~ph/src/texfund/
12244    *
12245    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12246    * quad to rectangle only, which significantly simplifies things; the
12247    * function calls have been unrolled, and most of the math is done in fixed
12248    * point.
12249    */
12250
12251   clutter_actor_get_abs_allocation_vertices (self, v);
12252
12253   /* Keeping these as ints simplifies the multiplication (no significant
12254    * loss of precision here).
12255    */
12256   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12257   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12258
12259   if (!du || !dv)
12260     return FALSE;
12261
12262 #define UX2FP(x)        (x)
12263 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12264
12265   /* First, find mapping from unit uv square to xy quadrilateral; this
12266    * equivalent to the pmap_square_quad() functions in the sample
12267    * implementation, which we can simplify, since our target is always
12268    * a rectangle.
12269    */
12270   px = v[0].x - v[1].x + v[3].x - v[2].x;
12271   py = v[0].y - v[1].y + v[3].y - v[2].y;
12272
12273   if (!px && !py)
12274     {
12275       /* affine transform */
12276       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12277       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12278       RQ[2][0] = UX2FP (v[0].x);
12279       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12280       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12281       RQ[2][1] = UX2FP (v[0].y);
12282       RQ[0][2] = 0;
12283       RQ[1][2] = 0;
12284       RQ[2][2] = 1.0;
12285     }
12286   else
12287     {
12288       /* projective transform */
12289       double dx1, dx2, dy1, dy2, del;
12290
12291       dx1 = UX2FP (v[1].x - v[3].x);
12292       dx2 = UX2FP (v[2].x - v[3].x);
12293       dy1 = UX2FP (v[1].y - v[3].y);
12294       dy2 = UX2FP (v[2].y - v[3].y);
12295
12296       del = DET2FP (dx1, dx2, dy1, dy2);
12297       if (!del)
12298         return FALSE;
12299
12300       /*
12301        * The division here needs to be done in floating point for
12302        * precisions reasons.
12303        */
12304       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12305       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12306       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12307       RQ[2][2] = 1.0;
12308       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12309       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12310       RQ[2][0] = UX2FP (v[0].x);
12311       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12312       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12313       RQ[2][1] = UX2FP (v[0].y);
12314     }
12315
12316   /*
12317    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12318    * square. Since our rectangle is based at 0,0 we only need to scale.
12319    */
12320   RQ[0][0] /= du;
12321   RQ[1][0] /= dv;
12322   RQ[0][1] /= du;
12323   RQ[1][1] /= dv;
12324   RQ[0][2] /= du;
12325   RQ[1][2] /= dv;
12326
12327   /*
12328    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12329    * inverse of that.
12330    */
12331   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12332   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12333   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12334   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12335   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12336   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12337   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12338   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12339   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12340
12341   /*
12342    * Check the resulting matrix is OK.
12343    */
12344   det = (RQ[0][0] * ST[0][0])
12345       + (RQ[0][1] * ST[0][1])
12346       + (RQ[0][2] * ST[0][2]);
12347   if (!det)
12348     return FALSE;
12349
12350   /*
12351    * Now transform our point with the ST matrix; the notional w
12352    * coordinate is 1, hence the last part is simply added.
12353    */
12354   xi = (int) x;
12355   yi = (int) y;
12356
12357   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12358   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12359   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12360
12361   if (x_out)
12362     *x_out = xf / wf;
12363
12364   if (y_out)
12365     *y_out = yf / wf;
12366
12367 #undef UX2FP
12368 #undef DET2FP
12369
12370   return TRUE;
12371 }
12372
12373 /*
12374  * ClutterGeometry
12375  */
12376
12377 static ClutterGeometry*
12378 clutter_geometry_copy (const ClutterGeometry *geometry)
12379 {
12380   return g_slice_dup (ClutterGeometry, geometry);
12381 }
12382
12383 static void
12384 clutter_geometry_free (ClutterGeometry *geometry)
12385 {
12386   if (G_LIKELY (geometry != NULL))
12387     g_slice_free (ClutterGeometry, geometry);
12388 }
12389
12390 /**
12391  * clutter_geometry_union:
12392  * @geometry_a: a #ClutterGeometry
12393  * @geometry_b: another #ClutterGeometry
12394  * @result: (out): location to store the result
12395  *
12396  * Find the union of two rectangles represented as #ClutterGeometry.
12397  *
12398  * Since: 1.4
12399  */
12400 void
12401 clutter_geometry_union (const ClutterGeometry *geometry_a,
12402                         const ClutterGeometry *geometry_b,
12403                         ClutterGeometry       *result)
12404 {
12405   /* We don't try to handle rectangles that can't be represented
12406    * as a signed integer box */
12407   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12408   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12409   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12410                   geometry_b->x + (gint)geometry_b->width);
12411   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12412                   geometry_b->y + (gint)geometry_b->height);
12413   result->x = x_1;
12414   result->y = y_1;
12415   result->width = x_2 - x_1;
12416   result->height = y_2 - y_1;
12417 }
12418
12419 /**
12420  * clutter_geometry_intersects:
12421  * @geometry0: The first geometry to test
12422  * @geometry1: The second geometry to test
12423  *
12424  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12425  * they do else %FALSE.
12426  *
12427  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12428  * %FALSE.
12429  *
12430  * Since: 1.4
12431  */
12432 gboolean
12433 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12434                              const ClutterGeometry *geometry1)
12435 {
12436   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12437       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12438       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12439       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12440     return FALSE;
12441   else
12442     return TRUE;
12443 }
12444
12445 static gboolean
12446 clutter_geometry_progress (const GValue *a,
12447                            const GValue *b,
12448                            gdouble       progress,
12449                            GValue       *retval)
12450 {
12451   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12452   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12453   ClutterGeometry res = { 0, };
12454   gint a_width = a_geom->width;
12455   gint b_width = b_geom->width;
12456   gint a_height = a_geom->height;
12457   gint b_height = b_geom->height;
12458
12459   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12460   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12461
12462   res.width = a_width + (b_width - a_width) * progress;
12463   res.height = a_height + (b_height - a_height) * progress;
12464
12465   g_value_set_boxed (retval, &res);
12466
12467   return TRUE;
12468 }
12469
12470 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12471                                clutter_geometry_copy,
12472                                clutter_geometry_free,
12473                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12474
12475 /*
12476  * ClutterVertices
12477  */
12478
12479 /**
12480  * clutter_vertex_new:
12481  * @x: X coordinate
12482  * @y: Y coordinate
12483  * @z: Z coordinate
12484  *
12485  * Creates a new #ClutterVertex for the point in 3D space
12486  * identified by the 3 coordinates @x, @y, @z
12487  *
12488  * Return value: the newly allocate #ClutterVertex. Use
12489  *   clutter_vertex_free() to free the resources
12490  *
12491  * Since: 1.0
12492  */
12493 ClutterVertex *
12494 clutter_vertex_new (gfloat x,
12495                     gfloat y,
12496                     gfloat z)
12497 {
12498   ClutterVertex *vertex;
12499
12500   vertex = g_slice_new (ClutterVertex);
12501   vertex->x = x;
12502   vertex->y = y;
12503   vertex->z = z;
12504
12505   return vertex;
12506 }
12507
12508 /**
12509  * clutter_vertex_copy:
12510  * @vertex: a #ClutterVertex
12511  *
12512  * Copies @vertex
12513  *
12514  * Return value: a newly allocated copy of #ClutterVertex. Use
12515  *   clutter_vertex_free() to free the allocated resources
12516  *
12517  * Since: 1.0
12518  */
12519 ClutterVertex *
12520 clutter_vertex_copy (const ClutterVertex *vertex)
12521 {
12522   if (G_LIKELY (vertex != NULL))
12523     return g_slice_dup (ClutterVertex, vertex);
12524
12525   return NULL;
12526 }
12527
12528 /**
12529  * clutter_vertex_free:
12530  * @vertex: a #ClutterVertex
12531  *
12532  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
12533  *
12534  * Since: 1.0
12535  */
12536 void
12537 clutter_vertex_free (ClutterVertex *vertex)
12538 {
12539   if (G_UNLIKELY (vertex != NULL))
12540     g_slice_free (ClutterVertex, vertex);
12541 }
12542
12543 /**
12544  * clutter_vertex_equal:
12545  * @vertex_a: a #ClutterVertex
12546  * @vertex_b: a #ClutterVertex
12547  *
12548  * Compares @vertex_a and @vertex_b for equality
12549  *
12550  * Return value: %TRUE if the passed #ClutterVertex are equal
12551  *
12552  * Since: 1.0
12553  */
12554 gboolean
12555 clutter_vertex_equal (const ClutterVertex *vertex_a,
12556                       const ClutterVertex *vertex_b)
12557 {
12558   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
12559
12560   if (vertex_a == vertex_b)
12561     return TRUE;
12562
12563   return vertex_a->x == vertex_b->x &&
12564          vertex_a->y == vertex_b->y &&
12565          vertex_a->z == vertex_b->z;
12566 }
12567
12568 static gboolean
12569 clutter_vertex_progress (const GValue *a,
12570                          const GValue *b,
12571                          gdouble       progress,
12572                          GValue       *retval)
12573 {
12574   const ClutterVertex *av = g_value_get_boxed (a);
12575   const ClutterVertex *bv = g_value_get_boxed (b);
12576   ClutterVertex res = { 0, };
12577
12578   res.x = av->x + (bv->x - av->x) * progress;
12579   res.y = av->y + (bv->y - av->y) * progress;
12580   res.z = av->z + (bv->z - av->z) * progress;
12581
12582   g_value_set_boxed (retval, &res);
12583
12584   return TRUE;
12585 }
12586
12587 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
12588                                clutter_vertex_copy,
12589                                clutter_vertex_free,
12590                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
12591
12592 /**
12593  * clutter_actor_is_rotated:
12594  * @self: a #ClutterActor
12595  *
12596  * Checks whether any rotation is applied to the actor.
12597  *
12598  * Return value: %TRUE if the actor is rotated.
12599  *
12600  * Since: 0.6
12601  */
12602 gboolean
12603 clutter_actor_is_rotated (ClutterActor *self)
12604 {
12605   const ClutterTransformInfo *info;
12606
12607   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12608
12609   info = _clutter_actor_get_transform_info_or_defaults (self);
12610
12611   if (info->rx_angle || info->ry_angle || info->rz_angle)
12612     return TRUE;
12613
12614   return FALSE;
12615 }
12616
12617 /**
12618  * clutter_actor_is_scaled:
12619  * @self: a #ClutterActor
12620  *
12621  * Checks whether the actor is scaled in either dimension.
12622  *
12623  * Return value: %TRUE if the actor is scaled.
12624  *
12625  * Since: 0.6
12626  */
12627 gboolean
12628 clutter_actor_is_scaled (ClutterActor *self)
12629 {
12630   const ClutterTransformInfo *info;
12631
12632   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12633
12634   info = _clutter_actor_get_transform_info_or_defaults (self);
12635
12636   if (info->scale_x != 1.0 || info->scale_y != 1.0)
12637     return TRUE;
12638
12639   return FALSE;
12640 }
12641
12642 ClutterActor *
12643 _clutter_actor_get_stage_internal (ClutterActor *actor)
12644 {
12645   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
12646     actor = actor->priv->parent;
12647
12648   return actor;
12649 }
12650
12651 /**
12652  * clutter_actor_get_stage:
12653  * @actor: a #ClutterActor
12654  *
12655  * Retrieves the #ClutterStage where @actor is contained.
12656  *
12657  * Return value: (transfer none) (type Clutter.Stage): the stage
12658  *   containing the actor, or %NULL
12659  *
12660  * Since: 0.8
12661  */
12662 ClutterActor *
12663 clutter_actor_get_stage (ClutterActor *actor)
12664 {
12665   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
12666
12667   return _clutter_actor_get_stage_internal (actor);
12668 }
12669
12670 /**
12671  * clutter_actor_allocate_available_size:
12672  * @self: a #ClutterActor
12673  * @x: the actor's X coordinate
12674  * @y: the actor's Y coordinate
12675  * @available_width: the maximum available width, or -1 to use the
12676  *   actor's natural width
12677  * @available_height: the maximum available height, or -1 to use the
12678  *   actor's natural height
12679  * @flags: flags controlling the allocation
12680  *
12681  * Allocates @self taking into account the #ClutterActor<!-- -->'s
12682  * preferred size, but limiting it to the maximum available width
12683  * and height provided.
12684  *
12685  * This function will do the right thing when dealing with the
12686  * actor's request mode.
12687  *
12688  * The implementation of this function is equivalent to:
12689  *
12690  * |[
12691  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12692  *     {
12693  *       clutter_actor_get_preferred_width (self, available_height,
12694  *                                          &amp;min_width,
12695  *                                          &amp;natural_width);
12696  *       width = CLAMP (natural_width, min_width, available_width);
12697  *
12698  *       clutter_actor_get_preferred_height (self, width,
12699  *                                           &amp;min_height,
12700  *                                           &amp;natural_height);
12701  *       height = CLAMP (natural_height, min_height, available_height);
12702  *     }
12703  *   else
12704  *     {
12705  *       clutter_actor_get_preferred_height (self, available_width,
12706  *                                           &amp;min_height,
12707  *                                           &amp;natural_height);
12708  *       height = CLAMP (natural_height, min_height, available_height);
12709  *
12710  *       clutter_actor_get_preferred_width (self, height,
12711  *                                          &amp;min_width,
12712  *                                          &amp;natural_width);
12713  *       width = CLAMP (natural_width, min_width, available_width);
12714  *     }
12715  *
12716  *   box.x1 = x; box.y1 = y;
12717  *   box.x2 = box.x1 + available_width;
12718  *   box.y2 = box.y1 + available_height;
12719  *   clutter_actor_allocate (self, &amp;box, flags);
12720  * ]|
12721  *
12722  * This function can be used by fluid layout managers to allocate
12723  * an actor's preferred size without making it bigger than the area
12724  * available for the container.
12725  *
12726  * Since: 1.0
12727  */
12728 void
12729 clutter_actor_allocate_available_size (ClutterActor           *self,
12730                                        gfloat                  x,
12731                                        gfloat                  y,
12732                                        gfloat                  available_width,
12733                                        gfloat                  available_height,
12734                                        ClutterAllocationFlags  flags)
12735 {
12736   ClutterActorPrivate *priv;
12737   gfloat width, height;
12738   gfloat min_width, min_height;
12739   gfloat natural_width, natural_height;
12740   ClutterActorBox box;
12741
12742   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12743
12744   priv = self->priv;
12745
12746   width = height = 0.0;
12747
12748   switch (priv->request_mode)
12749     {
12750     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
12751       clutter_actor_get_preferred_width (self, available_height,
12752                                          &min_width,
12753                                          &natural_width);
12754       width  = CLAMP (natural_width, min_width, available_width);
12755
12756       clutter_actor_get_preferred_height (self, width,
12757                                           &min_height,
12758                                           &natural_height);
12759       height = CLAMP (natural_height, min_height, available_height);
12760       break;
12761
12762     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
12763       clutter_actor_get_preferred_height (self, available_width,
12764                                           &min_height,
12765                                           &natural_height);
12766       height = CLAMP (natural_height, min_height, available_height);
12767
12768       clutter_actor_get_preferred_width (self, height,
12769                                          &min_width,
12770                                          &natural_width);
12771       width  = CLAMP (natural_width, min_width, available_width);
12772       break;
12773     }
12774
12775
12776   box.x1 = x;
12777   box.y1 = y;
12778   box.x2 = box.x1 + width;
12779   box.y2 = box.y1 + height;
12780   clutter_actor_allocate (self, &box, flags);
12781 }
12782
12783 /**
12784  * clutter_actor_allocate_preferred_size:
12785  * @self: a #ClutterActor
12786  * @flags: flags controlling the allocation
12787  *
12788  * Allocates the natural size of @self.
12789  *
12790  * This function is a utility call for #ClutterActor implementations
12791  * that allocates the actor's preferred natural size. It can be used
12792  * by fixed layout managers (like #ClutterGroup or so called
12793  * 'composite actors') inside the ClutterActor::allocate
12794  * implementation to give each child exactly how much space it
12795  * requires.
12796  *
12797  * This function is not meant to be used by applications. It is also
12798  * not meant to be used outside the implementation of the
12799  * ClutterActor::allocate virtual function.
12800  *
12801  * Since: 0.8
12802  */
12803 void
12804 clutter_actor_allocate_preferred_size (ClutterActor           *self,
12805                                        ClutterAllocationFlags  flags)
12806 {
12807   gfloat actor_x, actor_y;
12808   gfloat natural_width, natural_height;
12809   ClutterActorBox actor_box;
12810
12811   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12812
12813   actor_x = clutter_actor_get_x (self);
12814   actor_y = clutter_actor_get_y (self);
12815
12816   clutter_actor_get_preferred_size (self,
12817                                     NULL, NULL,
12818                                     &natural_width,
12819                                     &natural_height);
12820
12821   actor_box.x1 = actor_x;
12822   actor_box.y1 = actor_y;
12823   actor_box.x2 = actor_box.x1 + natural_width;
12824   actor_box.y2 = actor_box.y1 + natural_height;
12825
12826   clutter_actor_allocate (self, &actor_box, flags);
12827 }
12828
12829 /**
12830  * clutter_actor_allocate_align_fill:
12831  * @self: a #ClutterActor
12832  * @box: a #ClutterActorBox, containing the available width and height
12833  * @x_align: the horizontal alignment, between 0 and 1
12834  * @y_align: the vertical alignment, between 0 and 1
12835  * @x_fill: whether the actor should fill horizontally
12836  * @y_fill: whether the actor should fill vertically
12837  * @flags: allocation flags to be passed to clutter_actor_allocate()
12838  *
12839  * Allocates @self by taking into consideration the available allocation
12840  * area; an alignment factor on either axis; and whether the actor should
12841  * fill the allocation on either axis.
12842  *
12843  * The @box should contain the available allocation width and height;
12844  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
12845  * allocation will be offset by their value.
12846  *
12847  * This function takes into consideration the geometry request specified by
12848  * the #ClutterActor:request-mode property, and the text direction.
12849  *
12850  * This function is useful for fluid layout managers, like #ClutterBinLayout
12851  * or #ClutterTableLayout
12852  *
12853  * Since: 1.4
12854  */
12855 void
12856 clutter_actor_allocate_align_fill (ClutterActor           *self,
12857                                    const ClutterActorBox  *box,
12858                                    gdouble                 x_align,
12859                                    gdouble                 y_align,
12860                                    gboolean                x_fill,
12861                                    gboolean                y_fill,
12862                                    ClutterAllocationFlags  flags)
12863 {
12864   ClutterActorPrivate *priv;
12865   ClutterActorBox allocation = { 0, };
12866   gfloat x_offset, y_offset;
12867   gfloat available_width, available_height;
12868   gfloat child_width, child_height;
12869
12870   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12871   g_return_if_fail (box != NULL);
12872   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
12873   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
12874
12875   priv = self->priv;
12876
12877   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
12878   clutter_actor_box_get_size (box, &available_width, &available_height);
12879
12880   if (available_width < 0)
12881     available_width = 0;
12882
12883   if (available_height < 0)
12884     available_height = 0;
12885
12886   if (x_fill)
12887     {
12888       allocation.x1 = x_offset;
12889       allocation.x2 = allocation.x1 + available_width;
12890     }
12891
12892   if (y_fill)
12893     {
12894       allocation.y1 = y_offset;
12895       allocation.y2 = allocation.y1 + available_height;
12896     }
12897
12898   /* if we are filling horizontally and vertically then we're done */
12899   if (x_fill && y_fill)
12900     goto out;
12901
12902   child_width = child_height = 0.0f;
12903
12904   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12905     {
12906       gfloat min_width, natural_width;
12907       gfloat min_height, natural_height;
12908
12909       clutter_actor_get_preferred_width (self, available_height,
12910                                          &min_width,
12911                                          &natural_width);
12912
12913       child_width = CLAMP (natural_width, min_width, available_width);
12914
12915       if (!y_fill)
12916         {
12917           clutter_actor_get_preferred_height (self, child_width,
12918                                               &min_height,
12919                                               &natural_height);
12920
12921           child_height = CLAMP (natural_height, min_height, available_height);
12922         }
12923     }
12924   else
12925     {
12926       gfloat min_width, natural_width;
12927       gfloat min_height, natural_height;
12928
12929       clutter_actor_get_preferred_height (self, available_width,
12930                                           &min_height,
12931                                           &natural_height);
12932
12933       child_height = CLAMP (natural_height, min_height, available_height);
12934
12935       if (!x_fill)
12936         {
12937           clutter_actor_get_preferred_width (self, child_height,
12938                                              &min_width,
12939                                              &natural_width);
12940
12941           child_width = CLAMP (natural_width, min_width, available_width);
12942         }
12943     }
12944
12945   /* invert the horizontal alignment for RTL languages */
12946   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
12947     x_align = 1.0 - x_align;
12948
12949   if (!x_fill)
12950     {
12951       allocation.x1 = x_offset
12952                     + ((available_width - child_width) * x_align);
12953       allocation.x2 = allocation.x1 + child_width;
12954     }
12955
12956   if (!y_fill)
12957     {
12958       allocation.y1 = y_offset
12959                     + ((available_height - child_height) * y_align);
12960       allocation.y2 = allocation.y1 + child_height;
12961     }
12962
12963 out:
12964   clutter_actor_box_clamp_to_pixel (&allocation);
12965   clutter_actor_allocate (self, &allocation, flags);
12966 }
12967
12968 /**
12969  * clutter_actor_grab_key_focus:
12970  * @self: a #ClutterActor
12971  *
12972  * Sets the key focus of the #ClutterStage including @self
12973  * to this #ClutterActor.
12974  *
12975  * Since: 1.0
12976  */
12977 void
12978 clutter_actor_grab_key_focus (ClutterActor *self)
12979 {
12980   ClutterActor *stage;
12981
12982   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12983
12984   stage = _clutter_actor_get_stage_internal (self);
12985   if (stage != NULL)
12986     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
12987 }
12988
12989 /**
12990  * clutter_actor_get_pango_context:
12991  * @self: a #ClutterActor
12992  *
12993  * Retrieves the #PangoContext for @self. The actor's #PangoContext
12994  * is already configured using the appropriate font map, resolution
12995  * and font options.
12996  *
12997  * Unlike clutter_actor_create_pango_context(), this context is owend
12998  * by the #ClutterActor and it will be updated each time the options
12999  * stored by the #ClutterBackend change.
13000  *
13001  * You can use the returned #PangoContext to create a #PangoLayout
13002  * and render text using cogl_pango_render_layout() to reuse the
13003  * glyphs cache also used by Clutter.
13004  *
13005  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13006  *   The returned #PangoContext is owned by the actor and should not be
13007  *   unreferenced by the application code
13008  *
13009  * Since: 1.0
13010  */
13011 PangoContext *
13012 clutter_actor_get_pango_context (ClutterActor *self)
13013 {
13014   ClutterActorPrivate *priv;
13015
13016   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13017
13018   priv = self->priv;
13019
13020   if (priv->pango_context != NULL)
13021     return priv->pango_context;
13022
13023   priv->pango_context = _clutter_context_get_pango_context ();
13024   g_object_ref (priv->pango_context);
13025
13026   return priv->pango_context;
13027 }
13028
13029 /**
13030  * clutter_actor_create_pango_context:
13031  * @self: a #ClutterActor
13032  *
13033  * Creates a #PangoContext for the given actor. The #PangoContext
13034  * is already configured using the appropriate font map, resolution
13035  * and font options.
13036  *
13037  * See also clutter_actor_get_pango_context().
13038  *
13039  * Return value: (transfer full): the newly created #PangoContext.
13040  *   Use g_object_unref() on the returned value to deallocate its
13041  *   resources
13042  *
13043  * Since: 1.0
13044  */
13045 PangoContext *
13046 clutter_actor_create_pango_context (ClutterActor *self)
13047 {
13048   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13049
13050   return _clutter_context_create_pango_context ();
13051 }
13052
13053 /**
13054  * clutter_actor_create_pango_layout:
13055  * @self: a #ClutterActor
13056  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13057  *
13058  * Creates a new #PangoLayout from the same #PangoContext used
13059  * by the #ClutterActor. The #PangoLayout is already configured
13060  * with the font map, resolution and font options, and the
13061  * given @text.
13062  *
13063  * If you want to keep around a #PangoLayout created by this
13064  * function you will have to connect to the #ClutterBackend::font-changed
13065  * and #ClutterBackend::resolution-changed signals, and call
13066  * pango_layout_context_changed() in response to them.
13067  *
13068  * Return value: (transfer full): the newly created #PangoLayout.
13069  *   Use g_object_unref() when done
13070  *
13071  * Since: 1.0
13072  */
13073 PangoLayout *
13074 clutter_actor_create_pango_layout (ClutterActor *self,
13075                                    const gchar  *text)
13076 {
13077   PangoContext *context;
13078   PangoLayout *layout;
13079
13080   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13081
13082   context = clutter_actor_get_pango_context (self);
13083   layout = pango_layout_new (context);
13084
13085   if (text)
13086     pango_layout_set_text (layout, text, -1);
13087
13088   return layout;
13089 }
13090
13091 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13092  * ClutterOffscreenEffect.
13093  */
13094 void
13095 _clutter_actor_set_opacity_override (ClutterActor *self,
13096                                      gint          opacity)
13097 {
13098   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13099
13100   self->priv->opacity_override = opacity;
13101 }
13102
13103 gint
13104 _clutter_actor_get_opacity_override (ClutterActor *self)
13105 {
13106   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13107
13108   return self->priv->opacity_override;
13109 }
13110
13111 /* Allows you to disable applying the actors model view transform during
13112  * a paint. Used by ClutterClone. */
13113 void
13114 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13115                                                 gboolean      enable)
13116 {
13117   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13118
13119   self->priv->enable_model_view_transform = enable;
13120 }
13121
13122 void
13123 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13124                                           gboolean      enable)
13125 {
13126   ClutterActorPrivate *priv;
13127
13128   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13129
13130   priv = self->priv;
13131
13132   priv->enable_paint_unmapped = enable;
13133
13134   if (priv->enable_paint_unmapped)
13135     {
13136       /* Make sure that the parents of the widget are realized first;
13137        * otherwise checks in clutter_actor_update_map_state() will
13138        * fail.
13139        */
13140       clutter_actor_realize (self);
13141
13142       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13143     }
13144   else
13145     {
13146       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13147     }
13148 }
13149
13150 static void
13151 clutter_anchor_coord_get_units (ClutterActor      *self,
13152                                 const AnchorCoord *coord,
13153                                 gfloat            *x,
13154                                 gfloat            *y,
13155                                 gfloat            *z)
13156 {
13157   if (coord->is_fractional)
13158     {
13159       gfloat actor_width, actor_height;
13160
13161       clutter_actor_get_size (self, &actor_width, &actor_height);
13162
13163       if (x)
13164         *x = actor_width * coord->v.fraction.x;
13165
13166       if (y)
13167         *y = actor_height * coord->v.fraction.y;
13168
13169       if (z)
13170         *z = 0;
13171     }
13172   else
13173     {
13174       if (x)
13175         *x = coord->v.units.x;
13176
13177       if (y)
13178         *y = coord->v.units.y;
13179
13180       if (z)
13181         *z = coord->v.units.z;
13182     }
13183 }
13184
13185 static void
13186 clutter_anchor_coord_set_units (AnchorCoord *coord,
13187                                 gfloat       x,
13188                                 gfloat       y,
13189                                 gfloat       z)
13190 {
13191   coord->is_fractional = FALSE;
13192   coord->v.units.x = x;
13193   coord->v.units.y = y;
13194   coord->v.units.z = z;
13195 }
13196
13197 static ClutterGravity
13198 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13199 {
13200   if (coord->is_fractional)
13201     {
13202       if (coord->v.fraction.x == 0.0)
13203         {
13204           if (coord->v.fraction.y == 0.0)
13205             return CLUTTER_GRAVITY_NORTH_WEST;
13206           else if (coord->v.fraction.y == 0.5)
13207             return CLUTTER_GRAVITY_WEST;
13208           else if (coord->v.fraction.y == 1.0)
13209             return CLUTTER_GRAVITY_SOUTH_WEST;
13210           else
13211             return CLUTTER_GRAVITY_NONE;
13212         }
13213       else if (coord->v.fraction.x == 0.5)
13214         {
13215           if (coord->v.fraction.y == 0.0)
13216             return CLUTTER_GRAVITY_NORTH;
13217           else if (coord->v.fraction.y == 0.5)
13218             return CLUTTER_GRAVITY_CENTER;
13219           else if (coord->v.fraction.y == 1.0)
13220             return CLUTTER_GRAVITY_SOUTH;
13221           else
13222             return CLUTTER_GRAVITY_NONE;
13223         }
13224       else if (coord->v.fraction.x == 1.0)
13225         {
13226           if (coord->v.fraction.y == 0.0)
13227             return CLUTTER_GRAVITY_NORTH_EAST;
13228           else if (coord->v.fraction.y == 0.5)
13229             return CLUTTER_GRAVITY_EAST;
13230           else if (coord->v.fraction.y == 1.0)
13231             return CLUTTER_GRAVITY_SOUTH_EAST;
13232           else
13233             return CLUTTER_GRAVITY_NONE;
13234         }
13235       else
13236         return CLUTTER_GRAVITY_NONE;
13237     }
13238   else
13239     return CLUTTER_GRAVITY_NONE;
13240 }
13241
13242 static void
13243 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13244                                   ClutterGravity  gravity)
13245 {
13246   switch (gravity)
13247     {
13248     case CLUTTER_GRAVITY_NORTH:
13249       coord->v.fraction.x = 0.5;
13250       coord->v.fraction.y = 0.0;
13251       break;
13252
13253     case CLUTTER_GRAVITY_NORTH_EAST:
13254       coord->v.fraction.x = 1.0;
13255       coord->v.fraction.y = 0.0;
13256       break;
13257
13258     case CLUTTER_GRAVITY_EAST:
13259       coord->v.fraction.x = 1.0;
13260       coord->v.fraction.y = 0.5;
13261       break;
13262
13263     case CLUTTER_GRAVITY_SOUTH_EAST:
13264       coord->v.fraction.x = 1.0;
13265       coord->v.fraction.y = 1.0;
13266       break;
13267
13268     case CLUTTER_GRAVITY_SOUTH:
13269       coord->v.fraction.x = 0.5;
13270       coord->v.fraction.y = 1.0;
13271       break;
13272
13273     case CLUTTER_GRAVITY_SOUTH_WEST:
13274       coord->v.fraction.x = 0.0;
13275       coord->v.fraction.y = 1.0;
13276       break;
13277
13278     case CLUTTER_GRAVITY_WEST:
13279       coord->v.fraction.x = 0.0;
13280       coord->v.fraction.y = 0.5;
13281       break;
13282
13283     case CLUTTER_GRAVITY_NORTH_WEST:
13284       coord->v.fraction.x = 0.0;
13285       coord->v.fraction.y = 0.0;
13286       break;
13287
13288     case CLUTTER_GRAVITY_CENTER:
13289       coord->v.fraction.x = 0.5;
13290       coord->v.fraction.y = 0.5;
13291       break;
13292
13293     default:
13294       coord->v.fraction.x = 0.0;
13295       coord->v.fraction.y = 0.0;
13296       break;
13297     }
13298
13299   coord->is_fractional = TRUE;
13300 }
13301
13302 static gboolean
13303 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13304 {
13305   if (coord->is_fractional)
13306     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13307   else
13308     return (coord->v.units.x == 0.0
13309             && coord->v.units.y == 0.0
13310             && coord->v.units.z == 0.0);
13311 }
13312
13313 /**
13314  * clutter_actor_get_flags:
13315  * @self: a #ClutterActor
13316  *
13317  * Retrieves the flags set on @self
13318  *
13319  * Return value: a bitwise or of #ClutterActorFlags or 0
13320  *
13321  * Since: 1.0
13322  */
13323 ClutterActorFlags
13324 clutter_actor_get_flags (ClutterActor *self)
13325 {
13326   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13327
13328   return self->flags;
13329 }
13330
13331 /**
13332  * clutter_actor_set_flags:
13333  * @self: a #ClutterActor
13334  * @flags: the flags to set
13335  *
13336  * Sets @flags on @self
13337  *
13338  * This function will emit notifications for the changed properties
13339  *
13340  * Since: 1.0
13341  */
13342 void
13343 clutter_actor_set_flags (ClutterActor      *self,
13344                          ClutterActorFlags  flags)
13345 {
13346   ClutterActorFlags old_flags;
13347   GObject *obj;
13348   gboolean was_reactive_set, reactive_set;
13349   gboolean was_realized_set, realized_set;
13350   gboolean was_mapped_set, mapped_set;
13351   gboolean was_visible_set, visible_set;
13352
13353   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13354
13355   if (self->flags == flags)
13356     return;
13357
13358   obj = G_OBJECT (self);
13359   g_object_ref (obj);
13360   g_object_freeze_notify (obj);
13361
13362   old_flags = self->flags;
13363
13364   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13365   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13366   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13367   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13368
13369   self->flags |= flags;
13370
13371   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13372   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13373   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13374   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13375
13376   if (reactive_set != was_reactive_set)
13377     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13378
13379   if (realized_set != was_realized_set)
13380     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13381
13382   if (mapped_set != was_mapped_set)
13383     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13384
13385   if (visible_set != was_visible_set)
13386     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13387
13388   g_object_thaw_notify (obj);
13389   g_object_unref (obj);
13390 }
13391
13392 /**
13393  * clutter_actor_unset_flags:
13394  * @self: a #ClutterActor
13395  * @flags: the flags to unset
13396  *
13397  * Unsets @flags on @self
13398  *
13399  * This function will emit notifications for the changed properties
13400  *
13401  * Since: 1.0
13402  */
13403 void
13404 clutter_actor_unset_flags (ClutterActor      *self,
13405                            ClutterActorFlags  flags)
13406 {
13407   ClutterActorFlags old_flags;
13408   GObject *obj;
13409   gboolean was_reactive_set, reactive_set;
13410   gboolean was_realized_set, realized_set;
13411   gboolean was_mapped_set, mapped_set;
13412   gboolean was_visible_set, visible_set;
13413
13414   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13415
13416   obj = G_OBJECT (self);
13417   g_object_freeze_notify (obj);
13418
13419   old_flags = self->flags;
13420
13421   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13422   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13423   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13424   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13425
13426   self->flags &= ~flags;
13427
13428   if (self->flags == old_flags)
13429     return;
13430
13431   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13432   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13433   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13434   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13435
13436   if (reactive_set != was_reactive_set)
13437     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13438
13439   if (realized_set != was_realized_set)
13440     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13441
13442   if (mapped_set != was_mapped_set)
13443     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13444
13445   if (visible_set != was_visible_set)
13446     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13447
13448   g_object_thaw_notify (obj);
13449 }
13450
13451 /**
13452  * clutter_actor_get_transformation_matrix:
13453  * @self: a #ClutterActor
13454  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13455  *
13456  * Retrieves the transformations applied to @self relative to its
13457  * parent.
13458  *
13459  * Since: 1.0
13460  */
13461 void
13462 clutter_actor_get_transformation_matrix (ClutterActor *self,
13463                                          CoglMatrix   *matrix)
13464 {
13465   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13466
13467   cogl_matrix_init_identity (matrix);
13468
13469   _clutter_actor_apply_modelview_transform (self, matrix);
13470 }
13471
13472 void
13473 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13474                                    gboolean      is_in_clone_paint)
13475 {
13476   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13477   self->priv->in_clone_paint = is_in_clone_paint;
13478 }
13479
13480 /**
13481  * clutter_actor_is_in_clone_paint:
13482  * @self: a #ClutterActor
13483  *
13484  * Checks whether @self is being currently painted by a #ClutterClone
13485  *
13486  * This function is useful only inside the ::paint virtual function
13487  * implementations or within handlers for the #ClutterActor::paint
13488  * signal
13489  *
13490  * This function should not be used by applications
13491  *
13492  * Return value: %TRUE if the #ClutterActor is currently being painted
13493  *   by a #ClutterClone, and %FALSE otherwise
13494  *
13495  * Since: 1.0
13496  */
13497 gboolean
13498 clutter_actor_is_in_clone_paint (ClutterActor *self)
13499 {
13500   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13501
13502   return self->priv->in_clone_paint;
13503 }
13504
13505 static gboolean
13506 set_direction_recursive (ClutterActor *actor,
13507                          gpointer      user_data)
13508 {
13509   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
13510
13511   clutter_actor_set_text_direction (actor, text_dir);
13512
13513   return TRUE;
13514 }
13515
13516 /**
13517  * clutter_actor_set_text_direction:
13518  * @self: a #ClutterActor
13519  * @text_dir: the text direction for @self
13520  *
13521  * Sets the #ClutterTextDirection for an actor
13522  *
13523  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
13524  *
13525  * If @self implements #ClutterContainer then this function will recurse
13526  * inside all the children of @self (including the internal ones).
13527  *
13528  * Composite actors not implementing #ClutterContainer, or actors requiring
13529  * special handling when the text direction changes, should connect to
13530  * the #GObject::notify signal for the #ClutterActor:text-direction property
13531  *
13532  * Since: 1.2
13533  */
13534 void
13535 clutter_actor_set_text_direction (ClutterActor         *self,
13536                                   ClutterTextDirection  text_dir)
13537 {
13538   ClutterActorPrivate *priv;
13539
13540   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13541   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
13542
13543   priv = self->priv;
13544
13545   if (priv->text_direction != text_dir)
13546     {
13547       priv->text_direction = text_dir;
13548
13549       /* we need to emit the notify::text-direction first, so that
13550        * the sub-classes can catch that and do specific handling of
13551        * the text direction; see clutter_text_direction_changed_cb()
13552        * inside clutter-text.c
13553        */
13554       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
13555
13556       _clutter_actor_foreach_child (self, set_direction_recursive,
13557                                     GINT_TO_POINTER (text_dir));
13558
13559       clutter_actor_queue_relayout (self);
13560     }
13561 }
13562
13563 void
13564 _clutter_actor_set_has_pointer (ClutterActor *self,
13565                                 gboolean      has_pointer)
13566 {
13567   ClutterActorPrivate *priv = self->priv;
13568
13569   if (priv->has_pointer != has_pointer)
13570     {
13571       priv->has_pointer = has_pointer;
13572
13573       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
13574     }
13575 }
13576
13577 /**
13578  * clutter_actor_get_text_direction:
13579  * @self: a #ClutterActor
13580  *
13581  * Retrieves the value set using clutter_actor_set_text_direction()
13582  *
13583  * If no text direction has been previously set, the default text
13584  * direction, as returned by clutter_get_default_text_direction(), will
13585  * be returned instead
13586  *
13587  * Return value: the #ClutterTextDirection for the actor
13588  *
13589  * Since: 1.2
13590  */
13591 ClutterTextDirection
13592 clutter_actor_get_text_direction (ClutterActor *self)
13593 {
13594   ClutterActorPrivate *priv;
13595
13596   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
13597                         CLUTTER_TEXT_DIRECTION_LTR);
13598
13599   priv = self->priv;
13600
13601   /* if no direction has been set yet use the default */
13602   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
13603     priv->text_direction = clutter_get_default_text_direction ();
13604
13605   return priv->text_direction;
13606 }
13607
13608 /**
13609  * clutter_actor_push_internal:
13610  * @self: a #ClutterActor
13611  *
13612  * Should be used by actors implementing the #ClutterContainer and with
13613  * internal children added through clutter_actor_set_parent(), for instance:
13614  *
13615  * |[
13616  *   static void
13617  *   my_actor_init (MyActor *self)
13618  *   {
13619  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
13620  *
13621  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
13622  *
13623  *     /&ast; calling clutter_actor_set_parent() now will result in
13624  *      &ast; the internal flag being set on a child of MyActor
13625  *      &ast;/
13626  *
13627  *     /&ast; internal child - a background texture &ast;/
13628  *     self->priv->background_tex = clutter_texture_new ();
13629  *     clutter_actor_set_parent (self->priv->background_tex,
13630  *                               CLUTTER_ACTOR (self));
13631  *
13632  *     /&ast; internal child - a label &ast;/
13633  *     self->priv->label = clutter_text_new ();
13634  *     clutter_actor_set_parent (self->priv->label,
13635  *                               CLUTTER_ACTOR (self));
13636  *
13637  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
13638  *
13639  *     /&ast; calling clutter_actor_set_parent() now will not result in
13640  *      &ast; the internal flag being set on a child of MyActor
13641  *      &ast;/
13642  *   }
13643  * ]|
13644  *
13645  * This function will be used by Clutter to toggle an "internal child"
13646  * flag whenever clutter_actor_set_parent() is called; internal children
13647  * are handled differently by Clutter, specifically when destroying their
13648  * parent.
13649  *
13650  * Call clutter_actor_pop_internal() when you finished adding internal
13651  * children.
13652  *
13653  * Nested calls to clutter_actor_push_internal() are allowed, but each
13654  * one must by followed by a clutter_actor_pop_internal() call.
13655  *
13656  * Since: 1.2
13657  *
13658  * Deprecated: 1.10: All children of an actor are accessible through
13659  *   the #ClutterActor API, and #ClutterActor implements the
13660  *   #ClutterContainer interface, so this function is only useful
13661  *   for legacy containers overriding the default implementation.
13662  */
13663 void
13664 clutter_actor_push_internal (ClutterActor *self)
13665 {
13666   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13667
13668   self->priv->internal_child += 1;
13669 }
13670
13671 /**
13672  * clutter_actor_pop_internal:
13673  * @self: a #ClutterActor
13674  *
13675  * Disables the effects of clutter_actor_push_internal().
13676  *
13677  * Since: 1.2
13678  *
13679  * Deprecated: 1.10: All children of an actor are accessible through
13680  *   the #ClutterActor API. This function is only useful for legacy
13681  *   containers overriding the default implementation of the
13682  *   #ClutterContainer interface.
13683  */
13684 void
13685 clutter_actor_pop_internal (ClutterActor *self)
13686 {
13687   ClutterActorPrivate *priv;
13688
13689   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13690
13691   priv = self->priv;
13692
13693   if (priv->internal_child == 0)
13694     {
13695       g_warning ("Mismatched %s: you need to call "
13696                  "clutter_actor_push_composite() at least once before "
13697                  "calling this function", G_STRFUNC);
13698       return;
13699     }
13700
13701   priv->internal_child -= 1;
13702 }
13703
13704 /**
13705  * clutter_actor_has_pointer:
13706  * @self: a #ClutterActor
13707  *
13708  * Checks whether an actor contains the pointer of a
13709  * #ClutterInputDevice
13710  *
13711  * Return value: %TRUE if the actor contains the pointer, and
13712  *   %FALSE otherwise
13713  *
13714  * Since: 1.2
13715  */
13716 gboolean
13717 clutter_actor_has_pointer (ClutterActor *self)
13718 {
13719   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13720
13721   return self->priv->has_pointer;
13722 }
13723
13724 /* XXX: This is a workaround for not being able to break the ABI of
13725  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
13726  * clutter_actor_queue_clipped_redraw() for details.
13727  */
13728 ClutterPaintVolume *
13729 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
13730 {
13731   return g_object_get_data (G_OBJECT (self),
13732                             "-clutter-actor-queue-redraw-clip");
13733 }
13734
13735 void
13736 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
13737                                       ClutterPaintVolume *clip)
13738 {
13739   g_object_set_data (G_OBJECT (self),
13740                      "-clutter-actor-queue-redraw-clip",
13741                      clip);
13742 }
13743
13744 /**
13745  * clutter_actor_has_allocation:
13746  * @self: a #ClutterActor
13747  *
13748  * Checks if the actor has an up-to-date allocation assigned to
13749  * it. This means that the actor should have an allocation: it's
13750  * visible and has a parent. It also means that there is no
13751  * outstanding relayout request in progress for the actor or its
13752  * children (There might be other outstanding layout requests in
13753  * progress that will cause the actor to get a new allocation
13754  * when the stage is laid out, however).
13755  *
13756  * If this function returns %FALSE, then the actor will normally
13757  * be allocated before it is next drawn on the screen.
13758  *
13759  * Return value: %TRUE if the actor has an up-to-date allocation
13760  *
13761  * Since: 1.4
13762  */
13763 gboolean
13764 clutter_actor_has_allocation (ClutterActor *self)
13765 {
13766   ClutterActorPrivate *priv;
13767
13768   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13769
13770   priv = self->priv;
13771
13772   return priv->parent != NULL &&
13773          CLUTTER_ACTOR_IS_VISIBLE (self) &&
13774          !priv->needs_allocation;
13775 }
13776
13777 /**
13778  * clutter_actor_add_action:
13779  * @self: a #ClutterActor
13780  * @action: a #ClutterAction
13781  *
13782  * Adds @action to the list of actions applied to @self
13783  *
13784  * A #ClutterAction can only belong to one actor at a time
13785  *
13786  * The #ClutterActor will hold a reference on @action until either
13787  * clutter_actor_remove_action() or clutter_actor_clear_actions()
13788  * is called
13789  *
13790  * Since: 1.4
13791  */
13792 void
13793 clutter_actor_add_action (ClutterActor  *self,
13794                           ClutterAction *action)
13795 {
13796   ClutterActorPrivate *priv;
13797
13798   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13799   g_return_if_fail (CLUTTER_IS_ACTION (action));
13800
13801   priv = self->priv;
13802
13803   if (priv->actions == NULL)
13804     {
13805       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13806       priv->actions->actor = self;
13807     }
13808
13809   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
13810
13811   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13812 }
13813
13814 /**
13815  * clutter_actor_add_action_with_name:
13816  * @self: a #ClutterActor
13817  * @name: the name to set on the action
13818  * @action: a #ClutterAction
13819  *
13820  * A convenience function for setting the name of a #ClutterAction
13821  * while adding it to the list of actions applied to @self
13822  *
13823  * This function is the logical equivalent of:
13824  *
13825  * |[
13826  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13827  *   clutter_actor_add_action (self, action);
13828  * ]|
13829  *
13830  * Since: 1.4
13831  */
13832 void
13833 clutter_actor_add_action_with_name (ClutterActor  *self,
13834                                     const gchar   *name,
13835                                     ClutterAction *action)
13836 {
13837   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13838   g_return_if_fail (name != NULL);
13839   g_return_if_fail (CLUTTER_IS_ACTION (action));
13840
13841   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13842   clutter_actor_add_action (self, action);
13843 }
13844
13845 /**
13846  * clutter_actor_remove_action:
13847  * @self: a #ClutterActor
13848  * @action: a #ClutterAction
13849  *
13850  * Removes @action from the list of actions applied to @self
13851  *
13852  * The reference held by @self on the #ClutterAction will be released
13853  *
13854  * Since: 1.4
13855  */
13856 void
13857 clutter_actor_remove_action (ClutterActor  *self,
13858                              ClutterAction *action)
13859 {
13860   ClutterActorPrivate *priv;
13861
13862   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13863   g_return_if_fail (CLUTTER_IS_ACTION (action));
13864
13865   priv = self->priv;
13866
13867   if (priv->actions == NULL)
13868     return;
13869
13870   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
13871
13872   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13873 }
13874
13875 /**
13876  * clutter_actor_remove_action_by_name:
13877  * @self: a #ClutterActor
13878  * @name: the name of the action to remove
13879  *
13880  * Removes the #ClutterAction with the given name from the list
13881  * of actions applied to @self
13882  *
13883  * Since: 1.4
13884  */
13885 void
13886 clutter_actor_remove_action_by_name (ClutterActor *self,
13887                                      const gchar  *name)
13888 {
13889   ClutterActorPrivate *priv;
13890   ClutterActorMeta *meta;
13891
13892   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13893   g_return_if_fail (name != NULL);
13894
13895   priv = self->priv;
13896
13897   if (priv->actions == NULL)
13898     return;
13899
13900   meta = _clutter_meta_group_get_meta (priv->actions, name);
13901   if (meta == NULL)
13902     return;
13903
13904   _clutter_meta_group_remove_meta (priv->actions, meta);
13905
13906   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13907 }
13908
13909 /**
13910  * clutter_actor_get_actions:
13911  * @self: a #ClutterActor
13912  *
13913  * Retrieves the list of actions applied to @self
13914  *
13915  * Return value: (transfer container) (element-type Clutter.Action): a copy
13916  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
13917  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13918  *   allocated by the returned #GList
13919  *
13920  * Since: 1.4
13921  */
13922 GList *
13923 clutter_actor_get_actions (ClutterActor *self)
13924 {
13925   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13926
13927   if (self->priv->actions == NULL)
13928     return NULL;
13929
13930   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
13931 }
13932
13933 /**
13934  * clutter_actor_get_action:
13935  * @self: a #ClutterActor
13936  * @name: the name of the action to retrieve
13937  *
13938  * Retrieves the #ClutterAction with the given name in the list
13939  * of actions applied to @self
13940  *
13941  * Return value: (transfer none): a #ClutterAction for the given
13942  *   name, or %NULL. The returned #ClutterAction is owned by the
13943  *   actor and it should not be unreferenced directly
13944  *
13945  * Since: 1.4
13946  */
13947 ClutterAction *
13948 clutter_actor_get_action (ClutterActor *self,
13949                           const gchar  *name)
13950 {
13951   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13952   g_return_val_if_fail (name != NULL, NULL);
13953
13954   if (self->priv->actions == NULL)
13955     return NULL;
13956
13957   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
13958 }
13959
13960 /**
13961  * clutter_actor_clear_actions:
13962  * @self: a #ClutterActor
13963  *
13964  * Clears the list of actions applied to @self
13965  *
13966  * Since: 1.4
13967  */
13968 void
13969 clutter_actor_clear_actions (ClutterActor *self)
13970 {
13971   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13972
13973   if (self->priv->actions == NULL)
13974     return;
13975
13976   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
13977 }
13978
13979 /**
13980  * clutter_actor_add_constraint:
13981  * @self: a #ClutterActor
13982  * @constraint: a #ClutterConstraint
13983  *
13984  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
13985  * to @self
13986  *
13987  * The #ClutterActor will hold a reference on the @constraint until
13988  * either clutter_actor_remove_constraint() or
13989  * clutter_actor_clear_constraints() is called.
13990  *
13991  * Since: 1.4
13992  */
13993 void
13994 clutter_actor_add_constraint (ClutterActor      *self,
13995                               ClutterConstraint *constraint)
13996 {
13997   ClutterActorPrivate *priv;
13998
13999   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14000   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14001
14002   priv = self->priv;
14003
14004   if (priv->constraints == NULL)
14005     {
14006       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14007       priv->constraints->actor = self;
14008     }
14009
14010   _clutter_meta_group_add_meta (priv->constraints,
14011                                 CLUTTER_ACTOR_META (constraint));
14012   clutter_actor_queue_relayout (self);
14013
14014   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14015 }
14016
14017 /**
14018  * clutter_actor_add_constraint_with_name:
14019  * @self: a #ClutterActor
14020  * @name: the name to set on the constraint
14021  * @constraint: a #ClutterConstraint
14022  *
14023  * A convenience function for setting the name of a #ClutterConstraint
14024  * while adding it to the list of constraints applied to @self
14025  *
14026  * This function is the logical equivalent of:
14027  *
14028  * |[
14029  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14030  *   clutter_actor_add_constraint (self, constraint);
14031  * ]|
14032  *
14033  * Since: 1.4
14034  */
14035 void
14036 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14037                                         const gchar       *name,
14038                                         ClutterConstraint *constraint)
14039 {
14040   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14041   g_return_if_fail (name != NULL);
14042   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14043
14044   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14045   clutter_actor_add_constraint (self, constraint);
14046 }
14047
14048 /**
14049  * clutter_actor_remove_constraint:
14050  * @self: a #ClutterActor
14051  * @constraint: a #ClutterConstraint
14052  *
14053  * Removes @constraint from the list of constraints applied to @self
14054  *
14055  * The reference held by @self on the #ClutterConstraint will be released
14056  *
14057  * Since: 1.4
14058  */
14059 void
14060 clutter_actor_remove_constraint (ClutterActor      *self,
14061                                  ClutterConstraint *constraint)
14062 {
14063   ClutterActorPrivate *priv;
14064
14065   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14066   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14067
14068   priv = self->priv;
14069
14070   if (priv->constraints == NULL)
14071     return;
14072
14073   _clutter_meta_group_remove_meta (priv->constraints,
14074                                    CLUTTER_ACTOR_META (constraint));
14075   clutter_actor_queue_relayout (self);
14076
14077   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14078 }
14079
14080 /**
14081  * clutter_actor_remove_constraint_by_name:
14082  * @self: a #ClutterActor
14083  * @name: the name of the constraint to remove
14084  *
14085  * Removes the #ClutterConstraint with the given name from the list
14086  * of constraints applied to @self
14087  *
14088  * Since: 1.4
14089  */
14090 void
14091 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14092                                          const gchar  *name)
14093 {
14094   ClutterActorPrivate *priv;
14095   ClutterActorMeta *meta;
14096
14097   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14098   g_return_if_fail (name != NULL);
14099
14100   priv = self->priv;
14101
14102   if (priv->constraints == NULL)
14103     return;
14104
14105   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14106   if (meta == NULL)
14107     return;
14108
14109   _clutter_meta_group_remove_meta (priv->constraints, meta);
14110   clutter_actor_queue_relayout (self);
14111 }
14112
14113 /**
14114  * clutter_actor_get_constraints:
14115  * @self: a #ClutterActor
14116  *
14117  * Retrieves the list of constraints applied to @self
14118  *
14119  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14120  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14121  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14122  *   allocated by the returned #GList
14123  *
14124  * Since: 1.4
14125  */
14126 GList *
14127 clutter_actor_get_constraints (ClutterActor *self)
14128 {
14129   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14130
14131   if (self->priv->constraints == NULL)
14132     return NULL;
14133
14134   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14135 }
14136
14137 /**
14138  * clutter_actor_get_constraint:
14139  * @self: a #ClutterActor
14140  * @name: the name of the constraint to retrieve
14141  *
14142  * Retrieves the #ClutterConstraint with the given name in the list
14143  * of constraints applied to @self
14144  *
14145  * Return value: (transfer none): a #ClutterConstraint for the given
14146  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14147  *   actor and it should not be unreferenced directly
14148  *
14149  * Since: 1.4
14150  */
14151 ClutterConstraint *
14152 clutter_actor_get_constraint (ClutterActor *self,
14153                               const gchar  *name)
14154 {
14155   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14156   g_return_val_if_fail (name != NULL, NULL);
14157
14158   if (self->priv->constraints == NULL)
14159     return NULL;
14160
14161   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14162 }
14163
14164 /**
14165  * clutter_actor_clear_constraints:
14166  * @self: a #ClutterActor
14167  *
14168  * Clears the list of constraints applied to @self
14169  *
14170  * Since: 1.4
14171  */
14172 void
14173 clutter_actor_clear_constraints (ClutterActor *self)
14174 {
14175   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14176
14177   if (self->priv->constraints == NULL)
14178     return;
14179
14180   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14181
14182   clutter_actor_queue_relayout (self);
14183 }
14184
14185 /**
14186  * clutter_actor_set_clip_to_allocation:
14187  * @self: a #ClutterActor
14188  * @clip_set: %TRUE to apply a clip tracking the allocation
14189  *
14190  * Sets whether @self should be clipped to the same size as its
14191  * allocation
14192  *
14193  * Since: 1.4
14194  */
14195 void
14196 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14197                                       gboolean      clip_set)
14198 {
14199   ClutterActorPrivate *priv;
14200
14201   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14202
14203   clip_set = !!clip_set;
14204
14205   priv = self->priv;
14206
14207   if (priv->clip_to_allocation != clip_set)
14208     {
14209       priv->clip_to_allocation = clip_set;
14210
14211       clutter_actor_queue_redraw (self);
14212
14213       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14214     }
14215 }
14216
14217 /**
14218  * clutter_actor_get_clip_to_allocation:
14219  * @self: a #ClutterActor
14220  *
14221  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14222  *
14223  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14224  *
14225  * Since: 1.4
14226  */
14227 gboolean
14228 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14229 {
14230   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14231
14232   return self->priv->clip_to_allocation;
14233 }
14234
14235 /**
14236  * clutter_actor_add_effect:
14237  * @self: a #ClutterActor
14238  * @effect: a #ClutterEffect
14239  *
14240  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14241  *
14242  * The #ClutterActor will hold a reference on the @effect until either
14243  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14244  * called.
14245  *
14246  * Since: 1.4
14247  */
14248 void
14249 clutter_actor_add_effect (ClutterActor  *self,
14250                           ClutterEffect *effect)
14251 {
14252   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14253   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14254
14255   _clutter_actor_add_effect_internal (self, effect);
14256
14257   clutter_actor_queue_redraw (self);
14258
14259   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14260 }
14261
14262 /**
14263  * clutter_actor_add_effect_with_name:
14264  * @self: a #ClutterActor
14265  * @name: the name to set on the effect
14266  * @effect: a #ClutterEffect
14267  *
14268  * A convenience function for setting the name of a #ClutterEffect
14269  * while adding it to the list of effectss applied to @self
14270  *
14271  * This function is the logical equivalent of:
14272  *
14273  * |[
14274  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14275  *   clutter_actor_add_effect (self, effect);
14276  * ]|
14277  *
14278  * Since: 1.4
14279  */
14280 void
14281 clutter_actor_add_effect_with_name (ClutterActor  *self,
14282                                     const gchar   *name,
14283                                     ClutterEffect *effect)
14284 {
14285   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14286   g_return_if_fail (name != NULL);
14287   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14288
14289   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14290   clutter_actor_add_effect (self, effect);
14291 }
14292
14293 /**
14294  * clutter_actor_remove_effect:
14295  * @self: a #ClutterActor
14296  * @effect: a #ClutterEffect
14297  *
14298  * Removes @effect from the list of effects applied to @self
14299  *
14300  * The reference held by @self on the #ClutterEffect will be released
14301  *
14302  * Since: 1.4
14303  */
14304 void
14305 clutter_actor_remove_effect (ClutterActor  *self,
14306                              ClutterEffect *effect)
14307 {
14308   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14309   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14310
14311   _clutter_actor_remove_effect_internal (self, effect);
14312
14313   clutter_actor_queue_redraw (self);
14314
14315   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14316 }
14317
14318 /**
14319  * clutter_actor_remove_effect_by_name:
14320  * @self: a #ClutterActor
14321  * @name: the name of the effect to remove
14322  *
14323  * Removes the #ClutterEffect with the given name from the list
14324  * of effects applied to @self
14325  *
14326  * Since: 1.4
14327  */
14328 void
14329 clutter_actor_remove_effect_by_name (ClutterActor *self,
14330                                      const gchar  *name)
14331 {
14332   ClutterActorPrivate *priv;
14333   ClutterActorMeta *meta;
14334
14335   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14336   g_return_if_fail (name != NULL);
14337
14338   priv = self->priv;
14339
14340   if (priv->effects == NULL)
14341     return;
14342
14343   meta = _clutter_meta_group_get_meta (priv->effects, name);
14344   if (meta == NULL)
14345     return;
14346
14347   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14348 }
14349
14350 /**
14351  * clutter_actor_get_effects:
14352  * @self: a #ClutterActor
14353  *
14354  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14355  *
14356  * Return value: (transfer container) (element-type Clutter.Effect): a list
14357  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14358  *   list are owned by Clutter and they should not be freed. You should
14359  *   free the returned list using g_list_free() when done
14360  *
14361  * Since: 1.4
14362  */
14363 GList *
14364 clutter_actor_get_effects (ClutterActor *self)
14365 {
14366   ClutterActorPrivate *priv;
14367
14368   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14369
14370   priv = self->priv;
14371
14372   if (priv->effects == NULL)
14373     return NULL;
14374
14375   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14376 }
14377
14378 /**
14379  * clutter_actor_get_effect:
14380  * @self: a #ClutterActor
14381  * @name: the name of the effect to retrieve
14382  *
14383  * Retrieves the #ClutterEffect with the given name in the list
14384  * of effects applied to @self
14385  *
14386  * Return value: (transfer none): a #ClutterEffect for the given
14387  *   name, or %NULL. The returned #ClutterEffect is owned by the
14388  *   actor and it should not be unreferenced directly
14389  *
14390  * Since: 1.4
14391  */
14392 ClutterEffect *
14393 clutter_actor_get_effect (ClutterActor *self,
14394                           const gchar  *name)
14395 {
14396   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14397   g_return_val_if_fail (name != NULL, NULL);
14398
14399   if (self->priv->effects == NULL)
14400     return NULL;
14401
14402   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14403 }
14404
14405 /**
14406  * clutter_actor_clear_effects:
14407  * @self: a #ClutterActor
14408  *
14409  * Clears the list of effects applied to @self
14410  *
14411  * Since: 1.4
14412  */
14413 void
14414 clutter_actor_clear_effects (ClutterActor *self)
14415 {
14416   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14417
14418   if (self->priv->effects == NULL)
14419     return;
14420
14421   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14422
14423   clutter_actor_queue_redraw (self);
14424 }
14425
14426 /**
14427  * clutter_actor_has_key_focus:
14428  * @self: a #ClutterActor
14429  *
14430  * Checks whether @self is the #ClutterActor that has key focus
14431  *
14432  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14433  *
14434  * Since: 1.4
14435  */
14436 gboolean
14437 clutter_actor_has_key_focus (ClutterActor *self)
14438 {
14439   ClutterActor *stage;
14440
14441   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14442
14443   stage = _clutter_actor_get_stage_internal (self);
14444   if (stage == NULL)
14445     return FALSE;
14446
14447   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14448 }
14449
14450 static gboolean
14451 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14452                                       ClutterPaintVolume *pv)
14453 {
14454   ClutterActorPrivate *priv = self->priv;
14455
14456   /* Actors are only expected to report a valid paint volume
14457    * while they have a valid allocation. */
14458   if (G_UNLIKELY (priv->needs_allocation))
14459     {
14460       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14461                     "Actor needs allocation",
14462                     _clutter_actor_get_debug_name (self));
14463       return FALSE;
14464     }
14465
14466   /* Check if there are any handlers connected to the paint
14467    * signal. If there are then all bets are off for what the paint
14468    * volume for this actor might possibly be!
14469    *
14470    * XXX: It's expected that this is going to end up being quite a
14471    * costly check to have to do here, but we haven't come up with
14472    * another solution that can reliably catch paint signal handlers at
14473    * the right time to either avoid artefacts due to invalid stage
14474    * clipping or due to incorrect culling.
14475    *
14476    * Previously we checked in clutter_actor_paint(), but at that time
14477    * we may already be using a stage clip that could be derived from
14478    * an invalid paint-volume. We used to try and handle that by
14479    * queuing a follow up, unclipped, redraw but still the previous
14480    * checking wasn't enough to catch invalid volumes involved in
14481    * culling (considering that containers may derive their volume from
14482    * children that haven't yet been painted)
14483    *
14484    * Longer term, improved solutions could be:
14485    * - Disallow painting in the paint signal, only allow using it
14486    *   for tracking when paints happen. We can add another API that
14487    *   allows monkey patching the paint of arbitrary actors but in a
14488    *   more controlled way and that also supports modifying the
14489    *   paint-volume.
14490    * - If we could be notified somehow when signal handlers are
14491    *   connected we wouldn't have to poll for handlers like this.
14492    */
14493   if (g_signal_has_handler_pending (self,
14494                                     actor_signals[PAINT],
14495                                     0,
14496                                     TRUE))
14497     {
14498       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14499                     "Actor has \"paint\" signal handlers",
14500                     _clutter_actor_get_debug_name (self));
14501       return FALSE;
14502     }
14503
14504   _clutter_paint_volume_init_static (pv, self);
14505
14506   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
14507     {
14508       clutter_paint_volume_free (pv);
14509       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14510                     "Actor failed to report a volume",
14511                     _clutter_actor_get_debug_name (self));
14512       return FALSE;
14513     }
14514
14515   /* since effects can modify the paint volume, we allow them to actually
14516    * do this by making get_paint_volume() "context sensitive"
14517    */
14518   if (priv->effects != NULL)
14519     {
14520       if (priv->current_effect != NULL)
14521         {
14522           const GList *effects, *l;
14523
14524           /* if we are being called from within the paint sequence of
14525            * an actor, get the paint volume up to the current effect
14526            */
14527           effects = _clutter_meta_group_peek_metas (priv->effects);
14528           for (l = effects;
14529                l != NULL || (l != NULL && l->data != priv->current_effect);
14530                l = l->next)
14531             {
14532               if (!_clutter_effect_get_paint_volume (l->data, pv))
14533                 {
14534                   clutter_paint_volume_free (pv);
14535                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14536                                 "Effect (%s) failed to report a volume",
14537                                 _clutter_actor_get_debug_name (self),
14538                                 _clutter_actor_meta_get_debug_name (l->data));
14539                   return FALSE;
14540                 }
14541             }
14542         }
14543       else
14544         {
14545           const GList *effects, *l;
14546
14547           /* otherwise, get the cumulative volume */
14548           effects = _clutter_meta_group_peek_metas (priv->effects);
14549           for (l = effects; l != NULL; l = l->next)
14550             if (!_clutter_effect_get_paint_volume (l->data, pv))
14551               {
14552                 clutter_paint_volume_free (pv);
14553                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14554                               "Effect (%s) failed to report a volume",
14555                               _clutter_actor_get_debug_name (self),
14556                               _clutter_actor_meta_get_debug_name (l->data));
14557                 return FALSE;
14558               }
14559         }
14560     }
14561
14562   return TRUE;
14563 }
14564
14565 /* The public clutter_actor_get_paint_volume API returns a const
14566  * pointer since we return a pointer directly to the cached
14567  * PaintVolume associated with the actor and don't want the user to
14568  * inadvertently modify it, but for internal uses we sometimes need
14569  * access to the same PaintVolume but need to apply some book-keeping
14570  * modifications to it so we don't want a const pointer.
14571  */
14572 static ClutterPaintVolume *
14573 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
14574 {
14575   ClutterActorPrivate *priv;
14576
14577   priv = self->priv;
14578
14579   if (priv->paint_volume_valid)
14580     clutter_paint_volume_free (&priv->paint_volume);
14581
14582   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
14583     {
14584       priv->paint_volume_valid = TRUE;
14585       return &priv->paint_volume;
14586     }
14587   else
14588     {
14589       priv->paint_volume_valid = FALSE;
14590       return NULL;
14591     }
14592 }
14593
14594 /**
14595  * clutter_actor_get_paint_volume:
14596  * @self: a #ClutterActor
14597  *
14598  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
14599  * when a paint volume can't be determined.
14600  *
14601  * The paint volume is defined as the 3D space occupied by an actor
14602  * when being painted.
14603  *
14604  * This function will call the <function>get_paint_volume()</function>
14605  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
14606  * should not usually care about overriding the default implementation,
14607  * unless they are, for instance: painting outside their allocation, or
14608  * actors with a depth factor (not in terms of #ClutterActor:depth but real
14609  * 3D depth).
14610  *
14611  * <note>2D actors overriding <function>get_paint_volume()</function>
14612  * ensure their volume has a depth of 0. (This will be true so long as
14613  * you don't call clutter_paint_volume_set_depth().)</note>
14614  *
14615  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
14616  *   or %NULL if no volume could be determined. The returned pointer
14617  *   is not guaranteed to be valid across multiple frames; if you want
14618  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
14619  *
14620  * Since: 1.6
14621  */
14622 const ClutterPaintVolume *
14623 clutter_actor_get_paint_volume (ClutterActor *self)
14624 {
14625   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14626
14627   return _clutter_actor_get_paint_volume_mutable (self);
14628 }
14629
14630 /**
14631  * clutter_actor_get_transformed_paint_volume:
14632  * @self: a #ClutterActor
14633  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
14634  *    (or %NULL for the stage)
14635  *
14636  * Retrieves the 3D paint volume of an actor like
14637  * clutter_actor_get_paint_volume() does (Please refer to the
14638  * documentation of clutter_actor_get_paint_volume() for more
14639  * details.) and it additionally transforms the paint volume into the
14640  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
14641  * is passed for @relative_to_ancestor)
14642  *
14643  * This can be used by containers that base their paint volume on
14644  * the volume of their children. Such containers can query the
14645  * transformed paint volume of all of its children and union them
14646  * together using clutter_paint_volume_union().
14647  *
14648  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
14649  *   or %NULL if no volume could be determined. The returned pointer is
14650  *   not guaranteed to be valid across multiple frames; if you wish to
14651  *   keep it, you will have to copy it using clutter_paint_volume_copy().
14652  *
14653  * Since: 1.6
14654  */
14655 const ClutterPaintVolume *
14656 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
14657                                             ClutterActor *relative_to_ancestor)
14658 {
14659   const ClutterPaintVolume *volume;
14660   ClutterActor *stage;
14661   ClutterPaintVolume *transformed_volume;
14662
14663   stage = _clutter_actor_get_stage_internal (self);
14664   if (G_UNLIKELY (stage == NULL))
14665     return NULL;
14666
14667   if (relative_to_ancestor == NULL)
14668     relative_to_ancestor = stage;
14669
14670   volume = clutter_actor_get_paint_volume (self);
14671   if (volume == NULL)
14672     return NULL;
14673
14674   transformed_volume =
14675     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
14676
14677   _clutter_paint_volume_copy_static (volume, transformed_volume);
14678
14679   _clutter_paint_volume_transform_relative (transformed_volume,
14680                                             relative_to_ancestor);
14681
14682   return transformed_volume;
14683 }
14684
14685 /**
14686  * clutter_actor_get_paint_box:
14687  * @self: a #ClutterActor
14688  * @box: (out): return location for a #ClutterActorBox
14689  *
14690  * Retrieves the paint volume of the passed #ClutterActor, and
14691  * transforms it into a 2D bounding box in stage coordinates.
14692  *
14693  * This function is useful to determine the on screen area occupied by
14694  * the actor. The box is only an approximation and may often be
14695  * considerably larger due to the optimizations used to calculate the
14696  * box. The box is never smaller though, so it can reliably be used
14697  * for culling.
14698  *
14699  * There are times when a 2D paint box can't be determined, e.g.
14700  * because the actor isn't yet parented under a stage or because
14701  * the actor is unable to determine a paint volume.
14702  *
14703  * Return value: %TRUE if a 2D paint box could be determined, else
14704  * %FALSE.
14705  *
14706  * Since: 1.6
14707  */
14708 gboolean
14709 clutter_actor_get_paint_box (ClutterActor    *self,
14710                              ClutterActorBox *box)
14711 {
14712   ClutterActor *stage;
14713   ClutterPaintVolume *pv;
14714
14715   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14716   g_return_val_if_fail (box != NULL, FALSE);
14717
14718   stage = _clutter_actor_get_stage_internal (self);
14719   if (G_UNLIKELY (!stage))
14720     return FALSE;
14721
14722   pv = _clutter_actor_get_paint_volume_mutable (self);
14723   if (G_UNLIKELY (!pv))
14724     return FALSE;
14725
14726   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
14727
14728   return TRUE;
14729 }
14730
14731 /**
14732  * clutter_actor_has_overlaps:
14733  * @self: A #ClutterActor
14734  *
14735  * Asks the actor's implementation whether it may contain overlapping
14736  * primitives.
14737  *
14738  * For example; Clutter may use this to determine whether the painting
14739  * should be redirected to an offscreen buffer to correctly implement
14740  * the opacity property.
14741  *
14742  * Custom actors can override the default response by implementing the
14743  * #ClutterActor <function>has_overlaps</function> virtual function. See
14744  * clutter_actor_set_offscreen_redirect() for more information.
14745  *
14746  * Return value: %TRUE if the actor may have overlapping primitives, and
14747  *   %FALSE otherwise
14748  *
14749  * Since: 1.8
14750  */
14751 gboolean
14752 clutter_actor_has_overlaps (ClutterActor *self)
14753 {
14754   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14755
14756   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
14757 }
14758
14759 /**
14760  * clutter_actor_has_effects:
14761  * @self: A #ClutterActor
14762  *
14763  * Returns whether the actor has any effects applied.
14764  *
14765  * Return value: %TRUE if the actor has any effects,
14766  *   %FALSE otherwise
14767  *
14768  * Since: 1.10
14769  */
14770 gboolean
14771 clutter_actor_has_effects (ClutterActor *self)
14772 {
14773   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14774
14775   if (self->priv->effects == NULL)
14776     return FALSE;
14777
14778   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
14779 }
14780
14781 /**
14782  * clutter_actor_has_constraints:
14783  * @self: A #ClutterActor
14784  *
14785  * Returns whether the actor has any constraints applied.
14786  *
14787  * Return value: %TRUE if the actor has any constraints,
14788  *   %FALSE otherwise
14789  *
14790  * Since: 1.10
14791  */
14792 gboolean
14793 clutter_actor_has_constraints (ClutterActor *self)
14794 {
14795   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14796
14797   return self->priv->constraints != NULL;
14798 }
14799
14800 /**
14801  * clutter_actor_has_actions:
14802  * @self: A #ClutterActor
14803  *
14804  * Returns whether the actor has any actions applied.
14805  *
14806  * Return value: %TRUE if the actor has any actions,
14807  *   %FALSE otherwise
14808  *
14809  * Since: 1.10
14810  */
14811 gboolean
14812 clutter_actor_has_actions (ClutterActor *self)
14813 {
14814   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14815
14816   return self->priv->actions != NULL;
14817 }
14818
14819 /**
14820  * clutter_actor_get_n_children:
14821  * @self: a #ClutterActor
14822  *
14823  * Retrieves the number of children of @self.
14824  *
14825  * Return value: the number of children of an actor
14826  *
14827  * Since: 1.10
14828  */
14829 gint
14830 clutter_actor_get_n_children (ClutterActor *self)
14831 {
14832   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14833
14834   return self->priv->n_children;
14835 }
14836
14837 /**
14838  * clutter_actor_get_child_at_index:
14839  * @self: a #ClutterActor
14840  * @index_: the position in the list of children
14841  *
14842  * Retrieves the actor at the given @index_ inside the list of
14843  * children of @self.
14844  *
14845  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
14846  *
14847  * Since: 1.10
14848  */
14849 ClutterActor *
14850 clutter_actor_get_child_at_index (ClutterActor *self,
14851                                   gint          index_)
14852 {
14853   ClutterActor *iter;
14854   int i;
14855
14856   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14857   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
14858
14859   for (iter = self->priv->first_child, i = 0;
14860        iter != NULL && i < index_;
14861        iter = iter->priv->next_sibling, i += 1)
14862     ;
14863
14864   return iter;
14865 }
14866
14867 /*< private >
14868  * _clutter_actor_foreach_child:
14869  * @actor: The actor whos children you want to iterate
14870  * @callback: The function to call for each child
14871  * @user_data: Private data to pass to @callback
14872  *
14873  * Calls a given @callback once for each child of the specified @actor and
14874  * passing the @user_data pointer each time.
14875  *
14876  * Return value: returns %TRUE if all children were iterated, else
14877  *    %FALSE if a callback broke out of iteration early.
14878  */
14879 gboolean
14880 _clutter_actor_foreach_child (ClutterActor           *self,
14881                               ClutterForeachCallback  callback,
14882                               gpointer                user_data)
14883 {
14884   ClutterActorPrivate *priv = self->priv;
14885   ClutterActor *iter;
14886   gboolean cont;
14887
14888   for (cont = TRUE, iter = priv->first_child;
14889        cont && iter != NULL;
14890        iter = iter->priv->next_sibling)
14891     {
14892       cont = callback (iter, user_data);
14893     }
14894
14895   return cont;
14896 }
14897
14898 #if 0
14899 /* For debugging purposes this gives us a simple way to print out
14900  * the scenegraph e.g in gdb using:
14901  * [|
14902  *   _clutter_actor_traverse (stage,
14903  *                            0,
14904  *                            clutter_debug_print_actor_cb,
14905  *                            NULL,
14906  *                            NULL);
14907  * |]
14908  */
14909 static ClutterActorTraverseVisitFlags
14910 clutter_debug_print_actor_cb (ClutterActor *actor,
14911                               int depth,
14912                               void *user_data)
14913 {
14914   g_print ("%*s%s:%p\n",
14915            depth * 2, "",
14916            _clutter_actor_get_debug_name (actor),
14917            actor);
14918
14919   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14920 }
14921 #endif
14922
14923 static void
14924 _clutter_actor_traverse_breadth (ClutterActor           *actor,
14925                                  ClutterTraverseCallback callback,
14926                                  gpointer                user_data)
14927 {
14928   GQueue *queue = g_queue_new ();
14929   ClutterActor dummy;
14930   int current_depth = 0;
14931
14932   g_queue_push_tail (queue, actor);
14933   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
14934
14935   while ((actor = g_queue_pop_head (queue)))
14936     {
14937       ClutterActorTraverseVisitFlags flags;
14938
14939       if (actor == &dummy)
14940         {
14941           current_depth++;
14942           g_queue_push_tail (queue, &dummy);
14943           continue;
14944         }
14945
14946       flags = callback (actor, current_depth, user_data);
14947       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14948         break;
14949       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14950         {
14951           ClutterActor *iter;
14952
14953           for (iter = actor->priv->first_child;
14954                iter != NULL;
14955                iter = iter->priv->next_sibling)
14956             {
14957               g_queue_push_tail (queue, iter);
14958             }
14959         }
14960     }
14961
14962   g_queue_free (queue);
14963 }
14964
14965 static ClutterActorTraverseVisitFlags
14966 _clutter_actor_traverse_depth (ClutterActor           *actor,
14967                                ClutterTraverseCallback before_children_callback,
14968                                ClutterTraverseCallback after_children_callback,
14969                                int                     current_depth,
14970                                gpointer                user_data)
14971 {
14972   ClutterActorTraverseVisitFlags flags;
14973
14974   flags = before_children_callback (actor, current_depth, user_data);
14975   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14976     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14977
14978   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14979     {
14980       ClutterActor *iter;
14981
14982       for (iter = actor->priv->first_child;
14983            iter != NULL;
14984            iter = iter->priv->next_sibling)
14985         {
14986           flags = _clutter_actor_traverse_depth (iter,
14987                                                  before_children_callback,
14988                                                  after_children_callback,
14989                                                  current_depth + 1,
14990                                                  user_data);
14991
14992           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14993             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14994         }
14995     }
14996
14997   if (after_children_callback)
14998     return after_children_callback (actor, current_depth, user_data);
14999   else
15000     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15001 }
15002
15003 /* _clutter_actor_traverse:
15004  * @actor: The actor to start traversing the graph from
15005  * @flags: These flags may affect how the traversal is done
15006  * @before_children_callback: A function to call before visiting the
15007  *   children of the current actor.
15008  * @after_children_callback: A function to call after visiting the
15009  *   children of the current actor. (Ignored if
15010  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15011  * @user_data: The private data to pass to the callbacks
15012  *
15013  * Traverses the scenegraph starting at the specified @actor and
15014  * descending through all its children and its children's children.
15015  * For each actor traversed @before_children_callback and
15016  * @after_children_callback are called with the specified
15017  * @user_data, before and after visiting that actor's children.
15018  *
15019  * The callbacks can return flags that affect the ongoing traversal
15020  * such as by skipping over an actors children or bailing out of
15021  * any further traversing.
15022  */
15023 void
15024 _clutter_actor_traverse (ClutterActor              *actor,
15025                          ClutterActorTraverseFlags  flags,
15026                          ClutterTraverseCallback    before_children_callback,
15027                          ClutterTraverseCallback    after_children_callback,
15028                          gpointer                   user_data)
15029 {
15030   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15031     _clutter_actor_traverse_breadth (actor,
15032                                      before_children_callback,
15033                                      user_data);
15034   else /* DEPTH_FIRST */
15035     _clutter_actor_traverse_depth (actor,
15036                                    before_children_callback,
15037                                    after_children_callback,
15038                                    0, /* start depth */
15039                                    user_data);
15040 }
15041
15042 static void
15043 on_layout_manager_changed (ClutterLayoutManager *manager,
15044                            ClutterActor         *self)
15045 {
15046   clutter_actor_queue_relayout (self);
15047 }
15048
15049 /**
15050  * clutter_actor_set_layout_manager:
15051  * @self: a #ClutterActor
15052  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15053  *
15054  * Sets the #ClutterLayoutManager delegate object that will be used to
15055  * lay out the children of @self.
15056  *
15057  * The #ClutterActor will take a reference on the passed @manager which
15058  * will be released either when the layout manager is removed, or when
15059  * the actor is destroyed.
15060  *
15061  * Since: 1.10
15062  */
15063 void
15064 clutter_actor_set_layout_manager (ClutterActor         *self,
15065                                   ClutterLayoutManager *manager)
15066 {
15067   ClutterActorPrivate *priv;
15068
15069   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15070   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15071
15072   priv = self->priv;
15073
15074   if (priv->layout_manager != NULL)
15075     {
15076       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15077                                             G_CALLBACK (on_layout_manager_changed),
15078                                             self);
15079       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15080       g_object_unref (priv->layout_manager);
15081     }
15082
15083   priv->layout_manager = manager;
15084
15085   if (priv->layout_manager != NULL)
15086     {
15087       g_object_ref_sink (priv->layout_manager);
15088       clutter_layout_manager_set_container (priv->layout_manager,
15089                                             CLUTTER_CONTAINER (self));
15090       g_signal_connect (priv->layout_manager, "layout-changed",
15091                         G_CALLBACK (on_layout_manager_changed),
15092                         self);
15093     }
15094
15095   clutter_actor_queue_relayout (self);
15096
15097   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15098 }
15099
15100 /**
15101  * clutter_actor_get_layout_manager:
15102  * @self: a #ClutterActor
15103  *
15104  * Retrieves the #ClutterLayoutManager used by @self.
15105  *
15106  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15107  *   or %NULL
15108  *
15109  * Since: 1.10
15110  */
15111 ClutterLayoutManager *
15112 clutter_actor_get_layout_manager (ClutterActor *self)
15113 {
15114   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15115
15116   return self->priv->layout_manager;
15117 }
15118
15119 static const ClutterLayoutInfo default_layout_info = {
15120   0.f,                          /* fixed-x */
15121   0.f,                          /* fixed-y */
15122   { 0, 0, 0, 0 },               /* margin */
15123   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15124   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15125   0.f, 0.f,                     /* min_width, natural_width */
15126   0.f, 0.f,                     /* natual_width, natural_height */
15127 };
15128
15129 static void
15130 layout_info_free (gpointer data)
15131 {
15132   if (G_LIKELY (data != NULL))
15133     g_slice_free (ClutterLayoutInfo, data);
15134 }
15135
15136 /*< private >
15137  * _clutter_actor_get_layout_info:
15138  * @self: a #ClutterActor
15139  *
15140  * Retrieves a pointer to the ClutterLayoutInfo structure.
15141  *
15142  * If the actor does not have a ClutterLayoutInfo associated to it, one
15143  * will be created and initialized to the default values.
15144  *
15145  * This function should be used for setters.
15146  *
15147  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15148  * instead.
15149  *
15150  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15151  */
15152 ClutterLayoutInfo *
15153 _clutter_actor_get_layout_info (ClutterActor *self)
15154 {
15155   ClutterLayoutInfo *retval;
15156
15157   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15158   if (retval == NULL)
15159     {
15160       retval = g_slice_new (ClutterLayoutInfo);
15161
15162       *retval = default_layout_info;
15163
15164       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15165                                retval,
15166                                layout_info_free);
15167     }
15168
15169   return retval;
15170 }
15171
15172 /*< private >
15173  * _clutter_actor_get_layout_info_or_defaults:
15174  * @self: a #ClutterActor
15175  *
15176  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15177  *
15178  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15179  * then the default structure will be returned.
15180  *
15181  * This function should only be used for getters.
15182  *
15183  * Return value: a const pointer to the ClutterLayoutInfo structure
15184  */
15185 const ClutterLayoutInfo *
15186 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15187 {
15188   const ClutterLayoutInfo *info;
15189
15190   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15191   if (info == NULL)
15192     return &default_layout_info;
15193
15194   return info;
15195 }
15196
15197 /**
15198  * clutter_actor_set_x_align:
15199  * @self: a #ClutterActor
15200  * @x_align: the horizontal alignment policy
15201  *
15202  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15203  * actor received extra horizontal space.
15204  *
15205  * See also the #ClutterActor:x-align property.
15206  *
15207  * Since: 1.10
15208  */
15209 void
15210 clutter_actor_set_x_align (ClutterActor      *self,
15211                            ClutterActorAlign  x_align)
15212 {
15213   ClutterLayoutInfo *info;
15214
15215   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15216
15217   info = _clutter_actor_get_layout_info (self);
15218
15219   if (info->x_align != x_align)
15220     {
15221       info->x_align = x_align;
15222
15223       clutter_actor_queue_relayout (self);
15224
15225       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15226     }
15227 }
15228
15229 /**
15230  * clutter_actor_get_x_align:
15231  * @self: a #ClutterActor
15232  *
15233  * Retrieves the horizontal alignment policy set using
15234  * clutter_actor_set_x_align().
15235  *
15236  * Return value: the horizontal alignment policy.
15237  *
15238  * Since: 1.10
15239  */
15240 ClutterActorAlign
15241 clutter_actor_get_x_align (ClutterActor *self)
15242 {
15243   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15244
15245   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15246 }
15247
15248 /**
15249  * clutter_actor_set_y_align:
15250  * @self: a #ClutterActor
15251  * @y_align: the vertical alignment policy
15252  *
15253  * Sets the vertical alignment policy of a #ClutterActor, in case the
15254  * actor received extra vertical space.
15255  *
15256  * See also the #ClutterActor:y-align property.
15257  *
15258  * Since: 1.10
15259  */
15260 void
15261 clutter_actor_set_y_align (ClutterActor      *self,
15262                            ClutterActorAlign  y_align)
15263 {
15264   ClutterLayoutInfo *info;
15265
15266   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15267
15268   info = _clutter_actor_get_layout_info (self);
15269
15270   if (info->y_align != y_align)
15271     {
15272       info->y_align = y_align;
15273
15274       clutter_actor_queue_relayout (self);
15275
15276       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15277     }
15278 }
15279
15280 /**
15281  * clutter_actor_get_y_align:
15282  * @self: a #ClutterActor
15283  *
15284  * Retrieves the vertical alignment policy set using
15285  * clutter_actor_set_y_align().
15286  *
15287  * Return value: the vertical alignment policy.
15288  *
15289  * Since: 1.10
15290  */
15291 ClutterActorAlign
15292 clutter_actor_get_y_align (ClutterActor *self)
15293 {
15294   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15295
15296   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15297 }
15298
15299
15300 /**
15301  * clutter_margin_new:
15302  *
15303  * Creates a new #ClutterMargin.
15304  *
15305  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15306  *   clutter_margin_free() to free the resources associated with it when
15307  *   done.
15308  *
15309  * Since: 1.10
15310  */
15311 ClutterMargin *
15312 clutter_margin_new (void)
15313 {
15314   return g_slice_new0 (ClutterMargin);
15315 }
15316
15317 /**
15318  * clutter_margin_copy:
15319  * @margin_: a #ClutterMargin
15320  *
15321  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15322  * the newly created structure.
15323  *
15324  * Return value: (transfer full): a copy of the #ClutterMargin.
15325  *
15326  * Since: 1.10
15327  */
15328 ClutterMargin *
15329 clutter_margin_copy (const ClutterMargin *margin_)
15330 {
15331   if (G_LIKELY (margin_ != NULL))
15332     return g_slice_dup (ClutterMargin, margin_);
15333
15334   return NULL;
15335 }
15336
15337 /**
15338  * clutter_margin_free:
15339  * @margin_: a #ClutterMargin
15340  *
15341  * Frees the resources allocated by clutter_margin_new() and
15342  * clutter_margin_copy().
15343  *
15344  * Since: 1.10
15345  */
15346 void
15347 clutter_margin_free (ClutterMargin *margin_)
15348 {
15349   if (G_LIKELY (margin_ != NULL))
15350     g_slice_free (ClutterMargin, margin_);
15351 }
15352
15353 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15354                      clutter_margin_copy,
15355                      clutter_margin_free)
15356
15357 /**
15358  * clutter_actor_set_margin:
15359  * @self: a #ClutterActor
15360  * @margin: a #ClutterMargin
15361  *
15362  * Sets all the components of the margin of a #ClutterActor.
15363  *
15364  * Since: 1.10
15365  */
15366 void
15367 clutter_actor_set_margin (ClutterActor        *self,
15368                           const ClutterMargin *margin)
15369 {
15370   ClutterLayoutInfo *info;
15371   gboolean changed;
15372   GObject *obj;
15373
15374   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15375   g_return_if_fail (margin != NULL);
15376
15377   obj = G_OBJECT (self);
15378   changed = FALSE;
15379
15380   g_object_freeze_notify (obj);
15381
15382   info = _clutter_actor_get_layout_info (self);
15383
15384   if (info->margin.top != margin->top)
15385     {
15386       info->margin.top = margin->top;
15387       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15388       changed = TRUE;
15389     }
15390
15391   if (info->margin.right != margin->right)
15392     {
15393       info->margin.right = margin->right;
15394       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15395       changed = TRUE;
15396     }
15397
15398   if (info->margin.bottom != margin->bottom)
15399     {
15400       info->margin.bottom = margin->bottom;
15401       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15402       changed = TRUE;
15403     }
15404
15405   if (info->margin.left != margin->left)
15406     {
15407       info->margin.left = margin->left;
15408       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15409       changed = TRUE;
15410     }
15411
15412   if (changed)
15413     clutter_actor_queue_relayout (self);
15414
15415   g_object_thaw_notify (obj);
15416 }
15417
15418 /**
15419  * clutter_actor_get_margin:
15420  * @self: a #ClutterActor
15421  * @margin: (out caller-allocates): return location for a #ClutterMargin
15422  *
15423  * Retrieves all the components of the margin of a #ClutterActor.
15424  *
15425  * Since: 1.10
15426  */
15427 void
15428 clutter_actor_get_margin (ClutterActor  *self,
15429                           ClutterMargin *margin)
15430 {
15431   const ClutterLayoutInfo *info;
15432
15433   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15434   g_return_if_fail (margin != NULL);
15435
15436   info = _clutter_actor_get_layout_info_or_defaults (self);
15437
15438   *margin = info->margin;
15439 }
15440
15441 /**
15442  * clutter_actor_set_margin_top:
15443  * @self: a #ClutterActor
15444  * @margin: the top margin
15445  *
15446  * Sets the margin from the top of a #ClutterActor.
15447  *
15448  * Since: 1.10
15449  */
15450 void
15451 clutter_actor_set_margin_top (ClutterActor *self,
15452                               gfloat        margin)
15453 {
15454   ClutterLayoutInfo *info;
15455
15456   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15457   g_return_if_fail (margin >= 0.f);
15458
15459   info = _clutter_actor_get_layout_info (self);
15460
15461   if (info->margin.top == margin)
15462     return;
15463
15464   info->margin.top = margin;
15465
15466   clutter_actor_queue_relayout (self);
15467
15468   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15469 }
15470
15471 /**
15472  * clutter_actor_get_margin_top:
15473  * @self: a #ClutterActor
15474  *
15475  * Retrieves the top margin of a #ClutterActor.
15476  *
15477  * Return value: the top margin
15478  *
15479  * Since: 1.10
15480  */
15481 gfloat
15482 clutter_actor_get_margin_top (ClutterActor *self)
15483 {
15484   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15485
15486   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15487 }
15488
15489 /**
15490  * clutter_actor_set_margin_bottom:
15491  * @self: a #ClutterActor
15492  * @margin: the bottom margin
15493  *
15494  * Sets the margin from the bottom of a #ClutterActor.
15495  *
15496  * Since: 1.10
15497  */
15498 void
15499 clutter_actor_set_margin_bottom (ClutterActor *self,
15500                                  gfloat        margin)
15501 {
15502   ClutterLayoutInfo *info;
15503
15504   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15505   g_return_if_fail (margin >= 0.f);
15506
15507   info = _clutter_actor_get_layout_info (self);
15508
15509   if (info->margin.bottom == margin)
15510     return;
15511
15512   info->margin.bottom = margin;
15513
15514   clutter_actor_queue_relayout (self);
15515
15516   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
15517 }
15518
15519 /**
15520  * clutter_actor_get_margin_bottom:
15521  * @self: a #ClutterActor
15522  *
15523  * Retrieves the bottom margin of a #ClutterActor.
15524  *
15525  * Return value: the bottom margin
15526  *
15527  * Since: 1.10
15528  */
15529 gfloat
15530 clutter_actor_get_margin_bottom (ClutterActor *self)
15531 {
15532   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15533
15534   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
15535 }
15536
15537 /**
15538  * clutter_actor_set_margin_left:
15539  * @self: a #ClutterActor
15540  * @margin: the left margin
15541  *
15542  * Sets the margin from the left of a #ClutterActor.
15543  *
15544  * Since: 1.10
15545  */
15546 void
15547 clutter_actor_set_margin_left (ClutterActor *self,
15548                                gfloat        margin)
15549 {
15550   ClutterLayoutInfo *info;
15551
15552   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15553   g_return_if_fail (margin >= 0.f);
15554
15555   info = _clutter_actor_get_layout_info (self);
15556
15557   if (info->margin.left == margin)
15558     return;
15559
15560   info->margin.left = margin;
15561
15562   clutter_actor_queue_relayout (self);
15563
15564   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
15565 }
15566
15567 /**
15568  * clutter_actor_get_margin_left:
15569  * @self: a #ClutterActor
15570  *
15571  * Retrieves the left margin of a #ClutterActor.
15572  *
15573  * Return value: the left margin
15574  *
15575  * Since: 1.10
15576  */
15577 gfloat
15578 clutter_actor_get_margin_left (ClutterActor *self)
15579 {
15580   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15581
15582   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
15583 }
15584
15585 /**
15586  * clutter_actor_set_margin_right:
15587  * @self: a #ClutterActor
15588  * @margin: the right margin
15589  *
15590  * Sets the margin from the right of a #ClutterActor.
15591  *
15592  * Since: 1.10
15593  */
15594 void
15595 clutter_actor_set_margin_right (ClutterActor *self,
15596                                 gfloat        margin)
15597 {
15598   ClutterLayoutInfo *info;
15599
15600   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15601   g_return_if_fail (margin >= 0.f);
15602
15603   info = _clutter_actor_get_layout_info (self);
15604
15605   if (info->margin.right == margin)
15606     return;
15607
15608   info->margin.right = margin;
15609
15610   clutter_actor_queue_relayout (self);
15611
15612   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
15613 }
15614
15615 /**
15616  * clutter_actor_get_margin_right:
15617  * @self: a #ClutterActor
15618  *
15619  * Retrieves the right margin of a #ClutterActor.
15620  *
15621  * Return value: the right margin
15622  *
15623  * Since: 1.10
15624  */
15625 gfloat
15626 clutter_actor_get_margin_right (ClutterActor *self)
15627 {
15628   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15629
15630   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
15631 }
15632
15633 /**
15634  * clutter_actor_set_background_color:
15635  * @self: a #ClutterActor
15636  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
15637  *  set color
15638  *
15639  * Sets the background color of a #ClutterActor.
15640  *
15641  * The background color will be used to cover the whole allocation of the
15642  * actor. The default background color of an actor is transparent.
15643  *
15644  * To check whether an actor has a background color, you can use the
15645  * #ClutterActor:background-color-set actor property.
15646  *
15647  * Since: 1.10
15648  */
15649 void
15650 clutter_actor_set_background_color (ClutterActor       *self,
15651                                     const ClutterColor *color)
15652 {
15653   ClutterActorPrivate *priv;
15654
15655   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15656
15657   priv = self->priv;
15658
15659   if (color == NULL)
15660     {
15661       priv->bg_color_set = FALSE;
15662       g_object_notify_by_pspec (G_OBJECT (self),
15663                                 obj_props[PROP_BACKGROUND_COLOR_SET]);
15664       return;
15665     }
15666
15667   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
15668     return;
15669
15670   priv->bg_color = *color;
15671   priv->bg_color_set = TRUE;
15672
15673   clutter_actor_queue_redraw (self);
15674
15675   g_object_notify_by_pspec (G_OBJECT (self),
15676                             obj_props[PROP_BACKGROUND_COLOR_SET]);
15677   g_object_notify_by_pspec (G_OBJECT (self),
15678                             obj_props[PROP_BACKGROUND_COLOR]);
15679 }
15680
15681 /**
15682  * clutter_actor_get_background_color:
15683  * @self: a #ClutterActor
15684  * @color: (out caller-allocates): return location for a #ClutterColor
15685  *
15686  * Retrieves the color set using clutter_actor_set_background_color().
15687  *
15688  * Since: 1.10
15689  */
15690 void
15691 clutter_actor_get_background_color (ClutterActor *self,
15692                                     ClutterColor *color)
15693 {
15694   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15695   g_return_if_fail (color != NULL);
15696
15697   *color = self->priv->bg_color;
15698 }
15699
15700 /**
15701  * clutter_actor_get_previous_sibling:
15702  * @self: a #ClutterActor
15703  *
15704  * Retrieves the sibling of @self that comes before it in the list
15705  * of children of @self's parent.
15706  *
15707  * The returned pointer is only valid until the scene graph changes; it
15708  * is not safe to modify the list of children of @self while iterating
15709  * it.
15710  *
15711  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15712  *
15713  * Since: 1.10
15714  */
15715 ClutterActor *
15716 clutter_actor_get_previous_sibling (ClutterActor *self)
15717 {
15718   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15719
15720   return self->priv->prev_sibling;
15721 }
15722
15723 /**
15724  * clutter_actor_get_next_sibling:
15725  * @self: a #ClutterActor
15726  *
15727  * Retrieves the sibling of @self that comes after it in the list
15728  * of children of @self's parent.
15729  *
15730  * The returned pointer is only valid until the scene graph changes; it
15731  * is not safe to modify the list of children of @self while iterating
15732  * it.
15733  *
15734  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15735  *
15736  * Since: 1.10
15737  */
15738 ClutterActor *
15739 clutter_actor_get_next_sibling (ClutterActor *self)
15740 {
15741   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15742
15743   return self->priv->next_sibling;
15744 }
15745
15746 /**
15747  * clutter_actor_get_first_child:
15748  * @self: a #ClutterActor
15749  *
15750  * Retrieves the first child of @self.
15751  *
15752  * The returned pointer is only valid until the scene graph changes; it
15753  * is not safe to modify the list of children of @self while iterating
15754  * it.
15755  *
15756  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15757  *
15758  * Since: 1.10
15759  */
15760 ClutterActor *
15761 clutter_actor_get_first_child (ClutterActor *self)
15762 {
15763   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15764
15765   return self->priv->first_child;
15766 }
15767
15768 /**
15769  * clutter_actor_get_last_child:
15770  * @self: a #ClutterActor
15771  *
15772  * Retrieves the last child of @self.
15773  *
15774  * The returned pointer is only valid until the scene graph changes; it
15775  * is not safe to modify the list of children of @self while iterating
15776  * it.
15777  *
15778  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15779  *
15780  * Since: 1.10
15781  */
15782 ClutterActor *
15783 clutter_actor_get_last_child (ClutterActor *self)
15784 {
15785   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15786
15787   return self->priv->last_child;
15788 }
15789
15790 /* easy way to have properly named fields instead of the dummy ones
15791  * we use in the public structure
15792  */
15793 typedef struct _RealActorIter
15794 {
15795   ClutterActor *root;           /* dummy1 */
15796   ClutterActor *current;        /* dummy2 */
15797   gpointer padding_1;           /* dummy3 */
15798   gint age;                     /* dummy4 */
15799   gpointer padding_2;           /* dummy5 */
15800 } RealActorIter;
15801
15802 /**
15803  * clutter_actor_iter_init:
15804  * @iter: a #ClutterActorIter
15805  * @root: a #ClutterActor
15806  *
15807  * Initializes a #ClutterActorIter, which can then be used to iterate
15808  * efficiently over a section of the scene graph, and associates it
15809  * with @root.
15810  *
15811  * Modifying the scene graph section that contains @root will invalidate
15812  * the iterator.
15813  *
15814  * |[
15815  *   ClutterActorIter iter;
15816  *   ClutterActor *child;
15817  *
15818  *   clutter_actor_iter_init (&iter, container);
15819  *   while (clutter_actor_iter_next (&iter, &child))
15820  *     {
15821  *       /&ast; do something with child &ast;/
15822  *     }
15823  * ]|
15824  *
15825  * Since: 1.10
15826  */
15827 void
15828 clutter_actor_iter_init (ClutterActorIter *iter,
15829                          ClutterActor     *root)
15830 {
15831   RealActorIter *ri = (RealActorIter *) iter;
15832
15833   g_return_if_fail (iter != NULL);
15834   g_return_if_fail (CLUTTER_IS_ACTOR (root));
15835
15836   ri->root = root;
15837   ri->current = NULL;
15838   ri->age = root->priv->age;
15839 }
15840
15841 /**
15842  * clutter_actor_iter_next:
15843  * @iter: a #ClutterActorIter
15844  * @child: (out): return location for a #ClutterActor
15845  *
15846  * Advances the @iter and retrieves the next child of the root #ClutterActor
15847  * that was used to initialize the #ClutterActorIterator.
15848  *
15849  * If the iterator can advance, this function returns %TRUE and sets the
15850  * @child argument.
15851  *
15852  * If the iterator cannot advance, this function returns %FALSE, and
15853  * the contents of @child are undefined.
15854  *
15855  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15856  *
15857  * Since: 1.10
15858  */
15859 gboolean
15860 clutter_actor_iter_next (ClutterActorIter  *iter,
15861                          ClutterActor     **child)
15862 {
15863   RealActorIter *ri = (RealActorIter *) iter;
15864
15865   g_return_val_if_fail (iter != NULL, FALSE);
15866   g_return_val_if_fail (ri->root != NULL, FALSE);
15867 #ifndef G_DISABLE_ASSERT
15868   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15869 #endif
15870
15871   if (ri->current == NULL)
15872     ri->current = ri->root->priv->first_child;
15873   else
15874     ri->current = ri->current->priv->next_sibling;
15875
15876   if (child != NULL)
15877     *child = ri->current;
15878
15879   return ri->current != NULL;
15880 }
15881
15882 /**
15883  * clutter_actor_iter_prev:
15884  * @iter: a #ClutterActorIter
15885  * @child: (out): return location for a #ClutterActor
15886  *
15887  * Advances the @iter and retrieves the previous child of the root
15888  * #ClutterActor that was used to initialize the #ClutterActorIterator.
15889  *
15890  * If the iterator can advance, this function returns %TRUE and sets the
15891  * @child argument.
15892  *
15893  * If the iterator cannot advance, this function returns %FALSE, and
15894  * the contents of @child are undefined.
15895  *
15896  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15897  *
15898  * Since: 1.10
15899  */
15900 gboolean
15901 clutter_actor_iter_prev (ClutterActorIter  *iter,
15902                          ClutterActor     **child)
15903 {
15904   RealActorIter *ri = (RealActorIter *) iter;
15905
15906   g_return_val_if_fail (iter != NULL, FALSE);
15907   g_return_val_if_fail (ri->root != NULL, FALSE);
15908 #ifndef G_DISABLE_ASSERT
15909   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15910 #endif
15911
15912   if (ri->current == NULL)
15913     ri->current = ri->root->priv->last_child;
15914   else
15915     ri->current = ri->current->priv->prev_sibling;
15916
15917   if (child != NULL)
15918     *child = ri->current;
15919
15920   return ri->current != NULL;
15921 }
15922
15923 /**
15924  * clutter_actor_iter_remove:
15925  * @iter: a #ClutterActorIter
15926  *
15927  * Safely removes the #ClutterActor currently pointer to by the iterator
15928  * from its parent.
15929  *
15930  * This function can only be called after clutter_actor_iter_next() or
15931  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15932  * than once for the same actor.
15933  *
15934  * This function will call clutter_actor_remove_child() internally.
15935  *
15936  * Since: 1.10
15937  */
15938 void
15939 clutter_actor_iter_remove (ClutterActorIter *iter)
15940 {
15941   RealActorIter *ri = (RealActorIter *) iter;
15942   ClutterActor *cur;
15943
15944   g_return_if_fail (iter != NULL);
15945   g_return_if_fail (ri->root != NULL);
15946 #ifndef G_DISABLE_ASSERT
15947   g_return_if_fail (ri->age == ri->root->priv->age);
15948 #endif
15949   g_return_if_fail (ri->current != NULL);
15950
15951   cur = ri->current;
15952
15953   if (cur != NULL)
15954     {
15955       ri->current = cur->priv->prev_sibling;
15956
15957       clutter_actor_remove_child_internal (ri->root, cur,
15958                                            REMOVE_CHILD_DEFAULT_FLAGS);
15959
15960       ri->age += 1;
15961     }
15962 }
15963
15964 /**
15965  * clutter_actor_iter_destroy:
15966  * @iter: a #ClutterActorIter
15967  *
15968  * Safely destroys the #ClutterActor currently pointer to by the iterator
15969  * from its parent.
15970  *
15971  * This function can only be called after clutter_actor_iter_next() or
15972  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15973  * than once for the same actor.
15974  *
15975  * This function will call clutter_actor_destroy() internally.
15976  *
15977  * Since: 1.10
15978  */
15979 void
15980 clutter_actor_iter_destroy (ClutterActorIter *iter)
15981 {
15982   RealActorIter *ri = (RealActorIter *) iter;
15983   ClutterActor *cur;
15984
15985   g_return_if_fail (iter != NULL);
15986   g_return_if_fail (ri->root != NULL);
15987 #ifndef G_DISABLE_ASSERT
15988   g_return_if_fail (ri->age == ri->root->priv->age);
15989 #endif
15990   g_return_if_fail (ri->current != NULL);
15991
15992   cur = ri->current;
15993
15994   if (cur != NULL)
15995     {
15996       ri->current = cur->priv->prev_sibling;
15997
15998       clutter_actor_destroy (cur);
15999
16000       ri->age += 1;
16001     }
16002 }