Add deprecated header for ClutterAnimation
[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="bin-layout">
113  *     <title>Actors</title>
114  *     <graphic fileref="test-actor.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-events">
119  *   <title>Handling events on an actor</title>
120  *   <para>A #ClutterActor can receive and handle input device events, for
121  *   instance pointer events and key events, as long as its
122  *   #ClutterActor:reactive property is set to %TRUE.</para>
123  *   <para>Once an actor has been determined to be the source of an event,
124  *   Clutter will traverse the scene graph from the top-level actor towards the
125  *   event source, emitting the #ClutterActor::captured-event signal on each
126  *   ancestor until it reaches the source; this phase is also called
127  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
128  *   stopped, the graph is walked backwards, from the source actor to the
129  *   top-level, and the #ClutterActor::event signal, along with other event
130  *   signals if needed, is emitted; this phase is also called <emphasis>the
131  *   bubble phase</emphasis>. At any point of the signal emission, signal
132  *   handlers can stop the propagation through the scene graph by returning
133  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
134  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
135  * </refsect2>
136  *
137  * <refsect2 id="ClutterActor-subclassing">
138  *   <title>Implementing an actor</title>
139  *   <para>Careful consideration should be given when deciding to implement
140  *   a #ClutterActor sub-class. It is generally recommended to implement a
141  *   sub-class of #ClutterActor only for actors that should be used as leaf
142  *   nodes of a scene graph.</para>
143  *   <para>If your actor should be painted in a custom way, you should
144  *   override the #ClutterActor::paint signal class handler. You can either
145  *   opt to chain up to the parent class implementation or decide to fully
146  *   override the default paint implementation; Clutter will set up the
147  *   transformations and clip regions prior to emitting the #ClutterActor::paint
148  *   signal.</para>
149  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
150  *   #ClutterActorClass.get_preferred_height() virtual functions it is
151  *   possible to change or provide the preferred size of an actor; similarly,
152  *   by overriding the #ClutterActorClass.allocate() virtual function it is
153  *   possible to control the layout of the children of an actor. Make sure to
154  *   always chain up to the parent implementation of the
155  *   #ClutterActorClass.allocate() virtual function.</para>
156  *   <para>In general, it is strongly encouraged to use delegation and
157  *   composition instead of direct subclassing.</para>
158  * </refsect2>
159  *
160  * <refsect2 id="ClutterActor-script">
161  *   <title>ClutterActor custom properties for #ClutterScript</title>
162  *   <para>#ClutterActor defines a custom "rotation" property which
163  *   allows a short-hand description of the rotations to be applied
164  *   to an actor.</para>
165  *   <para>The syntax of the "rotation" property is the following:</para>
166  *   <informalexample>
167  *     <programlisting>
168  * "rotation" : [
169  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
170  * ]
171  *     </programlisting>
172  *   </informalexample>
173  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
174  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
175  *   floating point value representing the rotation angle on the given axis,
176  *   in degrees.</para>
177  *   <para>The <emphasis>center</emphasis> array is optional, and if present
178  *   it must contain the center of rotation as described by two coordinates:
179  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
180  *   "z-axis".</para>
181  *   <para>#ClutterActor will also parse every positional and dimensional
182  *   property defined as a string through clutter_units_from_string(); you
183  *   should read the documentation for the #ClutterUnits parser format for
184  *   the valid units and syntax.</para>
185  * </refsect2>
186  *
187  * <refsect2 id="ClutterActor-animating">
188  *   <title>Custom animatable properties</title>
189  *   <para>#ClutterActor allows accessing properties of #ClutterAction
190  *   and #ClutterConstraint instances associated to an actor instance
191  *   for animation purposes.</para>
192  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
193  *   property it is necessary to set the #ClutterActorMeta:name property on the
194  *   given action or constraint.</para>
195  *   <para>The property can be accessed using the following syntax:</para>
196  *   <informalexample>
197  *     <programlisting>
198  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
199  *     </programlisting>
200  *   </informalexample>
201  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
202  *   <para>The <emphasis>section</emphasis> fragment can be one between
203  *   "actions", "constraints" and "effects".</para>
204  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
205  *   action or constraint, as specified by the #ClutterActorMeta:name
206  *   property.</para>
207  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
208  *   action or constraint property to be animated.</para>
209  *   <para>The example below animates a #ClutterBindConstraint applied to an
210  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
211  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
212  *   its initial state is fully transparent and overlapping the actor to
213  *   which is bound to. </para>
214  *   <informalexample><programlisting>
215  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
216  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
217  * clutter_actor_add_constraint (rect, constraint);
218  *
219  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
220  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
221  * clutter_actor_add_constraint (rect, constraint);
222  *
223  * clutter_actor_set_reactive (rect, TRUE);
224  * clutter_actor_set_opacity (rect, 0);
225  *
226  * g_signal_connect (rect, "button-press-event",
227  *                   G_CALLBACK (on_button_press),
228  *                   NULL);
229  *   </programlisting></informalexample>
230  *   <para>On button press, the rectangle "slides" from behind the actor to
231  *   which is bound to, using the #ClutterBindConstraint:offset property and
232  *   the #ClutterActor:opacity property.</para>
233  *   <informalexample><programlisting>
234  * float new_offset = clutter_actor_get_width (origin) + h_padding;
235  *
236  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
237  *                        "opacity", 255,
238  *                        "@constraints.bind-x.offset", new_offset,
239  *                        NULL);
240  *   </programlisting></informalexample>
241  * </refsect2>
242  */
243
244 /**
245  * CLUTTER_ACTOR_IS_MAPPED:
246  * @a: a #ClutterActor
247  *
248  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
249  *
250  * The mapped state is set when the actor is visible and all its parents up
251  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
252  *
253  * This check can be used to see if an actor is going to be painted, as only
254  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
255  *
256  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
257  * not be checked directly; instead, the recommended usage is to connect a
258  * handler on the #GObject::notify signal for the #ClutterActor:mapped
259  * property of #ClutterActor, and check the presence of
260  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
261  *
262  * It is also important to note that Clutter may delay the changes of
263  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
264  * limitations, or during the reparenting of an actor, to optimize
265  * unnecessary (and potentially expensive) state changes.
266  *
267  * Since: 0.2
268  */
269
270 /**
271  * CLUTTER_ACTOR_IS_REALIZED:
272  * @a: a #ClutterActor
273  *
274  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
275  *
276  * The realized state has an actor-dependant interpretation. If an
277  * actor wants to delay allocating resources until it is attached to a
278  * stage, it may use the realize state to do so. However it is
279  * perfectly acceptable for an actor to allocate Cogl resources before
280  * being realized because there is only one drawing context used by Clutter
281  * so any resources will work on any stage.  If an actor is mapped it
282  * must also be realized, but an actor can be realized and unmapped
283  * (this is so hiding an actor temporarily doesn't do an expensive
284  * unrealize/realize).
285  *
286  * To be realized an actor must be inside a stage, and all its parents
287  * must be realized.
288  *
289  * Since: 0.2
290  */
291
292 /**
293  * CLUTTER_ACTOR_IS_VISIBLE:
294  * @a: a #ClutterActor
295  *
296  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
297  * Equivalent to the ClutterActor::visible object property.
298  *
299  * Note that an actor is only painted onscreen if it's mapped, which
300  * means it's visible, and all its parents are visible, and one of the
301  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
302  *
303  * Since: 0.2
304  */
305
306 /**
307  * CLUTTER_ACTOR_IS_REACTIVE:
308  * @a: a #ClutterActor
309  *
310  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
311  *
312  * Only reactive actors will receive event-related signals.
313  *
314  * Since: 0.6
315  */
316
317 #ifdef HAVE_CONFIG_H
318 #include "config.h"
319 #endif
320
321 #include <math.h>
322
323 #include "cogl/cogl.h"
324
325 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
326 #define CLUTTER_ENABLE_EXPERIMENTAL_API
327
328 #include "clutter-actor-private.h"
329
330 #include "clutter-action.h"
331 #include "clutter-actor-meta-private.h"
332 #include "clutter-animatable.h"
333 #include "clutter-color-static.h"
334 #include "clutter-color.h"
335 #include "clutter-constraint.h"
336 #include "clutter-container.h"
337 #include "clutter-debug.h"
338 #include "clutter-effect-private.h"
339 #include "clutter-enum-types.h"
340 #include "clutter-fixed-layout.h"
341 #include "clutter-flatten-effect.h"
342 #include "clutter-interval.h"
343 #include "clutter-main.h"
344 #include "clutter-marshal.h"
345 #include "clutter-paint-volume-private.h"
346 #include "clutter-private.h"
347 #include "clutter-profile.h"
348 #include "clutter-scriptable.h"
349 #include "clutter-script-private.h"
350 #include "clutter-stage-private.h"
351 #include "clutter-units.h"
352
353 #include "deprecated/clutter-behaviour.h"
354 #include "deprecated/clutter-container.h"
355
356 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
357 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
358
359 /* Internal enum used to control mapped state update.  This is a hint
360  * which indicates when to do something other than just enforce
361  * invariants.
362  */
363 typedef enum {
364   MAP_STATE_CHECK,           /* just enforce invariants. */
365   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
366                               * used when about to unparent.
367                               */
368   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
369                               * used to set mapped on toplevels.
370                               */
371   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
372                               * used just before unmapping parent.
373                               */
374 } MapStateChange;
375
376 /* 3 entries should be a good compromise, few layout managers
377  * will ask for 3 different preferred size in each allocation cycle */
378 #define N_CACHED_SIZE_REQUESTS 3
379
380 struct _ClutterActorPrivate
381 {
382   /* request mode */
383   ClutterRequestMode request_mode;
384
385   /* our cached size requests for different width / height */
386   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
387   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
388
389   /* An age of 0 means the entry is not set */
390   guint cached_height_age;
391   guint cached_width_age;
392
393   /* the bounding box of the actor, relative to the parent's
394    * allocation
395    */
396   ClutterActorBox allocation;
397   ClutterAllocationFlags allocation_flags;
398
399   /* depth */
400   gfloat z;
401
402   /* clip, in actor coordinates */
403   cairo_rectangle_t clip;
404
405   /* the cached transformation matrix; see apply_transform() */
406   CoglMatrix transform;
407
408   guint8 opacity;
409   gint opacity_override;
410
411   ClutterOffscreenRedirect offscreen_redirect;
412
413   /* This is an internal effect used to implement the
414      offscreen-redirect property */
415   ClutterEffect *flatten_effect;
416
417   /* scene graph */
418   ClutterActor *parent;
419   ClutterActor *prev_sibling;
420   ClutterActor *next_sibling;
421   ClutterActor *first_child;
422   ClutterActor *last_child;
423
424   gint n_children;
425
426   /* tracks whenever the children of an actor are changed; the
427    * age is incremented by 1 whenever an actor is added or
428    * removed. the age is not incremented when the first or the
429    * last child pointers are changed, or when grandchildren of
430    * an actor are changed.
431    */
432   gint age;
433
434   gchar *name; /* a non-unique name, used for debugging */
435   guint32 id; /* unique id, used for backward compatibility */
436
437   gint32 pick_id; /* per-stage unique id, used for picking */
438
439   /* a back-pointer to the Pango context that we can use
440    * to create pre-configured PangoLayout
441    */
442   PangoContext *pango_context;
443
444   /* the text direction configured for this child - either by
445    * application code, or by the actor's parent
446    */
447   ClutterTextDirection text_direction;
448
449   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
450   gint internal_child;
451
452   /* meta classes */
453   ClutterMetaGroup *actions;
454   ClutterMetaGroup *constraints;
455   ClutterMetaGroup *effects;
456
457   /* delegate object used to allocate the children of this actor */
458   ClutterLayoutManager *layout_manager;
459
460   /* used when painting, to update the paint volume */
461   ClutterEffect *current_effect;
462
463   /* This is used to store an effect which needs to be redrawn. A
464      redraw can be queued to start from a particular effect. This is
465      used by parametrised effects that can cache an image of the
466      actor. If a parameter of the effect changes then it only needs to
467      redraw the cached image, not the actual actor. The pointer is
468      only valid if is_dirty == TRUE. If the pointer is NULL then the
469      whole actor is dirty. */
470   ClutterEffect *effect_to_redraw;
471
472   /* This is used when painting effects to implement the
473      clutter_actor_continue_paint() function. It points to the node in
474      the list of effects that is next in the chain */
475   const GList *next_effect_to_paint;
476
477   ClutterPaintVolume paint_volume;
478
479   /* NB: This volume isn't relative to this actor, it is in eye
480    * coordinates so that it can remain valid after the actor changes.
481    */
482   ClutterPaintVolume last_paint_volume;
483
484   ClutterStageQueueRedrawEntry *queue_redraw_entry;
485
486   ClutterColor bg_color;
487
488   /* bitfields */
489
490   /* fixed position and sizes */
491   guint position_set                : 1;
492   guint min_width_set               : 1;
493   guint min_height_set              : 1;
494   guint natural_width_set           : 1;
495   guint natural_height_set          : 1;
496   /* cached request is invalid (implies allocation is too) */
497   guint needs_width_request         : 1;
498   /* cached request is invalid (implies allocation is too) */
499   guint needs_height_request        : 1;
500   /* cached allocation is invalid (request has changed, probably) */
501   guint needs_allocation            : 1;
502   guint show_on_set_parent          : 1;
503   guint has_clip                    : 1;
504   guint clip_to_allocation          : 1;
505   guint enable_model_view_transform : 1;
506   guint enable_paint_unmapped       : 1;
507   guint has_pointer                 : 1;
508   guint propagated_one_redraw       : 1;
509   guint paint_volume_valid          : 1;
510   guint last_paint_volume_valid     : 1;
511   guint in_clone_paint              : 1;
512   guint transform_valid             : 1;
513   /* This is TRUE if anything has queued a redraw since we were last
514      painted. In this case effect_to_redraw will point to an effect
515      the redraw was queued from or it will be NULL if the redraw was
516      queued without an effect. */
517   guint is_dirty                    : 1;
518   guint bg_color_set                : 1;
519 };
520
521 enum
522 {
523   PROP_0,
524
525   PROP_NAME,
526
527   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
528    * when set they force a size request, when gotten they
529    * get the allocation if the allocation is valid, and the
530    * request otherwise
531    */
532   PROP_X,
533   PROP_Y,
534   PROP_WIDTH,
535   PROP_HEIGHT,
536
537   /* Then the rest of these size-related properties are the "actual"
538    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
539    */
540   PROP_FIXED_X,
541   PROP_FIXED_Y,
542
543   PROP_FIXED_POSITION_SET,
544
545   PROP_MIN_WIDTH,
546   PROP_MIN_WIDTH_SET,
547
548   PROP_MIN_HEIGHT,
549   PROP_MIN_HEIGHT_SET,
550
551   PROP_NATURAL_WIDTH,
552   PROP_NATURAL_WIDTH_SET,
553
554   PROP_NATURAL_HEIGHT,
555   PROP_NATURAL_HEIGHT_SET,
556
557   PROP_REQUEST_MODE,
558
559   /* Allocation properties are read-only */
560   PROP_ALLOCATION,
561
562   PROP_DEPTH,
563
564   PROP_CLIP,
565   PROP_HAS_CLIP,
566   PROP_CLIP_TO_ALLOCATION,
567
568   PROP_OPACITY,
569
570   PROP_OFFSCREEN_REDIRECT,
571
572   PROP_VISIBLE,
573   PROP_MAPPED,
574   PROP_REALIZED,
575   PROP_REACTIVE,
576
577   PROP_SCALE_X,
578   PROP_SCALE_Y,
579   PROP_SCALE_CENTER_X,
580   PROP_SCALE_CENTER_Y,
581   PROP_SCALE_GRAVITY,
582
583   PROP_ROTATION_ANGLE_X,
584   PROP_ROTATION_ANGLE_Y,
585   PROP_ROTATION_ANGLE_Z,
586   PROP_ROTATION_CENTER_X,
587   PROP_ROTATION_CENTER_Y,
588   PROP_ROTATION_CENTER_Z,
589   /* This property only makes sense for the z rotation because the
590      others would depend on the actor having a size along the
591      z-axis */
592   PROP_ROTATION_CENTER_Z_GRAVITY,
593
594   PROP_ANCHOR_X,
595   PROP_ANCHOR_Y,
596   PROP_ANCHOR_GRAVITY,
597
598   PROP_SHOW_ON_SET_PARENT,
599
600   PROP_TEXT_DIRECTION,
601   PROP_HAS_POINTER,
602
603   PROP_ACTIONS,
604   PROP_CONSTRAINTS,
605   PROP_EFFECT,
606
607   PROP_LAYOUT_MANAGER,
608
609   PROP_X_ALIGN,
610   PROP_Y_ALIGN,
611   PROP_MARGIN_TOP,
612   PROP_MARGIN_BOTTOM,
613   PROP_MARGIN_LEFT,
614   PROP_MARGIN_RIGHT,
615
616   PROP_BACKGROUND_COLOR,
617   PROP_BACKGROUND_COLOR_SET,
618
619   PROP_FIRST_CHILD,
620   PROP_LAST_CHILD,
621
622   PROP_LAST
623 };
624
625 static GParamSpec *obj_props[PROP_LAST];
626
627 enum
628 {
629   SHOW,
630   HIDE,
631   DESTROY,
632   PARENT_SET,
633   KEY_FOCUS_IN,
634   KEY_FOCUS_OUT,
635   PAINT,
636   PICK,
637   REALIZE,
638   UNREALIZE,
639   QUEUE_REDRAW,
640   QUEUE_RELAYOUT,
641   EVENT,
642   CAPTURED_EVENT,
643   BUTTON_PRESS_EVENT,
644   BUTTON_RELEASE_EVENT,
645   SCROLL_EVENT,
646   KEY_PRESS_EVENT,
647   KEY_RELEASE_EVENT,
648   MOTION_EVENT,
649   ENTER_EVENT,
650   LEAVE_EVENT,
651   ALLOCATION_CHANGED,
652
653   LAST_SIGNAL
654 };
655
656 static guint actor_signals[LAST_SIGNAL] = { 0, };
657
658 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
659 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
660 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
661 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
662
663 /* These setters are all static for now, maybe they should be in the
664  * public API, but they are perhaps obscure enough to leave only as
665  * properties
666  */
667 static void clutter_actor_set_min_width          (ClutterActor *self,
668                                                   gfloat        min_width);
669 static void clutter_actor_set_min_height         (ClutterActor *self,
670                                                   gfloat        min_height);
671 static void clutter_actor_set_natural_width      (ClutterActor *self,
672                                                   gfloat        natural_width);
673 static void clutter_actor_set_natural_height     (ClutterActor *self,
674                                                   gfloat        natural_height);
675 static void clutter_actor_set_min_width_set      (ClutterActor *self,
676                                                   gboolean      use_min_width);
677 static void clutter_actor_set_min_height_set     (ClutterActor *self,
678                                                   gboolean      use_min_height);
679 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
680                                                   gboolean  use_natural_width);
681 static void clutter_actor_set_natural_height_set (ClutterActor *self,
682                                                   gboolean  use_natural_height);
683 static void clutter_actor_update_map_state       (ClutterActor  *self,
684                                                   MapStateChange change);
685 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
686
687 /* Helper routines for managing anchor coords */
688 static void clutter_anchor_coord_get_units (ClutterActor      *self,
689                                             const AnchorCoord *coord,
690                                             gfloat            *x,
691                                             gfloat            *y,
692                                             gfloat            *z);
693 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
694                                             gfloat             x,
695                                             gfloat             y,
696                                             gfloat             z);
697
698 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
699 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
700                                                         ClutterGravity     gravity);
701
702 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
703
704 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
705
706 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
707                                                                ClutterActor *ancestor,
708                                                                CoglMatrix *matrix);
709
710 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
711
712 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
713
714 static void on_layout_manager_changed (ClutterLayoutManager *manager,
715                                        ClutterActor         *self);
716
717 /* Helper macro which translates by the anchor coord, applies the
718    given transformation and then translates back */
719 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
720   gfloat _tx, _ty, _tz;                                                \
721   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
722   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
723   { _transform; }                                                      \
724   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
725
726 static GQuark quark_shader_data = 0;
727 static GQuark quark_actor_layout_info = 0;
728 static GQuark quark_actor_transform_info = 0;
729
730 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
731                          clutter_actor,
732                          G_TYPE_INITIALLY_UNOWNED,
733                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
734                                                 clutter_container_iface_init)
735                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
736                                                 clutter_scriptable_iface_init)
737                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
738                                                 clutter_animatable_iface_init)
739                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
740                                                 atk_implementor_iface_init));
741
742 /*< private >
743  * clutter_actor_get_debug_name:
744  * @actor: a #ClutterActor
745  *
746  * Retrieves a printable name of @actor for debugging messages
747  *
748  * Return value: a string with a printable name
749  */
750 const gchar *
751 _clutter_actor_get_debug_name (ClutterActor *actor)
752 {
753   return actor->priv->name != NULL ? actor->priv->name
754                                    : G_OBJECT_TYPE_NAME (actor);
755 }
756
757 #ifdef CLUTTER_ENABLE_DEBUG
758 /* XXX - this is for debugging only, remove once working (or leave
759  * in only in some debug mode). Should leave it for a little while
760  * until we're confident in the new map/realize/visible handling.
761  */
762 static inline void
763 clutter_actor_verify_map_state (ClutterActor *self)
764 {
765   ClutterActorPrivate *priv = self->priv;
766
767   if (CLUTTER_ACTOR_IS_REALIZED (self))
768     {
769       /* all bets are off during reparent when we're potentially realized,
770        * but should not be according to invariants
771        */
772       if (!CLUTTER_ACTOR_IN_REPARENT (self))
773         {
774           if (priv->parent == NULL)
775             {
776               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
777                 {
778                 }
779               else
780                 g_warning ("Realized non-toplevel actor '%s' should "
781                            "have a parent",
782                            _clutter_actor_get_debug_name (self));
783             }
784           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
785             {
786               g_warning ("Realized actor %s has an unrealized parent %s",
787                          _clutter_actor_get_debug_name (self),
788                          _clutter_actor_get_debug_name (priv->parent));
789             }
790         }
791     }
792
793   if (CLUTTER_ACTOR_IS_MAPPED (self))
794     {
795       if (!CLUTTER_ACTOR_IS_REALIZED (self))
796         g_warning ("Actor '%s' is mapped but not realized",
797                    _clutter_actor_get_debug_name (self));
798
799       /* remaining bets are off during reparent when we're potentially
800        * mapped, but should not be according to invariants
801        */
802       if (!CLUTTER_ACTOR_IN_REPARENT (self))
803         {
804           if (priv->parent == NULL)
805             {
806               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
807                 {
808                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
809                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
810                     {
811                       g_warning ("Toplevel actor '%s' is mapped "
812                                  "but not visible",
813                                  _clutter_actor_get_debug_name (self));
814                     }
815                 }
816               else
817                 {
818                   g_warning ("Mapped actor '%s' should have a parent",
819                              _clutter_actor_get_debug_name (self));
820                 }
821             }
822           else
823             {
824               ClutterActor *iter = self;
825
826               /* check for the enable_paint_unmapped flag on the actor
827                * and parents; if the flag is enabled at any point of this
828                * branch of the scene graph then all the later checks
829                * become pointless
830                */
831               while (iter != NULL)
832                 {
833                   if (iter->priv->enable_paint_unmapped)
834                     return;
835
836                   iter = iter->priv->parent;
837                 }
838
839               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
840                 {
841                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
842                              "is not visible",
843                              _clutter_actor_get_debug_name (self),
844                              _clutter_actor_get_debug_name (priv->parent));
845                 }
846
847               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
848                 {
849                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
850                              "is not realized",
851                              _clutter_actor_get_debug_name (self),
852                              _clutter_actor_get_debug_name (priv->parent));
853                 }
854
855               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
856                 {
857                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
858                     g_warning ("Actor '%s' is mapped but its non-toplevel "
859                                "parent '%s' is not mapped",
860                                _clutter_actor_get_debug_name (self),
861                                _clutter_actor_get_debug_name (priv->parent));
862                 }
863             }
864         }
865     }
866 }
867
868 #endif /* CLUTTER_ENABLE_DEBUG */
869
870 static void
871 clutter_actor_set_mapped (ClutterActor *self,
872                           gboolean      mapped)
873 {
874   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
875     return;
876
877   if (mapped)
878     {
879       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
880       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
881     }
882   else
883     {
884       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
885       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
886     }
887 }
888
889 /* this function updates the mapped and realized states according to
890  * invariants, in the appropriate order.
891  */
892 static void
893 clutter_actor_update_map_state (ClutterActor  *self,
894                                 MapStateChange change)
895 {
896   gboolean was_mapped;
897
898   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
899
900   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
901     {
902       /* the mapped flag on top-level actors must be set by the
903        * per-backend implementation because it might be asynchronous.
904        *
905        * That is, the MAPPED flag on toplevels currently tracks the X
906        * server mapped-ness of the window, while the expected behavior
907        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
908        * This creates some weird complexity by breaking the invariant
909        * that if we're visible and all ancestors shown then we are
910        * also mapped - instead, we are mapped if all ancestors
911        * _possibly excepting_ the stage are mapped. The stage
912        * will map/unmap for example when it is minimized or
913        * moved to another workspace.
914        *
915        * So, the only invariant on the stage is that if visible it
916        * should be realized, and that it has to be visible to be
917        * mapped.
918        */
919       if (CLUTTER_ACTOR_IS_VISIBLE (self))
920         clutter_actor_realize (self);
921
922       switch (change)
923         {
924         case MAP_STATE_CHECK:
925           break;
926
927         case MAP_STATE_MAKE_MAPPED:
928           g_assert (!was_mapped);
929           clutter_actor_set_mapped (self, TRUE);
930           break;
931
932         case MAP_STATE_MAKE_UNMAPPED:
933           g_assert (was_mapped);
934           clutter_actor_set_mapped (self, FALSE);
935           break;
936
937         case MAP_STATE_MAKE_UNREALIZED:
938           /* we only use MAKE_UNREALIZED in unparent,
939            * and unparenting a stage isn't possible.
940            * If someone wants to just unrealize a stage
941            * then clutter_actor_unrealize() doesn't
942            * go through this codepath.
943            */
944           g_warning ("Trying to force unrealize stage is not allowed");
945           break;
946         }
947
948       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
949           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
950           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
951         {
952           g_warning ("Clutter toplevel of type '%s' is not visible, but "
953                      "it is somehow still mapped",
954                      _clutter_actor_get_debug_name (self));
955         }
956     }
957   else
958     {
959       ClutterActorPrivate *priv = self->priv;
960       ClutterActor *parent = priv->parent;
961       gboolean should_be_mapped;
962       gboolean may_be_realized;
963       gboolean must_be_realized;
964
965       should_be_mapped = FALSE;
966       may_be_realized = TRUE;
967       must_be_realized = FALSE;
968
969       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
970         {
971           may_be_realized = FALSE;
972         }
973       else
974         {
975           /* Maintain invariant that if parent is mapped, and we are
976            * visible, then we are mapped ...  unless parent is a
977            * stage, in which case we map regardless of parent's map
978            * state but do require stage to be visible and realized.
979            *
980            * If parent is realized, that does not force us to be
981            * realized; but if parent is unrealized, that does force
982            * us to be unrealized.
983            *
984            * The reason we don't force children to realize with
985            * parents is _clutter_actor_rerealize(); if we require that
986            * a realized parent means children are realized, then to
987            * unrealize an actor we would have to unrealize its
988            * parents, which would end up meaning unrealizing and
989            * hiding the entire stage. So we allow unrealizing a
990            * child (as long as that child is not mapped) while that
991            * child still has a realized parent.
992            *
993            * Also, if we unrealize from leaf nodes to root, and
994            * realize from root to leaf, the invariants are never
995            * violated if we allow children to be unrealized
996            * while parents are realized.
997            *
998            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
999            * to force us to unmap, even though parent is still
1000            * mapped. This is because we're unmapping from leaf nodes
1001            * up to root nodes.
1002            */
1003           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1004               change != MAP_STATE_MAKE_UNMAPPED)
1005             {
1006               gboolean parent_is_visible_realized_toplevel;
1007
1008               parent_is_visible_realized_toplevel =
1009                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1010                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1011                  CLUTTER_ACTOR_IS_REALIZED (parent));
1012
1013               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1014                   parent_is_visible_realized_toplevel)
1015                 {
1016                   must_be_realized = TRUE;
1017                   should_be_mapped = TRUE;
1018                 }
1019             }
1020
1021           /* if the actor has been set to be painted even if unmapped
1022            * then we should map it and check for realization as well;
1023            * this is an override for the branch of the scene graph
1024            * which begins with this node
1025            */
1026           if (priv->enable_paint_unmapped)
1027             {
1028               if (priv->parent == NULL)
1029                 g_warning ("Attempting to map an unparented actor '%s'",
1030                            _clutter_actor_get_debug_name (self));
1031
1032               should_be_mapped = TRUE;
1033               must_be_realized = TRUE;
1034             }
1035
1036           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1037             may_be_realized = FALSE;
1038         }
1039
1040       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1041         {
1042           if (parent == NULL)
1043             g_warning ("Attempting to map a child that does not "
1044                        "meet the necessary invariants: the actor '%s' "
1045                        "has no parent",
1046                        _clutter_actor_get_debug_name (self));
1047           else
1048             g_warning ("Attempting to map a child that does not "
1049                        "meet the necessary invariants: the actor '%s' "
1050                        "is parented to an unmapped actor '%s'",
1051                        _clutter_actor_get_debug_name (self),
1052                        _clutter_actor_get_debug_name (priv->parent));
1053         }
1054
1055       /* If in reparent, we temporarily suspend unmap and unrealize.
1056        *
1057        * We want to go in the order "realize, map" and "unmap, unrealize"
1058        */
1059
1060       /* Unmap */
1061       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1062         clutter_actor_set_mapped (self, FALSE);
1063
1064       /* Realize */
1065       if (must_be_realized)
1066         clutter_actor_realize (self);
1067
1068       /* if we must be realized then we may be, presumably */
1069       g_assert (!(must_be_realized && !may_be_realized));
1070
1071       /* Unrealize */
1072       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1073         clutter_actor_unrealize_not_hiding (self);
1074
1075       /* Map */
1076       if (should_be_mapped)
1077         {
1078           if (!must_be_realized)
1079             g_warning ("Somehow we think actor '%s' should be mapped but "
1080                        "not realized, which isn't allowed",
1081                        _clutter_actor_get_debug_name (self));
1082
1083           /* realization is allowed to fail (though I don't know what
1084            * an app is supposed to do about that - shouldn't it just
1085            * be a g_error? anyway, we have to avoid mapping if this
1086            * happens)
1087            */
1088           if (CLUTTER_ACTOR_IS_REALIZED (self))
1089             clutter_actor_set_mapped (self, TRUE);
1090         }
1091     }
1092
1093 #ifdef CLUTTER_ENABLE_DEBUG
1094   /* check all invariants were kept */
1095   clutter_actor_verify_map_state (self);
1096 #endif
1097 }
1098
1099 static void
1100 clutter_actor_real_map (ClutterActor *self)
1101 {
1102   ClutterActorPrivate *priv = self->priv;
1103   ClutterActor *stage, *iter;
1104
1105   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1106
1107   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1108                 _clutter_actor_get_debug_name (self));
1109
1110   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1111
1112   stage = _clutter_actor_get_stage_internal (self);
1113   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1114
1115   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1116                 priv->pick_id,
1117                 _clutter_actor_get_debug_name (self));
1118
1119   /* notify on parent mapped before potentially mapping
1120    * children, so apps see a top-down notification.
1121    */
1122   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1123
1124   for (iter = self->priv->first_child;
1125        iter != NULL;
1126        iter = iter->priv->next_sibling)
1127     {
1128       clutter_actor_map (iter);
1129     }
1130 }
1131
1132 /**
1133  * clutter_actor_map:
1134  * @self: A #ClutterActor
1135  *
1136  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1137  * and realizes its children if they are visible. Does nothing if the
1138  * actor is not visible.
1139  *
1140  * Calling this function is strongly disencouraged: the default
1141  * implementation of #ClutterActorClass.map() will map all the children
1142  * of an actor when mapping its parent.
1143  *
1144  * When overriding map, it is mandatory to chain up to the parent
1145  * implementation.
1146  *
1147  * Since: 1.0
1148  */
1149 void
1150 clutter_actor_map (ClutterActor *self)
1151 {
1152   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1153
1154   if (CLUTTER_ACTOR_IS_MAPPED (self))
1155     return;
1156
1157   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1158     return;
1159
1160   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1161 }
1162
1163 static void
1164 clutter_actor_real_unmap (ClutterActor *self)
1165 {
1166   ClutterActorPrivate *priv = self->priv;
1167   ClutterActor *iter;
1168
1169   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1170
1171   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1172                 _clutter_actor_get_debug_name (self));
1173
1174   for (iter = self->priv->first_child;
1175        iter != NULL;
1176        iter = iter->priv->next_sibling)
1177     {
1178       clutter_actor_unmap (iter);
1179     }
1180
1181   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1182
1183   /* clear the contents of the last paint volume, so that hiding + moving +
1184    * showing will not result in the wrong area being repainted
1185    */
1186   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1187   priv->last_paint_volume_valid = TRUE;
1188
1189   /* notify on parent mapped after potentially unmapping
1190    * children, so apps see a bottom-up notification.
1191    */
1192   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1193
1194   /* relinquish keyboard focus if we were unmapped while owning it */
1195   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1196     {
1197       ClutterStage *stage;
1198
1199       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1200
1201       if (stage != NULL)
1202         _clutter_stage_release_pick_id (stage, priv->pick_id);
1203
1204       priv->pick_id = -1;
1205
1206       if (stage != NULL &&
1207           clutter_stage_get_key_focus (stage) == self)
1208         {
1209           clutter_stage_set_key_focus (stage, NULL);
1210         }
1211     }
1212 }
1213
1214 /**
1215  * clutter_actor_unmap:
1216  * @self: A #ClutterActor
1217  *
1218  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1219  * unmaps its children if they were mapped.
1220  *
1221  * Calling this function is not encouraged: the default #ClutterActor
1222  * implementation of #ClutterActorClass.unmap() will also unmap any
1223  * eventual children by default when their parent is unmapped.
1224  *
1225  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1226  * chain up to the parent implementation.
1227  *
1228  * <note>It is important to note that the implementation of the
1229  * #ClutterActorClass.unmap() virtual function may be called after
1230  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1231  * implementation, but it is guaranteed to be called before the
1232  * #GObjectClass.finalize() implementation.</note>
1233  *
1234  * Since: 1.0
1235  */
1236 void
1237 clutter_actor_unmap (ClutterActor *self)
1238 {
1239   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1240
1241   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1242     return;
1243
1244   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1245 }
1246
1247 static void
1248 clutter_actor_real_show (ClutterActor *self)
1249 {
1250   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1251     {
1252       ClutterActorPrivate *priv = self->priv;
1253
1254       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1255
1256       /* we notify on the "visible" flag in the clutter_actor_show()
1257        * wrapper so the entire show signal emission completes first
1258        * (?)
1259        */
1260       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1261
1262       /* we queue a relayout unless the actor is inside a
1263        * container that explicitly told us not to
1264        */
1265       if (priv->parent != NULL &&
1266           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1267         {
1268           /* While an actor is hidden the parent may not have
1269            * allocated/requested so we need to start from scratch
1270            * and avoid the short-circuiting in
1271            * clutter_actor_queue_relayout().
1272            */
1273           priv->needs_width_request  = FALSE;
1274           priv->needs_height_request = FALSE;
1275           priv->needs_allocation     = FALSE;
1276           clutter_actor_queue_relayout (self);
1277         }
1278     }
1279 }
1280
1281 static inline void
1282 set_show_on_set_parent (ClutterActor *self,
1283                         gboolean      set_show)
1284 {
1285   ClutterActorPrivate *priv = self->priv;
1286
1287   set_show = !!set_show;
1288
1289   if (priv->show_on_set_parent == set_show)
1290     return;
1291
1292   if (priv->parent == NULL)
1293     {
1294       priv->show_on_set_parent = set_show;
1295       g_object_notify_by_pspec (G_OBJECT (self),
1296                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1297     }
1298 }
1299
1300 /**
1301  * clutter_actor_show:
1302  * @self: A #ClutterActor
1303  *
1304  * Flags an actor to be displayed. An actor that isn't shown will not
1305  * be rendered on the stage.
1306  *
1307  * Actors are visible by default.
1308  *
1309  * If this function is called on an actor without a parent, the
1310  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1311  * effect.
1312  */
1313 void
1314 clutter_actor_show (ClutterActor *self)
1315 {
1316   ClutterActorPrivate *priv;
1317
1318   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1319
1320   /* simple optimization */
1321   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1322     {
1323       /* we still need to set the :show-on-set-parent property, in
1324        * case show() is called on an unparented actor
1325        */
1326       set_show_on_set_parent (self, TRUE);
1327       return;
1328     }
1329
1330 #ifdef CLUTTER_ENABLE_DEBUG
1331   clutter_actor_verify_map_state (self);
1332 #endif
1333
1334   priv = self->priv;
1335
1336   g_object_freeze_notify (G_OBJECT (self));
1337
1338   set_show_on_set_parent (self, TRUE);
1339
1340   g_signal_emit (self, actor_signals[SHOW], 0);
1341   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1342
1343   if (priv->parent != NULL)
1344     clutter_actor_queue_redraw (priv->parent);
1345
1346   g_object_thaw_notify (G_OBJECT (self));
1347 }
1348
1349 /**
1350  * clutter_actor_show_all:
1351  * @self: a #ClutterActor
1352  *
1353  * Calls clutter_actor_show() on all children of an actor (if any).
1354  *
1355  * Since: 0.2
1356  *
1357  * Deprecated: 1.10: Actors are visible by default
1358  */
1359 void
1360 clutter_actor_show_all (ClutterActor *self)
1361 {
1362   ClutterActorClass *klass;
1363
1364   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1365
1366   klass = CLUTTER_ACTOR_GET_CLASS (self);
1367   if (klass->show_all)
1368     klass->show_all (self);
1369 }
1370
1371 static void
1372 clutter_actor_real_hide (ClutterActor *self)
1373 {
1374   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1375     {
1376       ClutterActorPrivate *priv = self->priv;
1377
1378       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1379
1380       /* we notify on the "visible" flag in the clutter_actor_hide()
1381        * wrapper so the entire hide signal emission completes first
1382        * (?)
1383        */
1384       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1385
1386       /* we queue a relayout unless the actor is inside a
1387        * container that explicitly told us not to
1388        */
1389       if (priv->parent != NULL &&
1390           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1391         clutter_actor_queue_relayout (priv->parent);
1392     }
1393 }
1394
1395 /**
1396  * clutter_actor_hide:
1397  * @self: A #ClutterActor
1398  *
1399  * Flags an actor to be hidden. A hidden actor will not be
1400  * rendered on the stage.
1401  *
1402  * Actors are visible by default.
1403  *
1404  * If this function is called on an actor without a parent, the
1405  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1406  * as a side-effect.
1407  */
1408 void
1409 clutter_actor_hide (ClutterActor *self)
1410 {
1411   ClutterActorPrivate *priv;
1412
1413   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1414
1415   /* simple optimization */
1416   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1417     {
1418       /* we still need to set the :show-on-set-parent property, in
1419        * case hide() is called on an unparented actor
1420        */
1421       set_show_on_set_parent (self, FALSE);
1422       return;
1423     }
1424
1425 #ifdef CLUTTER_ENABLE_DEBUG
1426   clutter_actor_verify_map_state (self);
1427 #endif
1428
1429   priv = self->priv;
1430
1431   g_object_freeze_notify (G_OBJECT (self));
1432
1433   set_show_on_set_parent (self, FALSE);
1434
1435   g_signal_emit (self, actor_signals[HIDE], 0);
1436   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1437
1438   if (priv->parent != NULL)
1439     clutter_actor_queue_redraw (priv->parent);
1440
1441   g_object_thaw_notify (G_OBJECT (self));
1442 }
1443
1444 /**
1445  * clutter_actor_hide_all:
1446  * @self: a #ClutterActor
1447  *
1448  * Calls clutter_actor_hide() on all child actors (if any).
1449  *
1450  * Since: 0.2
1451  *
1452  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1453  *   prevent its children from being painted as well.
1454  */
1455 void
1456 clutter_actor_hide_all (ClutterActor *self)
1457 {
1458   ClutterActorClass *klass;
1459
1460   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1461
1462   klass = CLUTTER_ACTOR_GET_CLASS (self);
1463   if (klass->hide_all)
1464     klass->hide_all (self);
1465 }
1466
1467 /**
1468  * clutter_actor_realize:
1469  * @self: A #ClutterActor
1470  *
1471  * Realization informs the actor that it is attached to a stage. It
1472  * can use this to allocate resources if it wanted to delay allocation
1473  * until it would be rendered. However it is perfectly acceptable for
1474  * an actor to create resources before being realized because Clutter
1475  * only ever has a single rendering context so that actor is free to
1476  * be moved from one stage to another.
1477  *
1478  * This function does nothing if the actor is already realized.
1479  *
1480  * Because a realized actor must have realized parent actors, calling
1481  * clutter_actor_realize() will also realize all parents of the actor.
1482  *
1483  * This function does not realize child actors, except in the special
1484  * case that realizing the stage, when the stage is visible, will
1485  * suddenly map (and thus realize) the children of the stage.
1486  **/
1487 void
1488 clutter_actor_realize (ClutterActor *self)
1489 {
1490   ClutterActorPrivate *priv;
1491
1492   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1493
1494   priv = self->priv;
1495
1496 #ifdef CLUTTER_ENABLE_DEBUG
1497   clutter_actor_verify_map_state (self);
1498 #endif
1499
1500   if (CLUTTER_ACTOR_IS_REALIZED (self))
1501     return;
1502
1503   /* To be realized, our parent actors must be realized first.
1504    * This will only succeed if we're inside a toplevel.
1505    */
1506   if (priv->parent != NULL)
1507     clutter_actor_realize (priv->parent);
1508
1509   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1510     {
1511       /* toplevels can be realized at any time */
1512     }
1513   else
1514     {
1515       /* "Fail" the realization if parent is missing or unrealized;
1516        * this should really be a g_warning() not some kind of runtime
1517        * failure; how can an app possibly recover? Instead it's a bug
1518        * in the app and the app should get an explanatory warning so
1519        * someone can fix it. But for now it's too hard to fix this
1520        * because e.g. ClutterTexture needs reworking.
1521        */
1522       if (priv->parent == NULL ||
1523           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1524         return;
1525     }
1526
1527   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1528
1529   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1530   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1531
1532   g_signal_emit (self, actor_signals[REALIZE], 0);
1533
1534   /* Stage actor is allowed to unset the realized flag again in its
1535    * default signal handler, though that is a pathological situation.
1536    */
1537
1538   /* If realization "failed" we'll have to update child state. */
1539   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1540 }
1541
1542 static void
1543 clutter_actor_real_unrealize (ClutterActor *self)
1544 {
1545   /* we must be unmapped (implying our children are also unmapped) */
1546   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1547 }
1548
1549 /**
1550  * clutter_actor_unrealize:
1551  * @self: A #ClutterActor
1552  *
1553  * Unrealization informs the actor that it may be being destroyed or
1554  * moved to another stage. The actor may want to destroy any
1555  * underlying graphics resources at this point. However it is
1556  * perfectly acceptable for it to retain the resources until the actor
1557  * is destroyed because Clutter only ever uses a single rendering
1558  * context and all of the graphics resources are valid on any stage.
1559  *
1560  * Because mapped actors must be realized, actors may not be
1561  * unrealized if they are mapped. This function hides the actor to be
1562  * sure it isn't mapped, an application-visible side effect that you
1563  * may not be expecting.
1564  *
1565  * This function should not be called by application code.
1566  */
1567 void
1568 clutter_actor_unrealize (ClutterActor *self)
1569 {
1570   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1571   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1572
1573 /* This function should not really be in the public API, because
1574  * there isn't a good reason to call it. ClutterActor will already
1575  * unrealize things for you when it's important to do so.
1576  *
1577  * If you were using clutter_actor_unrealize() in a dispose
1578  * implementation, then don't, just chain up to ClutterActor's
1579  * dispose.
1580  *
1581  * If you were using clutter_actor_unrealize() to implement
1582  * unrealizing children of your container, then don't, ClutterActor
1583  * will already take care of that.
1584  *
1585  * If you were using clutter_actor_unrealize() to re-realize to
1586  * create your resources in a different way, then use
1587  * _clutter_actor_rerealize() (inside Clutter) or just call your
1588  * code that recreates your resources directly (outside Clutter).
1589  */
1590
1591 #ifdef CLUTTER_ENABLE_DEBUG
1592   clutter_actor_verify_map_state (self);
1593 #endif
1594
1595   clutter_actor_hide (self);
1596
1597   clutter_actor_unrealize_not_hiding (self);
1598 }
1599
1600 static ClutterActorTraverseVisitFlags
1601 unrealize_actor_before_children_cb (ClutterActor *self,
1602                                     int depth,
1603                                     void *user_data)
1604 {
1605   /* If an actor is already unrealized we know its children have also
1606    * already been unrealized... */
1607   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1608     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1609
1610   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1611
1612   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1613 }
1614
1615 static ClutterActorTraverseVisitFlags
1616 unrealize_actor_after_children_cb (ClutterActor *self,
1617                                    int depth,
1618                                    void *user_data)
1619 {
1620   /* We want to unset the realized flag only _after_
1621    * child actors are unrealized, to maintain invariants.
1622    */
1623   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1624   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1625   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1626 }
1627
1628 /*
1629  * clutter_actor_unrealize_not_hiding:
1630  * @self: A #ClutterActor
1631  *
1632  * Unrealization informs the actor that it may be being destroyed or
1633  * moved to another stage. The actor may want to destroy any
1634  * underlying graphics resources at this point. However it is
1635  * perfectly acceptable for it to retain the resources until the actor
1636  * is destroyed because Clutter only ever uses a single rendering
1637  * context and all of the graphics resources are valid on any stage.
1638  *
1639  * Because mapped actors must be realized, actors may not be
1640  * unrealized if they are mapped. You must hide the actor or one of
1641  * its parents before attempting to unrealize.
1642  *
1643  * This function is separate from clutter_actor_unrealize() because it
1644  * does not automatically hide the actor.
1645  * Actors need not be hidden to be unrealized, they just need to
1646  * be unmapped. In fact we don't want to mess up the application's
1647  * setting of the "visible" flag, so hiding is very undesirable.
1648  *
1649  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1650  * backward compatibility.
1651  */
1652 static void
1653 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1654 {
1655   _clutter_actor_traverse (self,
1656                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1657                            unrealize_actor_before_children_cb,
1658                            unrealize_actor_after_children_cb,
1659                            NULL);
1660 }
1661
1662 /*
1663  * _clutter_actor_rerealize:
1664  * @self: A #ClutterActor
1665  * @callback: Function to call while unrealized
1666  * @data: data for callback
1667  *
1668  * If an actor is already unrealized, this just calls the callback.
1669  *
1670  * If it is realized, it unrealizes temporarily, calls the callback,
1671  * and then re-realizes the actor.
1672  *
1673  * As a side effect, leaves all children of the actor unrealized if
1674  * the actor was realized but not showing.  This is because when we
1675  * unrealize the actor temporarily we must unrealize its children
1676  * (e.g. children of a stage can't be realized if stage window is
1677  * gone). And we aren't clever enough to save the realization state of
1678  * all children. In most cases this should not matter, because
1679  * the children will automatically realize when they next become mapped.
1680  */
1681 void
1682 _clutter_actor_rerealize (ClutterActor    *self,
1683                           ClutterCallback  callback,
1684                           void            *data)
1685 {
1686   gboolean was_mapped;
1687   gboolean was_showing;
1688   gboolean was_realized;
1689
1690   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1691
1692 #ifdef CLUTTER_ENABLE_DEBUG
1693   clutter_actor_verify_map_state (self);
1694 #endif
1695
1696   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1697   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1698   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1699
1700   /* Must be unmapped to unrealize. Note we only have to hide this
1701    * actor if it was mapped (if all parents were showing).  If actor
1702    * is merely visible (but not mapped), then that's fine, we can
1703    * leave it visible.
1704    */
1705   if (was_mapped)
1706     clutter_actor_hide (self);
1707
1708   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1709
1710   /* unrealize self and all children */
1711   clutter_actor_unrealize_not_hiding (self);
1712
1713   if (callback != NULL)
1714     {
1715       (* callback) (self, data);
1716     }
1717
1718   if (was_showing)
1719     clutter_actor_show (self); /* will realize only if mapping implies it */
1720   else if (was_realized)
1721     clutter_actor_realize (self); /* realize self and all parents */
1722 }
1723
1724 static void
1725 clutter_actor_real_pick (ClutterActor       *self,
1726                          const ClutterColor *color)
1727 {
1728   /* the default implementation is just to paint a rectangle
1729    * with the same size of the actor using the passed color
1730    */
1731   if (clutter_actor_should_pick_paint (self))
1732     {
1733       ClutterActorBox box = { 0, };
1734       float width, height;
1735
1736       clutter_actor_get_allocation_box (self, &box);
1737
1738       width = box.x2 - box.x1;
1739       height = box.y2 - box.y1;
1740
1741       cogl_set_source_color4ub (color->red,
1742                                 color->green,
1743                                 color->blue,
1744                                 color->alpha);
1745
1746       cogl_rectangle (0, 0, width, height);
1747     }
1748
1749   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1750    * with existing container classes that override the pick() virtual
1751    * and chain up to the default implementation - otherwise we'll end up
1752    * painting our children twice.
1753    *
1754    * this has to go away for 2.0; hopefully along the pick() itself.
1755    */
1756   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1757     {
1758       ClutterActor *iter;
1759
1760       for (iter = self->priv->first_child;
1761            iter != NULL;
1762            iter = iter->priv->next_sibling)
1763         clutter_actor_paint (iter);
1764     }
1765 }
1766
1767 /**
1768  * clutter_actor_should_pick_paint:
1769  * @self: A #ClutterActor
1770  *
1771  * Should be called inside the implementation of the
1772  * #ClutterActor::pick virtual function in order to check whether
1773  * the actor should paint itself in pick mode or not.
1774  *
1775  * This function should never be called directly by applications.
1776  *
1777  * Return value: %TRUE if the actor should paint its silhouette,
1778  *   %FALSE otherwise
1779  */
1780 gboolean
1781 clutter_actor_should_pick_paint (ClutterActor *self)
1782 {
1783   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1784
1785   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1786       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1787        CLUTTER_ACTOR_IS_REACTIVE (self)))
1788     return TRUE;
1789
1790   return FALSE;
1791 }
1792
1793 static void
1794 clutter_actor_real_get_preferred_width (ClutterActor *self,
1795                                         gfloat        for_height,
1796                                         gfloat       *min_width_p,
1797                                         gfloat       *natural_width_p)
1798 {
1799   ClutterActorPrivate *priv = self->priv;
1800
1801   if (priv->n_children != 0 &&
1802       priv->layout_manager != NULL)
1803     {
1804       ClutterContainer *container = CLUTTER_CONTAINER (self);
1805
1806       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1807                     "for the preferred width",
1808                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1809                     priv->layout_manager);
1810
1811       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1812                                                   container,
1813                                                   for_height,
1814                                                   min_width_p,
1815                                                   natural_width_p);
1816
1817       return;
1818     }
1819
1820   /* Default implementation is always 0x0, usually an actor
1821    * using this default is relying on someone to set the
1822    * request manually
1823    */
1824   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1825
1826   if (min_width_p)
1827     *min_width_p = 0;
1828
1829   if (natural_width_p)
1830     *natural_width_p = 0;
1831 }
1832
1833 static void
1834 clutter_actor_real_get_preferred_height (ClutterActor *self,
1835                                          gfloat        for_width,
1836                                          gfloat       *min_height_p,
1837                                          gfloat       *natural_height_p)
1838 {
1839   ClutterActorPrivate *priv = self->priv;
1840
1841   if (priv->n_children != 0 &&
1842       priv->layout_manager != NULL)
1843     {
1844       ClutterContainer *container = CLUTTER_CONTAINER (self);
1845
1846       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1847                     "for the preferred height",
1848                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1849                     priv->layout_manager);
1850
1851       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1852                                                    container,
1853                                                    for_width,
1854                                                    min_height_p,
1855                                                    natural_height_p);
1856
1857       return;
1858     }
1859   /* Default implementation is always 0x0, usually an actor
1860    * using this default is relying on someone to set the
1861    * request manually
1862    */
1863   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1864
1865   if (min_height_p)
1866     *min_height_p = 0;
1867
1868   if (natural_height_p)
1869     *natural_height_p = 0;
1870 }
1871
1872 static void
1873 clutter_actor_store_old_geometry (ClutterActor    *self,
1874                                   ClutterActorBox *box)
1875 {
1876   *box = self->priv->allocation;
1877 }
1878
1879 static inline void
1880 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1881                                           const ClutterActorBox *old)
1882 {
1883   ClutterActorPrivate *priv = self->priv;
1884   GObject *obj = G_OBJECT (self);
1885
1886   g_object_freeze_notify (obj);
1887
1888   /* to avoid excessive requisition or allocation cycles we
1889    * use the cached values.
1890    *
1891    * - if we don't have an allocation we assume that we need
1892    *   to notify anyway
1893    * - if we don't have a width or a height request we notify
1894    *   width and height
1895    * - if we have a valid allocation then we check the old
1896    *   bounding box with the current allocation and we notify
1897    *   the changes
1898    */
1899   if (priv->needs_allocation)
1900     {
1901       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1902       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1903       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1904       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1905     }
1906   else if (priv->needs_width_request || priv->needs_height_request)
1907     {
1908       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1909       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1910     }
1911   else
1912     {
1913       gfloat xu, yu;
1914       gfloat widthu, heightu;
1915
1916       xu = priv->allocation.x1;
1917       yu = priv->allocation.y1;
1918       widthu = priv->allocation.x2 - priv->allocation.x1;
1919       heightu = priv->allocation.y2 - priv->allocation.y1;
1920
1921       if (xu != old->x1)
1922         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1923
1924       if (yu != old->y1)
1925         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1926
1927       if (widthu != (old->x2 - old->x1))
1928         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1929
1930       if (heightu != (old->y2 - old->y1))
1931         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1932     }
1933
1934   g_object_thaw_notify (obj);
1935 }
1936
1937 /*< private >
1938  * clutter_actor_set_allocation_internal:
1939  * @self: a #ClutterActor
1940  * @box: a #ClutterActorBox
1941  * @flags: allocation flags
1942  *
1943  * Stores the allocation of @self.
1944  *
1945  * This function only performs basic storage and property notification.
1946  *
1947  * This function should be called by clutter_actor_set_allocation()
1948  * and by the default implementation of #ClutterActorClass.allocate().
1949  *
1950  * Return value: %TRUE if the allocation of the #ClutterActor has been
1951  *   changed, and %FALSE otherwise
1952  */
1953 static inline gboolean
1954 clutter_actor_set_allocation_internal (ClutterActor           *self,
1955                                        const ClutterActorBox  *box,
1956                                        ClutterAllocationFlags  flags)
1957 {
1958   ClutterActorPrivate *priv = self->priv;
1959   GObject *obj;
1960   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
1961   gboolean flags_changed;
1962   gboolean retval;
1963   ClutterActorBox old_alloc = { 0, };
1964
1965   obj = G_OBJECT (self);
1966
1967   g_object_freeze_notify (obj);
1968
1969   clutter_actor_store_old_geometry (self, &old_alloc);
1970
1971   x1_changed = priv->allocation.x1 != box->x1;
1972   y1_changed = priv->allocation.y1 != box->y1;
1973   x2_changed = priv->allocation.x2 != box->x2;
1974   y2_changed = priv->allocation.y2 != box->y2;
1975
1976   flags_changed = priv->allocation_flags != flags;
1977
1978   priv->allocation = *box;
1979   priv->allocation_flags = flags;
1980
1981   /* allocation is authoritative */
1982   priv->needs_width_request = FALSE;
1983   priv->needs_height_request = FALSE;
1984   priv->needs_allocation = FALSE;
1985
1986   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1987     {
1988       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
1989                     _clutter_actor_get_debug_name (self));
1990
1991       priv->transform_valid = FALSE;
1992
1993       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
1994
1995       retval = TRUE;
1996     }
1997   else
1998     retval = FALSE;
1999
2000   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2001
2002   g_object_thaw_notify (obj);
2003
2004   return retval;
2005 }
2006
2007 static void clutter_actor_real_allocate (ClutterActor           *self,
2008                                          const ClutterActorBox  *box,
2009                                          ClutterAllocationFlags  flags);
2010
2011 static inline void
2012 clutter_actor_maybe_layout_children (ClutterActor           *self,
2013                                      const ClutterActorBox  *allocation,
2014                                      ClutterAllocationFlags  flags)
2015 {
2016   ClutterActorPrivate *priv = self->priv;
2017
2018   /* this is going to be a bit hard to follow, so let's put an explanation
2019    * here.
2020    *
2021    * we want ClutterActor to have a default layout manager if the actor was
2022    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2023    *
2024    * we also want any subclass of ClutterActor that does not override the
2025    * ::allocate() virtual function to delegate to a layout manager.
2026    *
2027    * finally, we want to allow people subclassing ClutterActor and overriding
2028    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2029    *
2030    * on the other hand, we want existing actor subclasses overriding the
2031    * ::allocate() virtual function and chaining up to the parent's
2032    * implementation to continue working without allocating their children
2033    * twice, or without entering an allocation loop.
2034    *
2035    * for the first two points, we check if the class of the actor is
2036    * overridding the ::allocate() virtual function; if it isn't, then we
2037    * follow through with checking whether we have children and a layout
2038    * manager, and eventually calling clutter_layout_manager_allocate().
2039    *
2040    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2041    * allocation flags that we got passed, and if it is present, we continue
2042    * with the check above.
2043    *
2044    * if neither of these two checks yields a positive result, we just
2045    * assume that the ::allocate() virtual function that resulted in this
2046    * function being called will also allocate the children of the actor.
2047    */
2048
2049   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2050     goto check_layout;
2051
2052   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2053     goto check_layout;
2054
2055   return;
2056
2057 check_layout:
2058   if (priv->n_children != 0 &&
2059       priv->layout_manager != NULL)
2060     {
2061       ClutterContainer *container = CLUTTER_CONTAINER (self);
2062       ClutterAllocationFlags children_flags;
2063       ClutterActorBox children_box;
2064
2065       /* normalize the box passed to the layout manager */
2066       children_box.x1 = children_box.y1 = 0.f;
2067       children_box.x2 = (allocation->x2 - allocation->x1);
2068       children_box.y2 = (allocation->y2 - allocation->y1);
2069
2070       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2071        * the actor's children, since it refers only to the current
2072        * actor's allocation.
2073        */
2074       children_flags = flags;
2075       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2076
2077       CLUTTER_NOTE (LAYOUT,
2078                     "Allocating %d children of %s "
2079                     "at { %.2f, %.2f - %.2f x %.2f } "
2080                     "using %s",
2081                     priv->n_children,
2082                     _clutter_actor_get_debug_name (self),
2083                     allocation->x1,
2084                     allocation->y1,
2085                     (allocation->x2 - allocation->x1),
2086                     (allocation->y2 - allocation->y1),
2087                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2088
2089       clutter_layout_manager_allocate (priv->layout_manager,
2090                                        container,
2091                                        &children_box,
2092                                        children_flags);
2093     }
2094 }
2095
2096 static void
2097 clutter_actor_real_allocate (ClutterActor           *self,
2098                              const ClutterActorBox  *box,
2099                              ClutterAllocationFlags  flags)
2100 {
2101   ClutterActorPrivate *priv = self->priv;
2102   gboolean changed;
2103
2104   g_object_freeze_notify (G_OBJECT (self));
2105
2106   changed = clutter_actor_set_allocation_internal (self, box, flags);
2107
2108   /* we allocate our children before we notify changes in our geometry,
2109    * so that people connecting to properties will be able to get valid
2110    * data out of the sub-tree of the scene graph that has this actor at
2111    * the root.
2112    */
2113   clutter_actor_maybe_layout_children (self, box, flags);
2114
2115   if (changed)
2116     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2117                    &priv->allocation,
2118                    priv->allocation_flags);
2119
2120   g_object_thaw_notify (G_OBJECT (self));
2121 }
2122
2123 static void
2124 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2125                                     ClutterActor *origin)
2126 {
2127   /* no point in queuing a redraw on a destroyed actor */
2128   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2129     return;
2130
2131   /* NB: We can't bail out early here if the actor is hidden in case
2132    * the actor bas been cloned. In this case the clone will need to
2133    * receive the signal so it can queue its own redraw.
2134    */
2135
2136   /* calls klass->queue_redraw in default handler */
2137   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2138 }
2139
2140 static void
2141 clutter_actor_real_queue_redraw (ClutterActor *self,
2142                                  ClutterActor *origin)
2143 {
2144   ClutterActor *parent;
2145
2146   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2147                 _clutter_actor_get_debug_name (self),
2148                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2149                                : "same actor");
2150
2151   /* no point in queuing a redraw on a destroyed actor */
2152   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2153     return;
2154
2155   /* If the queue redraw is coming from a child then the actor has
2156      become dirty and any queued effect is no longer valid */
2157   if (self != origin)
2158     {
2159       self->priv->is_dirty = TRUE;
2160       self->priv->effect_to_redraw = NULL;
2161     }
2162
2163   /* If the actor isn't visible, we still had to emit the signal
2164    * to allow for a ClutterClone, but the appearance of the parent
2165    * won't change so we don't have to propagate up the hierarchy.
2166    */
2167   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2168     return;
2169
2170   /* Although we could determine here that a full stage redraw
2171    * has already been queued and immediately bail out, we actually
2172    * guarantee that we will propagate a queue-redraw signal to our
2173    * parent at least once so that it's possible to implement a
2174    * container that tracks which of its children have queued a
2175    * redraw.
2176    */
2177   if (self->priv->propagated_one_redraw)
2178     {
2179       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2180       if (stage != NULL &&
2181           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2182         return;
2183     }
2184
2185   self->priv->propagated_one_redraw = TRUE;
2186
2187   /* notify parents, if they are all visible eventually we'll
2188    * queue redraw on the stage, which queues the redraw idle.
2189    */
2190   parent = clutter_actor_get_parent (self);
2191   if (parent != NULL)
2192     {
2193       /* this will go up recursively */
2194       _clutter_actor_signal_queue_redraw (parent, origin);
2195     }
2196 }
2197
2198 static void
2199 clutter_actor_real_queue_relayout (ClutterActor *self)
2200 {
2201   ClutterActorPrivate *priv = self->priv;
2202
2203   /* no point in queueing a redraw on a destroyed actor */
2204   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2205     return;
2206
2207   priv->needs_width_request  = TRUE;
2208   priv->needs_height_request = TRUE;
2209   priv->needs_allocation     = TRUE;
2210
2211   /* reset the cached size requests */
2212   memset (priv->width_requests, 0,
2213           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2214   memset (priv->height_requests, 0,
2215           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2216
2217   /* We need to go all the way up the hierarchy */
2218   if (priv->parent != NULL)
2219     _clutter_actor_queue_only_relayout (priv->parent);
2220 }
2221
2222 /**
2223  * clutter_actor_apply_relative_transform_to_point:
2224  * @self: A #ClutterActor
2225  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2226  *   default #ClutterStage
2227  * @point: A point as #ClutterVertex
2228  * @vertex: (out caller-allocates): The translated #ClutterVertex
2229  *
2230  * Transforms @point in coordinates relative to the actor into
2231  * ancestor-relative coordinates using the relevant transform
2232  * stack (i.e. scale, rotation, etc).
2233  *
2234  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2235  * this case, the coordinates returned will be the coordinates on
2236  * the stage before the projection is applied. This is different from
2237  * the behaviour of clutter_actor_apply_transform_to_point().
2238  *
2239  * Since: 0.6
2240  */
2241 void
2242 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2243                                                  ClutterActor        *ancestor,
2244                                                  const ClutterVertex *point,
2245                                                  ClutterVertex       *vertex)
2246 {
2247   gfloat w;
2248   CoglMatrix matrix;
2249
2250   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2251   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2252   g_return_if_fail (point != NULL);
2253   g_return_if_fail (vertex != NULL);
2254
2255   *vertex = *point;
2256   w = 1.0;
2257
2258   if (ancestor == NULL)
2259     ancestor = _clutter_actor_get_stage_internal (self);
2260
2261   if (ancestor == NULL)
2262     {
2263       *vertex = *point;
2264       return;
2265     }
2266
2267   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2268   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2269 }
2270
2271 static gboolean
2272 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2273                                          const ClutterVertex *vertices_in,
2274                                          ClutterVertex *vertices_out,
2275                                          int n_vertices)
2276 {
2277   ClutterActor *stage;
2278   CoglMatrix modelview;
2279   CoglMatrix projection;
2280   float viewport[4];
2281
2282   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2283
2284   stage = _clutter_actor_get_stage_internal (self);
2285
2286   /* We really can't do anything meaningful in this case so don't try
2287    * to do any transform */
2288   if (stage == NULL)
2289     return FALSE;
2290
2291   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2292    * that gets us to stage coordinates, we want to go all the way to eye
2293    * coordinates */
2294   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2295
2296   /* Fetch the projection and viewport */
2297   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2298   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2299                                &viewport[0],
2300                                &viewport[1],
2301                                &viewport[2],
2302                                &viewport[3]);
2303
2304   _clutter_util_fully_transform_vertices (&modelview,
2305                                           &projection,
2306                                           viewport,
2307                                           vertices_in,
2308                                           vertices_out,
2309                                           n_vertices);
2310
2311   return TRUE;
2312 }
2313
2314 /**
2315  * clutter_actor_apply_transform_to_point:
2316  * @self: A #ClutterActor
2317  * @point: A point as #ClutterVertex
2318  * @vertex: (out caller-allocates): The translated #ClutterVertex
2319  *
2320  * Transforms @point in coordinates relative to the actor
2321  * into screen-relative coordinates with the current actor
2322  * transformation (i.e. scale, rotation, etc)
2323  *
2324  * Since: 0.4
2325  **/
2326 void
2327 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2328                                         const ClutterVertex *point,
2329                                         ClutterVertex       *vertex)
2330 {
2331   g_return_if_fail (point != NULL);
2332   g_return_if_fail (vertex != NULL);
2333   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2334 }
2335
2336 /*
2337  * _clutter_actor_get_relative_transformation_matrix:
2338  * @self: The actor whose coordinate space you want to transform from.
2339  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2340  *            or %NULL if you want to transform all the way to eye coordinates.
2341  * @matrix: A #CoglMatrix to store the transformation
2342  *
2343  * This gets a transformation @matrix that will transform coordinates from the
2344  * coordinate space of @self into the coordinate space of @ancestor.
2345  *
2346  * For example if you need a matrix that can transform the local actor
2347  * coordinates of @self into stage coordinates you would pass the actor's stage
2348  * pointer as the @ancestor.
2349  *
2350  * If you pass %NULL then the transformation will take you all the way through
2351  * to eye coordinates. This can be useful if you want to extract the entire
2352  * modelview transform that Clutter applies before applying the projection
2353  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2354  * using cogl_set_modelview_matrix() for example then you would want a matrix
2355  * that transforms into eye coordinates.
2356  *
2357  * <note><para>This function explicitly initializes the given @matrix. If you just
2358  * want clutter to multiply a relative transformation with an existing matrix
2359  * you can use clutter_actor_apply_relative_transformation_matrix()
2360  * instead.</para></note>
2361  *
2362  */
2363 /* XXX: We should consider caching the stage relative modelview along with
2364  * the actor itself */
2365 static void
2366 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2367                                                    ClutterActor *ancestor,
2368                                                    CoglMatrix *matrix)
2369 {
2370   cogl_matrix_init_identity (matrix);
2371
2372   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2373 }
2374
2375 /* Project the given @box into stage window coordinates, writing the
2376  * transformed vertices to @verts[]. */
2377 static gboolean
2378 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2379                                           const ClutterActorBox *box,
2380                                           ClutterVertex          verts[])
2381 {
2382   ClutterVertex box_vertices[4];
2383
2384   box_vertices[0].x = box->x1;
2385   box_vertices[0].y = box->y1;
2386   box_vertices[0].z = 0;
2387   box_vertices[1].x = box->x2;
2388   box_vertices[1].y = box->y1;
2389   box_vertices[1].z = 0;
2390   box_vertices[2].x = box->x1;
2391   box_vertices[2].y = box->y2;
2392   box_vertices[2].z = 0;
2393   box_vertices[3].x = box->x2;
2394   box_vertices[3].y = box->y2;
2395   box_vertices[3].z = 0;
2396
2397   return
2398     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2399 }
2400
2401 /**
2402  * clutter_actor_get_allocation_vertices:
2403  * @self: A #ClutterActor
2404  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2405  *   against, or %NULL to use the #ClutterStage
2406  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2407  *   location for an array of 4 #ClutterVertex in which to store the result
2408  *
2409  * Calculates the transformed coordinates of the four corners of the
2410  * actor in the plane of @ancestor. The returned vertices relate to
2411  * the #ClutterActorBox coordinates as follows:
2412  * <itemizedlist>
2413  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2414  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2415  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2416  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2417  * </itemizedlist>
2418  *
2419  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2420  * this case, the coordinates returned will be the coordinates on
2421  * the stage before the projection is applied. This is different from
2422  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2423  *
2424  * Since: 0.6
2425  */
2426 void
2427 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2428                                        ClutterActor  *ancestor,
2429                                        ClutterVertex  verts[])
2430 {
2431   ClutterActorPrivate *priv;
2432   ClutterActorBox box;
2433   ClutterVertex vertices[4];
2434   CoglMatrix modelview;
2435
2436   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2437   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2438
2439   if (ancestor == NULL)
2440     ancestor = _clutter_actor_get_stage_internal (self);
2441
2442   /* Fallback to a NOP transform if the actor isn't parented under a
2443    * stage. */
2444   if (ancestor == NULL)
2445     ancestor = self;
2446
2447   priv = self->priv;
2448
2449   /* if the actor needs to be allocated we force a relayout, so that
2450    * we will have valid values to use in the transformations */
2451   if (priv->needs_allocation)
2452     {
2453       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2454       if (stage)
2455         _clutter_stage_maybe_relayout (stage);
2456       else
2457         {
2458           box.x1 = box.y1 = 0;
2459           /* The result isn't really meaningful in this case but at
2460            * least try to do something *vaguely* reasonable... */
2461           clutter_actor_get_size (self, &box.x2, &box.y2);
2462         }
2463     }
2464
2465   clutter_actor_get_allocation_box (self, &box);
2466
2467   vertices[0].x = box.x1;
2468   vertices[0].y = box.y1;
2469   vertices[0].z = 0;
2470   vertices[1].x = box.x2;
2471   vertices[1].y = box.y1;
2472   vertices[1].z = 0;
2473   vertices[2].x = box.x1;
2474   vertices[2].y = box.y2;
2475   vertices[2].z = 0;
2476   vertices[3].x = box.x2;
2477   vertices[3].y = box.y2;
2478   vertices[3].z = 0;
2479
2480   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2481                                                      &modelview);
2482
2483   cogl_matrix_transform_points (&modelview,
2484                                 3,
2485                                 sizeof (ClutterVertex),
2486                                 vertices,
2487                                 sizeof (ClutterVertex),
2488                                 vertices,
2489                                 4);
2490 }
2491
2492 /**
2493  * clutter_actor_get_abs_allocation_vertices:
2494  * @self: A #ClutterActor
2495  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2496  *   of 4 #ClutterVertex where to store the result.
2497  *
2498  * Calculates the transformed screen coordinates of the four corners of
2499  * the actor; the returned vertices relate to the #ClutterActorBox
2500  * coordinates  as follows:
2501  * <itemizedlist>
2502  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2503  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2504  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2505  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2506  * </itemizedlist>
2507  *
2508  * Since: 0.4
2509  */
2510 void
2511 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2512                                            ClutterVertex  verts[])
2513 {
2514   ClutterActorPrivate *priv;
2515   ClutterActorBox actor_space_allocation;
2516
2517   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2518
2519   priv = self->priv;
2520
2521   /* if the actor needs to be allocated we force a relayout, so that
2522    * the actor allocation box will be valid for
2523    * _clutter_actor_transform_and_project_box()
2524    */
2525   if (priv->needs_allocation)
2526     {
2527       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2528       /* There's nothing meaningful we can do now */
2529       if (!stage)
2530         return;
2531
2532       _clutter_stage_maybe_relayout (stage);
2533     }
2534
2535   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2536    * own coordinate space... */
2537   actor_space_allocation.x1 = 0;
2538   actor_space_allocation.y1 = 0;
2539   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2540   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2541   _clutter_actor_transform_and_project_box (self,
2542                                             &actor_space_allocation,
2543                                             verts);
2544 }
2545
2546 static void
2547 clutter_actor_real_apply_transform (ClutterActor *self,
2548                                     CoglMatrix   *matrix)
2549 {
2550   ClutterActorPrivate *priv = self->priv;
2551
2552   if (!priv->transform_valid)
2553     {
2554       CoglMatrix *transform = &priv->transform;
2555       const ClutterTransformInfo *info;
2556
2557       info = _clutter_actor_get_transform_info_or_defaults (self);
2558
2559       cogl_matrix_init_identity (transform);
2560
2561       cogl_matrix_translate (transform,
2562                              priv->allocation.x1,
2563                              priv->allocation.y1,
2564                              0.0);
2565
2566       if (priv->z)
2567         cogl_matrix_translate (transform, 0, 0, priv->z);
2568
2569       /*
2570        * because the rotation involves translations, we must scale
2571        * before applying the rotations (if we apply the scale after
2572        * the rotations, the translations included in the rotation are
2573        * not scaled and so the entire object will move on the screen
2574        * as a result of rotating it).
2575        */
2576       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2577         {
2578           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2579                                         &info->scale_center,
2580                                         cogl_matrix_scale (transform,
2581                                                            info->scale_x,
2582                                                            info->scale_y,
2583                                                            1.0));
2584         }
2585
2586       if (info->rz_angle)
2587         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2588                                       &info->rz_center,
2589                                       cogl_matrix_rotate (transform,
2590                                                           info->rz_angle,
2591                                                           0, 0, 1.0));
2592
2593       if (info->ry_angle)
2594         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2595                                       &info->ry_center,
2596                                       cogl_matrix_rotate (transform,
2597                                                           info->ry_angle,
2598                                                           0, 1.0, 0));
2599
2600       if (info->rx_angle)
2601         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2602                                       &info->rx_center,
2603                                       cogl_matrix_rotate (transform,
2604                                                           info->rx_angle,
2605                                                           1.0, 0, 0));
2606
2607       if (!clutter_anchor_coord_is_zero (&info->anchor))
2608         {
2609           gfloat x, y, z;
2610
2611           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2612           cogl_matrix_translate (transform, -x, -y, -z);
2613         }
2614
2615       priv->transform_valid = TRUE;
2616     }
2617
2618   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2619 }
2620
2621 /* Applies the transforms associated with this actor to the given
2622  * matrix. */
2623 void
2624 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2625                                           CoglMatrix *matrix)
2626 {
2627   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2628 }
2629
2630 /*
2631  * clutter_actor_apply_relative_transformation_matrix:
2632  * @self: The actor whose coordinate space you want to transform from.
2633  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2634  *            or %NULL if you want to transform all the way to eye coordinates.
2635  * @matrix: A #CoglMatrix to apply the transformation too.
2636  *
2637  * This multiplies a transform with @matrix that will transform coordinates
2638  * from the coordinate space of @self into the coordinate space of @ancestor.
2639  *
2640  * For example if you need a matrix that can transform the local actor
2641  * coordinates of @self into stage coordinates you would pass the actor's stage
2642  * pointer as the @ancestor.
2643  *
2644  * If you pass %NULL then the transformation will take you all the way through
2645  * to eye coordinates. This can be useful if you want to extract the entire
2646  * modelview transform that Clutter applies before applying the projection
2647  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2648  * using cogl_set_modelview_matrix() for example then you would want a matrix
2649  * that transforms into eye coordinates.
2650  *
2651  * <note>This function doesn't initialize the given @matrix, it simply
2652  * multiplies the requested transformation matrix with the existing contents of
2653  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2654  * before calling this function, or you can use
2655  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2656  */
2657 void
2658 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2659                                                      ClutterActor *ancestor,
2660                                                      CoglMatrix *matrix)
2661 {
2662   ClutterActor *parent;
2663
2664   /* Note we terminate before ever calling stage->apply_transform()
2665    * since that would conceptually be relative to the underlying
2666    * window OpenGL coordinates so we'd need a special @ancestor
2667    * value to represent the fake parent of the stage. */
2668   if (self == ancestor)
2669     return;
2670
2671   parent = clutter_actor_get_parent (self);
2672
2673   if (parent != NULL)
2674     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2675                                                          matrix);
2676
2677   _clutter_actor_apply_modelview_transform (self, matrix);
2678 }
2679
2680 static void
2681 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2682                                        ClutterPaintVolume *pv,
2683                                        const char *label,
2684                                        const CoglColor *color)
2685 {
2686   static CoglPipeline *outline = NULL;
2687   CoglPrimitive *prim;
2688   ClutterVertex line_ends[12 * 2];
2689   int n_vertices;
2690   CoglContext *ctx =
2691     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2692   /* XXX: at some point we'll query this from the stage but we can't
2693    * do that until the osx backend uses Cogl natively. */
2694   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2695
2696   if (outline == NULL)
2697     outline = cogl_pipeline_new (ctx);
2698
2699   _clutter_paint_volume_complete (pv);
2700
2701   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2702
2703   /* Front face */
2704   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2705   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2706   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2707   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2708
2709   if (!pv->is_2d)
2710     {
2711       /* Back face */
2712       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2713       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2714       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2715       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2716
2717       /* Lines connecting front face to back face */
2718       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2719       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2720       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2721       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2722     }
2723
2724   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2725                                 n_vertices,
2726                                 (CoglVertexP3 *)line_ends);
2727
2728   cogl_pipeline_set_color (outline, color);
2729   cogl_framebuffer_draw_primitive (fb, outline, prim);
2730   cogl_object_unref (prim);
2731
2732   if (label)
2733     {
2734       PangoLayout *layout;
2735       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2736       pango_layout_set_text (layout, label, -1);
2737       cogl_pango_render_layout (layout,
2738                                 pv->vertices[0].x,
2739                                 pv->vertices[0].y,
2740                                 color,
2741                                 0);
2742       g_object_unref (layout);
2743     }
2744 }
2745
2746 static void
2747 _clutter_actor_draw_paint_volume (ClutterActor *self)
2748 {
2749   ClutterPaintVolume *pv;
2750   CoglColor color;
2751
2752   pv = _clutter_actor_get_paint_volume_mutable (self);
2753   if (!pv)
2754     {
2755       gfloat width, height;
2756       ClutterPaintVolume fake_pv;
2757
2758       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2759       _clutter_paint_volume_init_static (&fake_pv, stage);
2760
2761       clutter_actor_get_size (self, &width, &height);
2762       clutter_paint_volume_set_width (&fake_pv, width);
2763       clutter_paint_volume_set_height (&fake_pv, height);
2764
2765       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2766       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2767                                              _clutter_actor_get_debug_name (self),
2768                                              &color);
2769
2770       clutter_paint_volume_free (&fake_pv);
2771     }
2772   else
2773     {
2774       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2775       _clutter_actor_draw_paint_volume_full (self, pv,
2776                                              _clutter_actor_get_debug_name (self),
2777                                              &color);
2778     }
2779 }
2780
2781 static void
2782 _clutter_actor_paint_cull_result (ClutterActor *self,
2783                                   gboolean success,
2784                                   ClutterCullResult result)
2785 {
2786   ClutterPaintVolume *pv;
2787   CoglColor color;
2788
2789   if (success)
2790     {
2791       if (result == CLUTTER_CULL_RESULT_IN)
2792         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2793       else if (result == CLUTTER_CULL_RESULT_OUT)
2794         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2795       else
2796         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2797     }
2798   else
2799     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2800
2801   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2802     _clutter_actor_draw_paint_volume_full (self, pv,
2803                                            _clutter_actor_get_debug_name (self),
2804                                            &color);
2805   else
2806     {
2807       PangoLayout *layout;
2808       char *label =
2809         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2810       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2811       cogl_set_source_color (&color);
2812
2813       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2814       pango_layout_set_text (layout, label, -1);
2815       cogl_pango_render_layout (layout,
2816                                 0,
2817                                 0,
2818                                 &color,
2819                                 0);
2820       g_free (label);
2821       g_object_unref (layout);
2822     }
2823 }
2824
2825 static int clone_paint_level = 0;
2826
2827 void
2828 _clutter_actor_push_clone_paint (void)
2829 {
2830   clone_paint_level++;
2831 }
2832
2833 void
2834 _clutter_actor_pop_clone_paint (void)
2835 {
2836   clone_paint_level--;
2837 }
2838
2839 static gboolean
2840 in_clone_paint (void)
2841 {
2842   return clone_paint_level > 0;
2843 }
2844
2845 /* Returns TRUE if the actor can be ignored */
2846 /* FIXME: we should return a ClutterCullResult, and
2847  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2848  * means there's no point in trying to cull descendants of the current
2849  * node. */
2850 static gboolean
2851 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2852 {
2853   ClutterActorPrivate *priv = self->priv;
2854   ClutterActor *stage;
2855   const ClutterPlane *stage_clip;
2856
2857   if (!priv->last_paint_volume_valid)
2858     {
2859       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2860                     "->last_paint_volume_valid == FALSE",
2861                     _clutter_actor_get_debug_name (self));
2862       return FALSE;
2863     }
2864
2865   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2866     return FALSE;
2867
2868   stage = _clutter_actor_get_stage_internal (self);
2869   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2870   if (G_UNLIKELY (!stage_clip))
2871     {
2872       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2873                     "No stage clip set",
2874                     _clutter_actor_get_debug_name (self));
2875       return FALSE;
2876     }
2877
2878   if (cogl_get_draw_framebuffer () !=
2879       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2880     {
2881       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2882                     "Current framebuffer doesn't correspond to stage",
2883                     _clutter_actor_get_debug_name (self));
2884       return FALSE;
2885     }
2886
2887   *result_out =
2888     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2889   return TRUE;
2890 }
2891
2892 static void
2893 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2894 {
2895   ClutterActorPrivate *priv = self->priv;
2896   const ClutterPaintVolume *pv;
2897
2898   if (priv->last_paint_volume_valid)
2899     {
2900       clutter_paint_volume_free (&priv->last_paint_volume);
2901       priv->last_paint_volume_valid = FALSE;
2902     }
2903
2904   pv = clutter_actor_get_paint_volume (self);
2905   if (!pv)
2906     {
2907       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2908                     "Actor failed to report a paint volume",
2909                     _clutter_actor_get_debug_name (self));
2910       return;
2911     }
2912
2913   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2914
2915   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2916                                             NULL); /* eye coordinates */
2917
2918   priv->last_paint_volume_valid = TRUE;
2919 }
2920
2921 static inline gboolean
2922 actor_has_shader_data (ClutterActor *self)
2923 {
2924   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2925 }
2926
2927 guint32
2928 _clutter_actor_get_pick_id (ClutterActor *self)
2929 {
2930   if (self->priv->pick_id < 0)
2931     return 0;
2932
2933   return self->priv->pick_id;
2934 }
2935
2936 /* This is the same as clutter_actor_add_effect except that it doesn't
2937    queue a redraw and it doesn't notify on the effect property */
2938 static void
2939 _clutter_actor_add_effect_internal (ClutterActor  *self,
2940                                     ClutterEffect *effect)
2941 {
2942   ClutterActorPrivate *priv = self->priv;
2943
2944   if (priv->effects == NULL)
2945     {
2946       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
2947       priv->effects->actor = self;
2948     }
2949
2950   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2951 }
2952
2953 /* This is the same as clutter_actor_remove_effect except that it doesn't
2954    queue a redraw and it doesn't notify on the effect property */
2955 static void
2956 _clutter_actor_remove_effect_internal (ClutterActor  *self,
2957                                        ClutterEffect *effect)
2958 {
2959   ClutterActorPrivate *priv = self->priv;
2960
2961   if (priv->effects == NULL)
2962     return;
2963
2964   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2965 }
2966
2967 static gboolean
2968 needs_flatten_effect (ClutterActor *self)
2969 {
2970   ClutterActorPrivate *priv = self->priv;
2971
2972   if (G_UNLIKELY (clutter_paint_debug_flags &
2973                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
2974     return FALSE;
2975
2976   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
2977     return TRUE;
2978   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
2979     {
2980       if (clutter_actor_get_paint_opacity (self) < 255 &&
2981           clutter_actor_has_overlaps (self))
2982         return TRUE;
2983     }
2984
2985   return FALSE;
2986 }
2987
2988 static void
2989 add_or_remove_flatten_effect (ClutterActor *self)
2990 {
2991   ClutterActorPrivate *priv = self->priv;
2992
2993   /* Add or remove the flatten effect depending on the
2994      offscreen-redirect property. */
2995   if (needs_flatten_effect (self))
2996     {
2997       if (priv->flatten_effect == NULL)
2998         {
2999           ClutterActorMeta *actor_meta;
3000           gint priority;
3001
3002           priv->flatten_effect = _clutter_flatten_effect_new ();
3003           /* Keep a reference to the effect so that we can queue
3004              redraws from it */
3005           g_object_ref_sink (priv->flatten_effect);
3006
3007           /* Set the priority of the effect to high so that it will
3008              always be applied to the actor first. It uses an internal
3009              priority so that it won't be visible to applications */
3010           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3011           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3012           _clutter_actor_meta_set_priority (actor_meta, priority);
3013
3014           /* This will add the effect without queueing a redraw */
3015           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3016         }
3017     }
3018   else
3019     {
3020       if (priv->flatten_effect != NULL)
3021         {
3022           /* Destroy the effect so that it will lose its fbo cache of
3023              the actor */
3024           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3025           g_object_unref (priv->flatten_effect);
3026           priv->flatten_effect = NULL;
3027         }
3028     }
3029 }
3030
3031 static void
3032 clutter_actor_real_paint (ClutterActor *actor)
3033 {
3034   ClutterActorPrivate *priv = actor->priv;
3035   ClutterActor *iter;
3036
3037   /* paint the background color, if set */
3038   if (priv->bg_color_set)
3039     {
3040       float width, height;
3041       guint8 real_alpha;
3042
3043       clutter_actor_box_get_size (&priv->allocation, &width, &height);
3044
3045       real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3046                  * priv->bg_color.alpha
3047                  / 255;
3048
3049       cogl_set_source_color4ub (priv->bg_color.red,
3050                                 priv->bg_color.green,
3051                                 priv->bg_color.blue,
3052                                 real_alpha);
3053
3054       cogl_rectangle (0, 0, width, height);
3055     }
3056
3057   for (iter = priv->first_child;
3058        iter != NULL;
3059        iter = iter->priv->next_sibling)
3060     {
3061       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3062                     _clutter_actor_get_debug_name (iter),
3063                     _clutter_actor_get_debug_name (actor),
3064                     iter->priv->allocation.x1,
3065                     iter->priv->allocation.y1,
3066                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3067                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3068
3069       clutter_actor_paint (iter);
3070     }
3071 }
3072
3073 /**
3074  * clutter_actor_paint:
3075  * @self: A #ClutterActor
3076  *
3077  * Renders the actor to display.
3078  *
3079  * This function should not be called directly by applications.
3080  * Call clutter_actor_queue_redraw() to queue paints, instead.
3081  *
3082  * This function is context-aware, and will either cause a
3083  * regular paint or a pick paint.
3084  *
3085  * This function will emit the #ClutterActor::paint signal or
3086  * the #ClutterActor::pick signal, depending on the context.
3087  *
3088  * This function does not paint the actor if the actor is set to 0,
3089  * unless it is performing a pick paint.
3090  */
3091 void
3092 clutter_actor_paint (ClutterActor *self)
3093 {
3094   ClutterActorPrivate *priv;
3095   ClutterPickMode pick_mode;
3096   gboolean clip_set = FALSE;
3097   gboolean shader_applied = FALSE;
3098
3099   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3100                           "Actor real-paint counter",
3101                           "Increments each time any actor is painted",
3102                           0 /* no application private data */);
3103   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3104                           "Actor pick-paint counter",
3105                           "Increments each time any actor is painted "
3106                           "for picking",
3107                           0 /* no application private data */);
3108
3109   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3110
3111   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3112     return;
3113
3114   priv = self->priv;
3115
3116   pick_mode = _clutter_context_get_pick_mode ();
3117
3118   if (pick_mode == CLUTTER_PICK_NONE)
3119     priv->propagated_one_redraw = FALSE;
3120
3121   /* It's an important optimization that we consider painting of
3122    * actors with 0 opacity to be a NOP... */
3123   if (pick_mode == CLUTTER_PICK_NONE &&
3124       /* ignore top-levels, since they might be transparent */
3125       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3126       /* Use the override opacity if its been set */
3127       ((priv->opacity_override >= 0) ?
3128        priv->opacity_override : priv->opacity) == 0)
3129     return;
3130
3131   /* if we aren't paintable (not in a toplevel with all
3132    * parents paintable) then do nothing.
3133    */
3134   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3135     return;
3136
3137   /* mark that we are in the paint process */
3138   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3139
3140   cogl_push_matrix();
3141
3142   if (priv->enable_model_view_transform)
3143     {
3144       CoglMatrix matrix;
3145
3146       /* XXX: It could be better to cache the modelview with the actor
3147        * instead of progressively building up the transformations on
3148        * the matrix stack every time we paint. */
3149       cogl_get_modelview_matrix (&matrix);
3150       _clutter_actor_apply_modelview_transform (self, &matrix);
3151
3152 #ifdef CLUTTER_ENABLE_DEBUG
3153       /* Catch when out-of-band transforms have been made by actors not as part
3154        * of an apply_transform vfunc... */
3155       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3156         {
3157           CoglMatrix expected_matrix;
3158
3159           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3160                                                              &expected_matrix);
3161
3162           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3163             {
3164               GString *buf = g_string_sized_new (1024);
3165               ClutterActor *parent;
3166
3167               parent = self;
3168               while (parent != NULL)
3169                 {
3170                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3171
3172                   if (parent->priv->parent != NULL)
3173                     g_string_append (buf, "->");
3174
3175                   parent = parent->priv->parent;
3176                 }
3177
3178               g_warning ("Unexpected transform found when painting actor "
3179                          "\"%s\". This will be caused by one of the actor's "
3180                          "ancestors (%s) using the Cogl API directly to transform "
3181                          "children instead of using ::apply_transform().",
3182                          _clutter_actor_get_debug_name (self),
3183                          buf->str);
3184
3185               g_string_free (buf, TRUE);
3186             }
3187         }
3188 #endif /* CLUTTER_ENABLE_DEBUG */
3189
3190       cogl_set_modelview_matrix (&matrix);
3191     }
3192
3193   if (priv->has_clip)
3194     {
3195       cogl_clip_push_rectangle (priv->clip.x,
3196                                 priv->clip.y,
3197                                 priv->clip.x + priv->clip.width,
3198                                 priv->clip.y + priv->clip.height);
3199       clip_set = TRUE;
3200     }
3201   else if (priv->clip_to_allocation)
3202     {
3203       gfloat width, height;
3204
3205       width  = priv->allocation.x2 - priv->allocation.x1;
3206       height = priv->allocation.y2 - priv->allocation.y1;
3207
3208       cogl_clip_push_rectangle (0, 0, width, height);
3209       clip_set = TRUE;
3210     }
3211
3212   if (pick_mode == CLUTTER_PICK_NONE)
3213     {
3214       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3215
3216       /* We check whether we need to add the flatten effect before
3217          each paint so that we can avoid having a mechanism for
3218          applications to notify when the value of the
3219          has_overlaps virtual changes. */
3220       add_or_remove_flatten_effect (self);
3221     }
3222   else
3223     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3224
3225   /* We save the current paint volume so that the next time the
3226    * actor queues a redraw we can constrain the redraw to just
3227    * cover the union of the new bounding box and the old.
3228    *
3229    * We also fetch the current paint volume to perform culling so
3230    * we can avoid painting actors outside the current clip region.
3231    *
3232    * If we are painting inside a clone, we should neither update
3233    * the paint volume or use it to cull painting, since the paint
3234    * box represents the location of the source actor on the
3235    * screen.
3236    *
3237    * XXX: We are starting to do a lot of vertex transforms on
3238    * the CPU in a typical paint, so at some point we should
3239    * audit these and consider caching some things.
3240    *
3241    * NB: We don't perform culling while picking at this point because
3242    * clutter-stage.c doesn't setup the clipping planes appropriately.
3243    *
3244    * NB: We don't want to update the last-paint-volume during picking
3245    * because the last-paint-volume is used to determine the old screen
3246    * space location of an actor that has moved so we can know the
3247    * minimal region to redraw to clear an old view of the actor. If we
3248    * update this during picking then by the time we come around to
3249    * paint then the last-paint-volume would likely represent the new
3250    * actor position not the old.
3251    */
3252   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3253     {
3254       gboolean success;
3255       /* annoyingly gcc warns if uninitialized even though
3256        * the initialization is redundant :-( */
3257       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3258
3259       if (G_LIKELY ((clutter_paint_debug_flags &
3260                      (CLUTTER_DEBUG_DISABLE_CULLING |
3261                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3262                     (CLUTTER_DEBUG_DISABLE_CULLING |
3263                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3264         _clutter_actor_update_last_paint_volume (self);
3265
3266       success = cull_actor (self, &result);
3267
3268       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3269         _clutter_actor_paint_cull_result (self, success, result);
3270       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3271         goto done;
3272     }
3273
3274   if (priv->effects == NULL)
3275     {
3276       if (pick_mode == CLUTTER_PICK_NONE &&
3277           actor_has_shader_data (self))
3278         {
3279           _clutter_actor_shader_pre_paint (self, FALSE);
3280           shader_applied = TRUE;
3281         }
3282
3283       priv->next_effect_to_paint = NULL;
3284     }
3285   else
3286     priv->next_effect_to_paint =
3287       _clutter_meta_group_peek_metas (priv->effects);
3288
3289   clutter_actor_continue_paint (self);
3290
3291   if (shader_applied)
3292     _clutter_actor_shader_post_paint (self);
3293
3294   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3295                   pick_mode == CLUTTER_PICK_NONE))
3296     _clutter_actor_draw_paint_volume (self);
3297
3298 done:
3299   /* If we make it here then the actor has run through a complete
3300      paint run including all the effects so it's no longer dirty */
3301   if (pick_mode == CLUTTER_PICK_NONE)
3302     priv->is_dirty = FALSE;
3303
3304   if (clip_set)
3305     cogl_clip_pop();
3306
3307   cogl_pop_matrix();
3308
3309   /* paint sequence complete */
3310   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3311 }
3312
3313 /**
3314  * clutter_actor_continue_paint:
3315  * @self: A #ClutterActor
3316  *
3317  * Run the next stage of the paint sequence. This function should only
3318  * be called within the implementation of the ‘run’ virtual of a
3319  * #ClutterEffect. It will cause the run method of the next effect to
3320  * be applied, or it will paint the actual actor if the current effect
3321  * is the last effect in the chain.
3322  *
3323  * Since: 1.8
3324  */
3325 void
3326 clutter_actor_continue_paint (ClutterActor *self)
3327 {
3328   ClutterActorPrivate *priv;
3329
3330   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3331   /* This should only be called from with in the ‘run’ implementation
3332      of a ClutterEffect */
3333   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3334
3335   priv = self->priv;
3336
3337   /* Skip any effects that are disabled */
3338   while (priv->next_effect_to_paint &&
3339          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3340     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3341
3342   /* If this has come from the last effect then we'll just paint the
3343      actual actor */
3344   if (priv->next_effect_to_paint == NULL)
3345     {
3346       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3347         {
3348           g_signal_emit (self, actor_signals[PAINT], 0);
3349         }
3350       else
3351         {
3352           ClutterColor col = { 0, };
3353
3354           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3355
3356           /* Actor will then paint silhouette of itself in supplied
3357            * color.  See clutter_stage_get_actor_at_pos() for where
3358            * picking is enabled.
3359            */
3360           g_signal_emit (self, actor_signals[PICK], 0, &col);
3361         }
3362     }
3363   else
3364     {
3365       ClutterEffect *old_current_effect;
3366       ClutterEffectPaintFlags run_flags = 0;
3367
3368       /* Cache the current effect so that we can put it back before
3369          returning */
3370       old_current_effect = priv->current_effect;
3371
3372       priv->current_effect = priv->next_effect_to_paint->data;
3373       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3374
3375       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3376         {
3377           if (priv->is_dirty)
3378             {
3379               /* If there's an effect queued with this redraw then all
3380                  effects up to that one will be considered dirty. It
3381                  is expected the queued effect will paint the cached
3382                  image and not call clutter_actor_continue_paint again
3383                  (although it should work ok if it does) */
3384               if (priv->effect_to_redraw == NULL ||
3385                   priv->current_effect != priv->effect_to_redraw)
3386                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3387             }
3388
3389           _clutter_effect_paint (priv->current_effect, run_flags);
3390         }
3391       else
3392         {
3393           /* We can't determine when an actor has been modified since
3394              its last pick so lets just assume it has always been
3395              modified */
3396           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3397
3398           _clutter_effect_pick (priv->current_effect, run_flags);
3399         }
3400
3401       priv->current_effect = old_current_effect;
3402     }
3403 }
3404
3405 static ClutterActorTraverseVisitFlags
3406 invalidate_queue_redraw_entry (ClutterActor *self,
3407                                int           depth,
3408                                gpointer      user_data)
3409 {
3410   ClutterActorPrivate *priv = self->priv;
3411
3412   if (priv->queue_redraw_entry != NULL)
3413     {
3414       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3415       priv->queue_redraw_entry = NULL;
3416     }
3417
3418   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3419 }
3420
3421 static inline void
3422 remove_child (ClutterActor *self,
3423               ClutterActor *child)
3424 {
3425   ClutterActor *prev_sibling, *next_sibling;
3426
3427   prev_sibling = child->priv->prev_sibling;
3428   next_sibling = child->priv->next_sibling;
3429
3430   if (prev_sibling != NULL)
3431     prev_sibling->priv->next_sibling = next_sibling;
3432
3433   if (next_sibling != NULL)
3434     next_sibling->priv->prev_sibling = prev_sibling;
3435
3436   if (self->priv->first_child == child)
3437     self->priv->first_child = next_sibling;
3438
3439   if (self->priv->last_child == child)
3440     self->priv->last_child = prev_sibling;
3441
3442   child->priv->parent = NULL;
3443   child->priv->prev_sibling = NULL;
3444   child->priv->next_sibling = NULL;
3445 }
3446
3447 typedef enum {
3448   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3449   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3450   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3451   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3452   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3453   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3454
3455   /* default flags for public API */
3456   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3457                                     REMOVE_CHILD_EMIT_PARENT_SET |
3458                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3459                                     REMOVE_CHILD_CHECK_STATE |
3460                                     REMOVE_CHILD_FLUSH_QUEUE |
3461                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3462
3463   /* flags for legacy/deprecated API */
3464   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3465                                     REMOVE_CHILD_FLUSH_QUEUE |
3466                                     REMOVE_CHILD_EMIT_PARENT_SET |
3467                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3468 } ClutterActorRemoveChildFlags;
3469
3470 /*< private >
3471  * clutter_actor_remove_child_internal:
3472  * @self: a #ClutterActor
3473  * @child: the child of @self that has to be removed
3474  * @flags: control the removal operations
3475  *
3476  * Removes @child from the list of children of @self.
3477  */
3478 static void
3479 clutter_actor_remove_child_internal (ClutterActor                 *self,
3480                                      ClutterActor                 *child,
3481                                      ClutterActorRemoveChildFlags  flags)
3482 {
3483   ClutterActor *old_first, *old_last;
3484   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3485   gboolean flush_queue;
3486   gboolean notify_first_last;
3487   gboolean was_mapped;
3488
3489   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3490   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3491   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3492   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3493   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3494   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3495
3496   g_object_freeze_notify (G_OBJECT (self));
3497
3498   if (destroy_meta)
3499     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3500
3501   if (check_state)
3502     {
3503       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3504
3505       /* we need to unrealize *before* we set parent_actor to NULL,
3506        * because in an unrealize method actors are dissociating from the
3507        * stage, which means they need to be able to
3508        * clutter_actor_get_stage().
3509        *
3510        * yhis should unmap and unrealize, unless we're reparenting.
3511        */
3512       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3513     }
3514   else
3515     was_mapped = FALSE;
3516
3517   if (flush_queue)
3518     {
3519       /* We take this opportunity to invalidate any queue redraw entry
3520        * associated with the actor and descendants since we won't be able to
3521        * determine the appropriate stage after this.
3522        *
3523        * we do this after we updated the mapped state because actors might
3524        * end up queueing redraws inside their mapped/unmapped virtual
3525        * functions, and if we invalidate the redraw entry we could end up
3526        * with an inconsistent state and weird memory corruption. see
3527        * bugs:
3528        *
3529        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3530        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3531        */
3532       _clutter_actor_traverse (child,
3533                                0,
3534                                invalidate_queue_redraw_entry,
3535                                NULL,
3536                                NULL);
3537     }
3538
3539   old_first = self->priv->first_child;
3540   old_last = self->priv->last_child;
3541
3542   remove_child (self, child);
3543
3544   self->priv->n_children -= 1;
3545
3546   self->priv->age += 1;
3547
3548   /* clutter_actor_reparent() will emit ::parent-set for us */
3549   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3550     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3551
3552   /* if the child was mapped then we need to relayout ourselves to account
3553    * for the removed child
3554    */
3555   if (was_mapped)
3556     clutter_actor_queue_relayout (self);
3557
3558   /* we need to emit the signal before dropping the reference */
3559   if (emit_actor_removed)
3560     g_signal_emit_by_name (self, "actor-removed", child);
3561
3562   if (notify_first_last)
3563     {
3564       if (old_first != self->priv->first_child)
3565         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3566
3567       if (old_last != self->priv->last_child)
3568         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3569     }
3570
3571   g_object_thaw_notify (G_OBJECT (self));
3572
3573   /* remove the reference we acquired in clutter_actor_add_child() */
3574   g_object_unref (child);
3575 }
3576
3577 static const ClutterTransformInfo default_transform_info = {
3578   0.0, { 0, },          /* rotation-x */
3579   0.0, { 0, },          /* rotation-y */
3580   0.0, { 0, },          /* rotation-z */
3581
3582   1.0, 1.0, { 0, },     /* scale */
3583
3584   { 0, },               /* anchor */
3585 };
3586
3587 /*< private >
3588  * _clutter_actor_get_transform_info_or_defaults:
3589  * @self: a #ClutterActor
3590  *
3591  * Retrieves the ClutterTransformInfo structure associated to an actor.
3592  *
3593  * If the actor does not have a ClutterTransformInfo structure associated
3594  * to it, then the default structure will be returned.
3595  *
3596  * This function should only be used for getters.
3597  *
3598  * Return value: a const pointer to the ClutterTransformInfo structure
3599  */
3600 const ClutterTransformInfo *
3601 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3602 {
3603   ClutterTransformInfo *info;
3604
3605   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3606   if (info != NULL)
3607     return info;
3608
3609   return &default_transform_info;
3610 }
3611
3612 static void
3613 clutter_transform_info_free (gpointer data)
3614 {
3615   if (data != NULL)
3616     g_slice_free (ClutterTransformInfo, data);
3617 }
3618
3619 /*< private >
3620  * _clutter_actor_get_transform_info:
3621  * @self: a #ClutterActor
3622  *
3623  * Retrieves a pointer to the ClutterTransformInfo structure.
3624  *
3625  * If the actor does not have a ClutterTransformInfo associated to it, one
3626  * will be created and initialized to the default values.
3627  *
3628  * This function should be used for setters.
3629  *
3630  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3631  * instead.
3632  *
3633  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3634  *   structure
3635  */
3636 ClutterTransformInfo *
3637 _clutter_actor_get_transform_info (ClutterActor *self)
3638 {
3639   ClutterTransformInfo *info;
3640
3641   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3642   if (info == NULL)
3643     {
3644       info = g_slice_new (ClutterTransformInfo);
3645
3646       *info = default_transform_info;
3647
3648       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3649                                info,
3650                                clutter_transform_info_free);
3651     }
3652
3653   return info;
3654 }
3655
3656 /*< private >
3657  * clutter_actor_set_rotation_angle_internal:
3658  * @self: a #ClutterActor
3659  * @axis: the axis of the angle to change
3660  * @angle: the angle of rotation
3661  *
3662  * Sets the rotation angle on the given axis without affecting the
3663  * rotation center point.
3664  */
3665 static inline void
3666 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3667                                            ClutterRotateAxis  axis,
3668                                            gdouble            angle)
3669 {
3670   GObject *obj = G_OBJECT (self);
3671   ClutterTransformInfo *info;
3672
3673   info = _clutter_actor_get_transform_info (self);
3674
3675   g_object_freeze_notify (obj);
3676
3677   switch (axis)
3678     {
3679     case CLUTTER_X_AXIS:
3680       info->rx_angle = angle;
3681       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3682       break;
3683
3684     case CLUTTER_Y_AXIS:
3685       info->ry_angle = angle;
3686       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3687       break;
3688
3689     case CLUTTER_Z_AXIS:
3690       info->rz_angle = angle;
3691       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3692       break;
3693     }
3694
3695   self->priv->transform_valid = FALSE;
3696
3697   g_object_thaw_notify (obj);
3698
3699   clutter_actor_queue_redraw (self);
3700 }
3701
3702 /*< private >
3703  * clutter_actor_set_rotation_center_internal:
3704  * @self: a #ClutterActor
3705  * @axis: the axis of the center to change
3706  * @center: the coordinates of the rotation center
3707  *
3708  * Sets the rotation center on the given axis without affecting the
3709  * rotation angle.
3710  */
3711 static inline void
3712 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3713                                             ClutterRotateAxis    axis,
3714                                             const ClutterVertex *center)
3715 {
3716   GObject *obj = G_OBJECT (self);
3717   ClutterTransformInfo *info;
3718   ClutterVertex v = { 0, 0, 0 };
3719
3720   info = _clutter_actor_get_transform_info (self);
3721
3722   if (center != NULL)
3723     v = *center;
3724
3725   g_object_freeze_notify (obj);
3726
3727   switch (axis)
3728     {
3729     case CLUTTER_X_AXIS:
3730       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3731       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3732       break;
3733
3734     case CLUTTER_Y_AXIS:
3735       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3736       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3737       break;
3738
3739     case CLUTTER_Z_AXIS:
3740       /* if the previously set rotation center was fractional, then
3741        * setting explicit coordinates will have to notify the
3742        * :rotation-center-z-gravity property as well
3743        */
3744       if (info->rz_center.is_fractional)
3745         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3746
3747       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3748       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3749       break;
3750     }
3751
3752   self->priv->transform_valid = FALSE;
3753
3754   g_object_thaw_notify (obj);
3755
3756   clutter_actor_queue_redraw (self);
3757 }
3758
3759 static inline void
3760 clutter_actor_set_scale_factor (ClutterActor      *self,
3761                                 ClutterRotateAxis  axis,
3762                                 gdouble            factor)
3763 {
3764   GObject *obj = G_OBJECT (self);
3765   ClutterTransformInfo *info;
3766
3767   info = _clutter_actor_get_transform_info (self);
3768
3769   g_object_freeze_notify (obj);
3770
3771   switch (axis)
3772     {
3773     case CLUTTER_X_AXIS:
3774       info->scale_x = factor;
3775       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
3776       break;
3777
3778     case CLUTTER_Y_AXIS:
3779       info->scale_y = factor;
3780       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
3781       break;
3782
3783     default:
3784       g_assert_not_reached ();
3785     }
3786
3787   self->priv->transform_valid = FALSE;
3788
3789   clutter_actor_queue_redraw (self);
3790
3791   g_object_thaw_notify (obj);
3792 }
3793
3794 static inline void
3795 clutter_actor_set_scale_center (ClutterActor      *self,
3796                                 ClutterRotateAxis  axis,
3797                                 gfloat             coord)
3798 {
3799   GObject *obj = G_OBJECT (self);
3800   ClutterTransformInfo *info;
3801   gfloat center_x, center_y;
3802
3803   info = _clutter_actor_get_transform_info (self);
3804
3805   g_object_freeze_notify (obj);
3806
3807   /* get the current scale center coordinates */
3808   clutter_anchor_coord_get_units (self, &info->scale_center,
3809                                   &center_x,
3810                                   &center_y,
3811                                   NULL);
3812
3813   /* we need to notify this too, because setting explicit coordinates will
3814    * change the gravity as a side effect
3815    */
3816   if (info->scale_center.is_fractional)
3817     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3818
3819   switch (axis)
3820     {
3821     case CLUTTER_X_AXIS:
3822       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3823       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3824       break;
3825
3826     case CLUTTER_Y_AXIS:
3827       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3828       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3829       break;
3830
3831     default:
3832       g_assert_not_reached ();
3833     }
3834
3835   self->priv->transform_valid = FALSE;
3836
3837   clutter_actor_queue_redraw (self);
3838
3839   g_object_thaw_notify (obj);
3840 }
3841
3842 static inline void
3843 clutter_actor_set_anchor_coord (ClutterActor      *self,
3844                                 ClutterRotateAxis  axis,
3845                                 gfloat             coord)
3846 {
3847   GObject *obj = G_OBJECT (self);
3848   ClutterTransformInfo *info;
3849   gfloat anchor_x, anchor_y;
3850
3851   info = _clutter_actor_get_transform_info (self);
3852
3853   g_object_freeze_notify (obj);
3854
3855   clutter_anchor_coord_get_units (self, &info->anchor,
3856                                   &anchor_x,
3857                                   &anchor_y,
3858                                   NULL);
3859
3860   if (info->anchor.is_fractional)
3861     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
3862
3863   switch (axis)
3864     {
3865     case CLUTTER_X_AXIS:
3866       clutter_anchor_coord_set_units (&info->anchor,
3867                                       coord,
3868                                       anchor_y,
3869                                       0.0);
3870       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
3871       break;
3872
3873     case CLUTTER_Y_AXIS:
3874       clutter_anchor_coord_set_units (&info->anchor,
3875                                       anchor_x,
3876                                       coord,
3877                                       0.0);
3878       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
3879       break;
3880
3881     default:
3882       g_assert_not_reached ();
3883     }
3884
3885   self->priv->transform_valid = FALSE;
3886
3887   clutter_actor_queue_redraw (self);
3888
3889   g_object_thaw_notify (obj);
3890 }
3891
3892 static void
3893 clutter_actor_set_property (GObject      *object,
3894                             guint         prop_id,
3895                             const GValue *value,
3896                             GParamSpec   *pspec)
3897 {
3898   ClutterActor *actor = CLUTTER_ACTOR (object);
3899   ClutterActorPrivate *priv = actor->priv;
3900
3901   switch (prop_id)
3902     {
3903     case PROP_X:
3904       clutter_actor_set_x (actor, g_value_get_float (value));
3905       break;
3906
3907     case PROP_Y:
3908       clutter_actor_set_y (actor, g_value_get_float (value));
3909       break;
3910
3911     case PROP_WIDTH:
3912       clutter_actor_set_width (actor, g_value_get_float (value));
3913       break;
3914
3915     case PROP_HEIGHT:
3916       clutter_actor_set_height (actor, g_value_get_float (value));
3917       break;
3918
3919     case PROP_FIXED_X:
3920       clutter_actor_set_x (actor, g_value_get_float (value));
3921       break;
3922
3923     case PROP_FIXED_Y:
3924       clutter_actor_set_y (actor, g_value_get_float (value));
3925       break;
3926
3927     case PROP_FIXED_POSITION_SET:
3928       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
3929       break;
3930
3931     case PROP_MIN_WIDTH:
3932       clutter_actor_set_min_width (actor, g_value_get_float (value));
3933       break;
3934
3935     case PROP_MIN_HEIGHT:
3936       clutter_actor_set_min_height (actor, g_value_get_float (value));
3937       break;
3938
3939     case PROP_NATURAL_WIDTH:
3940       clutter_actor_set_natural_width (actor, g_value_get_float (value));
3941       break;
3942
3943     case PROP_NATURAL_HEIGHT:
3944       clutter_actor_set_natural_height (actor, g_value_get_float (value));
3945       break;
3946
3947     case PROP_MIN_WIDTH_SET:
3948       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
3949       break;
3950
3951     case PROP_MIN_HEIGHT_SET:
3952       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
3953       break;
3954
3955     case PROP_NATURAL_WIDTH_SET:
3956       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
3957       break;
3958
3959     case PROP_NATURAL_HEIGHT_SET:
3960       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
3961       break;
3962
3963     case PROP_REQUEST_MODE:
3964       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
3965       break;
3966
3967     case PROP_DEPTH:
3968       clutter_actor_set_depth (actor, g_value_get_float (value));
3969       break;
3970
3971     case PROP_OPACITY:
3972       clutter_actor_set_opacity (actor, g_value_get_uint (value));
3973       break;
3974
3975     case PROP_OFFSCREEN_REDIRECT:
3976       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
3977       break;
3978
3979     case PROP_NAME:
3980       clutter_actor_set_name (actor, g_value_get_string (value));
3981       break;
3982
3983     case PROP_VISIBLE:
3984       if (g_value_get_boolean (value) == TRUE)
3985         clutter_actor_show (actor);
3986       else
3987         clutter_actor_hide (actor);
3988       break;
3989
3990     case PROP_SCALE_X:
3991       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
3992                                       g_value_get_double (value));
3993       break;
3994
3995     case PROP_SCALE_Y:
3996       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
3997                                       g_value_get_double (value));
3998       break;
3999
4000     case PROP_SCALE_CENTER_X:
4001       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4002                                       g_value_get_float (value));
4003       break;
4004
4005     case PROP_SCALE_CENTER_Y:
4006       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4007                                       g_value_get_float (value));
4008       break;
4009
4010     case PROP_SCALE_GRAVITY:
4011       {
4012         const ClutterTransformInfo *info;
4013         ClutterGravity gravity;
4014
4015         info = _clutter_actor_get_transform_info_or_defaults (actor);
4016         gravity = g_value_get_enum (value);
4017
4018         clutter_actor_set_scale_with_gravity (actor,
4019                                               info->scale_x,
4020                                               info->scale_y,
4021                                               gravity);
4022       }
4023       break;
4024
4025     case PROP_CLIP:
4026       {
4027         const ClutterGeometry *geom = g_value_get_boxed (value);
4028
4029         clutter_actor_set_clip (actor,
4030                                 geom->x, geom->y,
4031                                 geom->width, geom->height);
4032       }
4033       break;
4034
4035     case PROP_CLIP_TO_ALLOCATION:
4036       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4037       break;
4038
4039     case PROP_REACTIVE:
4040       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4041       break;
4042
4043     case PROP_ROTATION_ANGLE_X:
4044       clutter_actor_set_rotation_angle_internal (actor,
4045                                                  CLUTTER_X_AXIS,
4046                                                  g_value_get_double (value));
4047       break;
4048
4049     case PROP_ROTATION_ANGLE_Y:
4050       clutter_actor_set_rotation_angle_internal (actor,
4051                                                  CLUTTER_Y_AXIS,
4052                                                  g_value_get_double (value));
4053       break;
4054
4055     case PROP_ROTATION_ANGLE_Z:
4056       clutter_actor_set_rotation_angle_internal (actor,
4057                                                  CLUTTER_Z_AXIS,
4058                                                  g_value_get_double (value));
4059       break;
4060
4061     case PROP_ROTATION_CENTER_X:
4062       clutter_actor_set_rotation_center_internal (actor,
4063                                                   CLUTTER_X_AXIS,
4064                                                   g_value_get_boxed (value));
4065       break;
4066
4067     case PROP_ROTATION_CENTER_Y:
4068       clutter_actor_set_rotation_center_internal (actor,
4069                                                   CLUTTER_Y_AXIS,
4070                                                   g_value_get_boxed (value));
4071       break;
4072
4073     case PROP_ROTATION_CENTER_Z:
4074       clutter_actor_set_rotation_center_internal (actor,
4075                                                   CLUTTER_Z_AXIS,
4076                                                   g_value_get_boxed (value));
4077       break;
4078
4079     case PROP_ROTATION_CENTER_Z_GRAVITY:
4080       {
4081         const ClutterTransformInfo *info;
4082
4083         info = _clutter_actor_get_transform_info_or_defaults (actor);
4084         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4085                                                    g_value_get_enum (value));
4086       }
4087       break;
4088
4089     case PROP_ANCHOR_X:
4090       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4091                                       g_value_get_float (value));
4092       break;
4093
4094     case PROP_ANCHOR_Y:
4095       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4096                                       g_value_get_float (value));
4097       break;
4098
4099     case PROP_ANCHOR_GRAVITY:
4100       clutter_actor_set_anchor_point_from_gravity (actor,
4101                                                    g_value_get_enum (value));
4102       break;
4103
4104     case PROP_SHOW_ON_SET_PARENT:
4105       priv->show_on_set_parent = g_value_get_boolean (value);
4106       break;
4107
4108     case PROP_TEXT_DIRECTION:
4109       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4110       break;
4111
4112     case PROP_ACTIONS:
4113       clutter_actor_add_action (actor, g_value_get_object (value));
4114       break;
4115
4116     case PROP_CONSTRAINTS:
4117       clutter_actor_add_constraint (actor, g_value_get_object (value));
4118       break;
4119
4120     case PROP_EFFECT:
4121       clutter_actor_add_effect (actor, g_value_get_object (value));
4122       break;
4123
4124     case PROP_LAYOUT_MANAGER:
4125       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4126       break;
4127
4128     case PROP_X_ALIGN:
4129       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4130       break;
4131
4132     case PROP_Y_ALIGN:
4133       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4134       break;
4135
4136     case PROP_MARGIN_TOP:
4137       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4138       break;
4139
4140     case PROP_MARGIN_BOTTOM:
4141       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4142       break;
4143
4144     case PROP_MARGIN_LEFT:
4145       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4146       break;
4147
4148     case PROP_MARGIN_RIGHT:
4149       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4150       break;
4151
4152     case PROP_BACKGROUND_COLOR:
4153       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4154       break;
4155
4156     default:
4157       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4158       break;
4159     }
4160 }
4161
4162 static void
4163 clutter_actor_get_property (GObject    *object,
4164                             guint       prop_id,
4165                             GValue     *value,
4166                             GParamSpec *pspec)
4167 {
4168   ClutterActor *actor = CLUTTER_ACTOR (object);
4169   ClutterActorPrivate *priv = actor->priv;
4170
4171   switch (prop_id)
4172     {
4173     case PROP_X:
4174       g_value_set_float (value, clutter_actor_get_x (actor));
4175       break;
4176
4177     case PROP_Y:
4178       g_value_set_float (value, clutter_actor_get_y (actor));
4179       break;
4180
4181     case PROP_WIDTH:
4182       g_value_set_float (value, clutter_actor_get_width (actor));
4183       break;
4184
4185     case PROP_HEIGHT:
4186       g_value_set_float (value, clutter_actor_get_height (actor));
4187       break;
4188
4189     case PROP_FIXED_X:
4190       {
4191         const ClutterLayoutInfo *info;
4192
4193         info = _clutter_actor_get_layout_info_or_defaults (actor);
4194         g_value_set_float (value, info->fixed_x);
4195       }
4196       break;
4197
4198     case PROP_FIXED_Y:
4199       {
4200         const ClutterLayoutInfo *info;
4201
4202         info = _clutter_actor_get_layout_info_or_defaults (actor);
4203         g_value_set_float (value, info->fixed_y);
4204       }
4205       break;
4206
4207     case PROP_FIXED_POSITION_SET:
4208       g_value_set_boolean (value, priv->position_set);
4209       break;
4210
4211     case PROP_MIN_WIDTH:
4212       {
4213         const ClutterLayoutInfo *info;
4214
4215         info = _clutter_actor_get_layout_info_or_defaults (actor);
4216         g_value_set_float (value, info->min_width);
4217       }
4218       break;
4219
4220     case PROP_MIN_HEIGHT:
4221       {
4222         const ClutterLayoutInfo *info;
4223
4224         info = _clutter_actor_get_layout_info_or_defaults (actor);
4225         g_value_set_float (value, info->min_height);
4226       }
4227       break;
4228
4229     case PROP_NATURAL_WIDTH:
4230       {
4231         const ClutterLayoutInfo *info;
4232
4233         info = _clutter_actor_get_layout_info_or_defaults (actor);
4234         g_value_set_float (value, info->natural_width);
4235       }
4236       break;
4237
4238     case PROP_NATURAL_HEIGHT:
4239       {
4240         const ClutterLayoutInfo *info;
4241
4242         info = _clutter_actor_get_layout_info_or_defaults (actor);
4243         g_value_set_float (value, info->natural_height);
4244       }
4245       break;
4246
4247     case PROP_MIN_WIDTH_SET:
4248       g_value_set_boolean (value, priv->min_width_set);
4249       break;
4250
4251     case PROP_MIN_HEIGHT_SET:
4252       g_value_set_boolean (value, priv->min_height_set);
4253       break;
4254
4255     case PROP_NATURAL_WIDTH_SET:
4256       g_value_set_boolean (value, priv->natural_width_set);
4257       break;
4258
4259     case PROP_NATURAL_HEIGHT_SET:
4260       g_value_set_boolean (value, priv->natural_height_set);
4261       break;
4262
4263     case PROP_REQUEST_MODE:
4264       g_value_set_enum (value, priv->request_mode);
4265       break;
4266
4267     case PROP_ALLOCATION:
4268       g_value_set_boxed (value, &priv->allocation);
4269       break;
4270
4271     case PROP_DEPTH:
4272       g_value_set_float (value, clutter_actor_get_depth (actor));
4273       break;
4274
4275     case PROP_OPACITY:
4276       g_value_set_uint (value, priv->opacity);
4277       break;
4278
4279     case PROP_OFFSCREEN_REDIRECT:
4280       g_value_set_enum (value, priv->offscreen_redirect);
4281       break;
4282
4283     case PROP_NAME:
4284       g_value_set_string (value, priv->name);
4285       break;
4286
4287     case PROP_VISIBLE:
4288       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4289       break;
4290
4291     case PROP_MAPPED:
4292       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4293       break;
4294
4295     case PROP_REALIZED:
4296       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4297       break;
4298
4299     case PROP_HAS_CLIP:
4300       g_value_set_boolean (value, priv->has_clip);
4301       break;
4302
4303     case PROP_CLIP:
4304       {
4305         ClutterGeometry clip;
4306
4307         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4308         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4309         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4310         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4311
4312         g_value_set_boxed (value, &clip);
4313       }
4314       break;
4315
4316     case PROP_CLIP_TO_ALLOCATION:
4317       g_value_set_boolean (value, priv->clip_to_allocation);
4318       break;
4319
4320     case PROP_SCALE_X:
4321       {
4322         const ClutterTransformInfo *info;
4323
4324         info = _clutter_actor_get_transform_info_or_defaults (actor);
4325         g_value_set_double (value, info->scale_x);
4326       }
4327       break;
4328
4329     case PROP_SCALE_Y:
4330       {
4331         const ClutterTransformInfo *info;
4332
4333         info = _clutter_actor_get_transform_info_or_defaults (actor);
4334         g_value_set_double (value, info->scale_y);
4335       }
4336       break;
4337
4338     case PROP_SCALE_CENTER_X:
4339       {
4340         gfloat center;
4341
4342         clutter_actor_get_scale_center (actor, &center, NULL);
4343
4344         g_value_set_float (value, center);
4345       }
4346       break;
4347
4348     case PROP_SCALE_CENTER_Y:
4349       {
4350         gfloat center;
4351
4352         clutter_actor_get_scale_center (actor, NULL, &center);
4353
4354         g_value_set_float (value, center);
4355       }
4356       break;
4357
4358     case PROP_SCALE_GRAVITY:
4359       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4360       break;
4361
4362     case PROP_REACTIVE:
4363       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4364       break;
4365
4366     case PROP_ROTATION_ANGLE_X:
4367       {
4368         const ClutterTransformInfo *info;
4369
4370         info = _clutter_actor_get_transform_info_or_defaults (actor);
4371         g_value_set_double (value, info->rx_angle);
4372       }
4373       break;
4374
4375     case PROP_ROTATION_ANGLE_Y:
4376       {
4377         const ClutterTransformInfo *info;
4378
4379         info = _clutter_actor_get_transform_info_or_defaults (actor);
4380         g_value_set_double (value, info->ry_angle);
4381       }
4382       break;
4383
4384     case PROP_ROTATION_ANGLE_Z:
4385       {
4386         const ClutterTransformInfo *info;
4387
4388         info = _clutter_actor_get_transform_info_or_defaults (actor);
4389         g_value_set_double (value, info->rz_angle);
4390       }
4391       break;
4392
4393     case PROP_ROTATION_CENTER_X:
4394       {
4395         ClutterVertex center;
4396
4397         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4398                                     &center.x,
4399                                     &center.y,
4400                                     &center.z);
4401
4402         g_value_set_boxed (value, &center);
4403       }
4404       break;
4405
4406     case PROP_ROTATION_CENTER_Y:
4407       {
4408         ClutterVertex center;
4409
4410         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4411                                     &center.x,
4412                                     &center.y,
4413                                     &center.z);
4414
4415         g_value_set_boxed (value, &center);
4416       }
4417       break;
4418
4419     case PROP_ROTATION_CENTER_Z:
4420       {
4421         ClutterVertex center;
4422
4423         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4424                                     &center.x,
4425                                     &center.y,
4426                                     &center.z);
4427
4428         g_value_set_boxed (value, &center);
4429       }
4430       break;
4431
4432     case PROP_ROTATION_CENTER_Z_GRAVITY:
4433       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4434       break;
4435
4436     case PROP_ANCHOR_X:
4437       {
4438         const ClutterTransformInfo *info;
4439         gfloat anchor_x;
4440
4441         info = _clutter_actor_get_transform_info_or_defaults (actor);
4442         clutter_anchor_coord_get_units (actor, &info->anchor,
4443                                         &anchor_x,
4444                                         NULL,
4445                                         NULL);
4446         g_value_set_float (value, anchor_x);
4447       }
4448       break;
4449
4450     case PROP_ANCHOR_Y:
4451       {
4452         const ClutterTransformInfo *info;
4453         gfloat anchor_y;
4454
4455         info = _clutter_actor_get_transform_info_or_defaults (actor);
4456         clutter_anchor_coord_get_units (actor, &info->anchor,
4457                                         NULL,
4458                                         &anchor_y,
4459                                         NULL);
4460         g_value_set_float (value, anchor_y);
4461       }
4462       break;
4463
4464     case PROP_ANCHOR_GRAVITY:
4465       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4466       break;
4467
4468     case PROP_SHOW_ON_SET_PARENT:
4469       g_value_set_boolean (value, priv->show_on_set_parent);
4470       break;
4471
4472     case PROP_TEXT_DIRECTION:
4473       g_value_set_enum (value, priv->text_direction);
4474       break;
4475
4476     case PROP_HAS_POINTER:
4477       g_value_set_boolean (value, priv->has_pointer);
4478       break;
4479
4480     case PROP_LAYOUT_MANAGER:
4481       g_value_set_object (value, priv->layout_manager);
4482       break;
4483
4484     case PROP_X_ALIGN:
4485       {
4486         const ClutterLayoutInfo *info;
4487
4488         info = _clutter_actor_get_layout_info_or_defaults (actor);
4489         g_value_set_enum (value, info->x_align);
4490       }
4491       break;
4492
4493     case PROP_Y_ALIGN:
4494       {
4495         const ClutterLayoutInfo *info;
4496
4497         info = _clutter_actor_get_layout_info_or_defaults (actor);
4498         g_value_set_enum (value, info->y_align);
4499       }
4500       break;
4501
4502     case PROP_MARGIN_TOP:
4503       {
4504         const ClutterLayoutInfo *info;
4505
4506         info = _clutter_actor_get_layout_info_or_defaults (actor);
4507         g_value_set_float (value, info->margin.top);
4508       }
4509       break;
4510
4511     case PROP_MARGIN_BOTTOM:
4512       {
4513         const ClutterLayoutInfo *info;
4514
4515         info = _clutter_actor_get_layout_info_or_defaults (actor);
4516         g_value_set_float (value, info->margin.bottom);
4517       }
4518       break;
4519
4520     case PROP_MARGIN_LEFT:
4521       {
4522         const ClutterLayoutInfo *info;
4523
4524         info = _clutter_actor_get_layout_info_or_defaults (actor);
4525         g_value_set_float (value, info->margin.left);
4526       }
4527       break;
4528
4529     case PROP_MARGIN_RIGHT:
4530       {
4531         const ClutterLayoutInfo *info;
4532
4533         info = _clutter_actor_get_layout_info_or_defaults (actor);
4534         g_value_set_float (value, info->margin.right);
4535       }
4536       break;
4537
4538     case PROP_BACKGROUND_COLOR_SET:
4539       g_value_set_boolean (value, priv->bg_color_set);
4540       break;
4541
4542     case PROP_BACKGROUND_COLOR:
4543       g_value_set_boxed (value, &priv->bg_color);
4544       break;
4545
4546     case PROP_FIRST_CHILD:
4547       g_value_set_object (value, priv->first_child);
4548       break;
4549
4550     case PROP_LAST_CHILD:
4551       g_value_set_object (value, priv->last_child);
4552       break;
4553
4554     default:
4555       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4556       break;
4557     }
4558 }
4559
4560 static void
4561 clutter_actor_dispose (GObject *object)
4562 {
4563   ClutterActor *self = CLUTTER_ACTOR (object);
4564   ClutterActorPrivate *priv = self->priv;
4565
4566   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4567                 priv->id,
4568                 g_type_name (G_OBJECT_TYPE (self)),
4569                 object->ref_count);
4570
4571   g_signal_emit (self, actor_signals[DESTROY], 0);
4572
4573   /* avoid recursing when called from clutter_actor_destroy() */
4574   if (priv->parent != NULL)
4575     {
4576       ClutterActor *parent = priv->parent;
4577
4578       /* go through the Container implementation unless this
4579        * is an internal child and has been marked as such.
4580        *
4581        * removing the actor from its parent will reset the
4582        * realized and mapped states.
4583        */
4584       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4585         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4586       else
4587         clutter_actor_remove_child_internal (parent, self,
4588                                              REMOVE_CHILD_LEGACY_FLAGS);
4589     }
4590
4591   /* parent must be gone at this point */
4592   g_assert (priv->parent == NULL);
4593
4594   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4595     {
4596       /* can't be mapped or realized with no parent */
4597       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4598       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4599     }
4600
4601   g_clear_object (&priv->pango_context);
4602   g_clear_object (&priv->actions);
4603   g_clear_object (&priv->constraints);
4604   g_clear_object (&priv->effects);
4605   g_clear_object (&priv->flatten_effect);
4606
4607   if (priv->layout_manager != NULL)
4608     {
4609       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4610       g_object_unref (priv->layout_manager);
4611       priv->layout_manager = NULL;
4612     }
4613
4614   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4615 }
4616
4617 static void
4618 clutter_actor_finalize (GObject *object)
4619 {
4620   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4621
4622   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4623                 priv->name != NULL ? priv->name : "<none>",
4624                 priv->id,
4625                 g_type_name (G_OBJECT_TYPE (object)));
4626
4627   _clutter_context_release_id (priv->id);
4628
4629   g_free (priv->name);
4630
4631   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4632 }
4633
4634
4635 /**
4636  * clutter_actor_get_accessible:
4637  * @self: a #ClutterActor
4638  *
4639  * Returns the accessible object that describes the actor to an
4640  * assistive technology.
4641  *
4642  * If no class-specific #AtkObject implementation is available for the
4643  * actor instance in question, it will inherit an #AtkObject
4644  * implementation from the first ancestor class for which such an
4645  * implementation is defined.
4646  *
4647  * The documentation of the <ulink
4648  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4649  * library contains more information about accessible objects and
4650  * their uses.
4651  *
4652  * Returns: (transfer none): the #AtkObject associated with @actor
4653  */
4654 AtkObject *
4655 clutter_actor_get_accessible (ClutterActor *self)
4656 {
4657   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4658
4659   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4660 }
4661
4662 static AtkObject *
4663 clutter_actor_real_get_accessible (ClutterActor *actor)
4664 {
4665   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4666 }
4667
4668 static AtkObject *
4669 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4670 {
4671   AtkObject *accessible;
4672
4673   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4674   if (accessible != NULL)
4675     g_object_ref (accessible);
4676
4677   return accessible;
4678 }
4679
4680 static void
4681 atk_implementor_iface_init (AtkImplementorIface *iface)
4682 {
4683   iface->ref_accessible = _clutter_actor_ref_accessible;
4684 }
4685
4686 static gboolean
4687 clutter_actor_update_default_paint_volume (ClutterActor       *self,
4688                                            ClutterPaintVolume *volume)
4689 {
4690   ClutterActorPrivate *priv = self->priv;
4691   gboolean res = FALSE;
4692
4693   /* we start from the allocation */
4694   clutter_paint_volume_set_width (volume,
4695                                   priv->allocation.x2 - priv->allocation.x1);
4696   clutter_paint_volume_set_height (volume,
4697                                    priv->allocation.y2 - priv->allocation.y1);
4698
4699   /* if the actor has a clip set then we have a pretty definite
4700    * size for the paint volume: the actor cannot possibly paint
4701    * outside the clip region.
4702    */
4703   if (priv->clip_to_allocation)
4704     {
4705       /* the allocation has already been set, so we just flip the
4706        * return value
4707        */
4708       res = TRUE;
4709     }
4710   else
4711     {
4712       ClutterActor *child;
4713
4714       if (priv->has_clip &&
4715           priv->clip.width >= 0 &&
4716           priv->clip.height >= 0)
4717         {
4718           ClutterVertex origin;
4719
4720           origin.x = priv->clip.x;
4721           origin.y = priv->clip.y;
4722           origin.z = 0;
4723
4724           clutter_paint_volume_set_origin (volume, &origin);
4725           clutter_paint_volume_set_width (volume, priv->clip.width);
4726           clutter_paint_volume_set_height (volume, priv->clip.height);
4727
4728           res = TRUE;
4729         }
4730
4731       /* if we don't have children we just bail out here... */
4732       if (priv->n_children == 0)
4733         return res;
4734
4735       /* ...but if we have children then we ask for their paint volume in
4736        * our coordinates. if any of our children replies that it doesn't
4737        * have a paint volume, we bail out
4738        */
4739       for (child = priv->first_child;
4740            child != NULL;
4741            child = child->priv->next_sibling)
4742         {
4743           const ClutterPaintVolume *child_volume;
4744
4745           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4746           if (child_volume == NULL)
4747             {
4748               res = FALSE;
4749               break;
4750             }
4751
4752           clutter_paint_volume_union (volume, child_volume);
4753           res = TRUE;
4754         }
4755     }
4756
4757   return res;
4758
4759 }
4760
4761 static gboolean
4762 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4763                                      ClutterPaintVolume *volume)
4764 {
4765   ClutterActorClass *klass;
4766   gboolean res;
4767
4768   klass = CLUTTER_ACTOR_GET_CLASS (self);
4769
4770   /* XXX - this thoroughly sucks, but we don't want to penalize users
4771    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
4772    * redraw. This should go away in 2.0.
4773    */
4774   if (klass->paint == clutter_actor_real_paint &&
4775       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
4776     {
4777       res = TRUE;
4778     }
4779   else
4780     {
4781       /* this is the default return value: we cannot know if a class
4782        * is going to paint outside its allocation, so we take the
4783        * conservative approach.
4784        */
4785       res = FALSE;
4786     }
4787
4788   if (clutter_actor_update_default_paint_volume (self, volume))
4789     return res;
4790
4791   return FALSE;
4792 }
4793
4794 /**
4795  * clutter_actor_get_default_paint_volume:
4796  * @self: a #ClutterActor
4797  *
4798  * Retrieves the default paint volume for @self.
4799  *
4800  * This function provides the same #ClutterPaintVolume that would be
4801  * computed by the default implementation inside #ClutterActor of the
4802  * #ClutterActorClass.get_paint_volume() virtual function.
4803  *
4804  * This function should only be used by #ClutterActor subclasses that
4805  * cannot chain up to the parent implementation when computing their
4806  * paint volume.
4807  *
4808  * Return value: (transfer none): a pointer to the default
4809  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
4810  *   the actor could not compute a valid paint volume. The returned value
4811  *   is not guaranteed to be stable across multiple frames, so if you
4812  *   want to retain it, you will need to copy it using
4813  *   clutter_paint_volume_copy().
4814  *
4815  * Since: 1.10
4816  */
4817 const ClutterPaintVolume *
4818 clutter_actor_get_default_paint_volume (ClutterActor *self)
4819 {
4820   ClutterPaintVolume volume;
4821   ClutterPaintVolume *res;
4822
4823   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4824
4825   res = NULL;
4826   _clutter_paint_volume_init_static (&volume, self);
4827   if (clutter_actor_update_default_paint_volume (self, &volume))
4828     {
4829       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
4830
4831       if (stage != NULL)
4832         {
4833           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
4834           _clutter_paint_volume_copy_static (&volume, res);
4835         }
4836     }
4837
4838   clutter_paint_volume_free (&volume);
4839
4840   return res;
4841 }
4842
4843 static gboolean
4844 clutter_actor_real_has_overlaps (ClutterActor *self)
4845 {
4846   /* By default we'll assume that all actors need an offscreen redirect to get
4847    * the correct opacity. Actors such as ClutterTexture that would never need
4848    * an offscreen redirect can override this to return FALSE. */
4849   return TRUE;
4850 }
4851
4852 static void
4853 clutter_actor_real_destroy (ClutterActor *actor)
4854 {
4855   ClutterActorIter iter;
4856
4857   clutter_actor_iter_init (&iter, actor);
4858   while (clutter_actor_iter_next (&iter, NULL))
4859     clutter_actor_iter_destroy (&iter);
4860 }
4861
4862 static GObject *
4863 clutter_actor_constructor (GType gtype,
4864                            guint n_props,
4865                            GObjectConstructParam *props)
4866 {
4867   GObjectClass *gobject_class;
4868   ClutterActor *self;
4869   GObject *retval;
4870
4871   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
4872   retval = gobject_class->constructor (gtype, n_props, props);
4873   self = CLUTTER_ACTOR (retval);
4874
4875   if (self->priv->layout_manager == NULL)
4876     {
4877       ClutterLayoutManager *default_layout;
4878
4879       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
4880
4881       default_layout = clutter_fixed_layout_new ();
4882       clutter_actor_set_layout_manager (self, default_layout);
4883     }
4884
4885   return retval;
4886 }
4887
4888 static void
4889 clutter_actor_class_init (ClutterActorClass *klass)
4890 {
4891   GObjectClass *object_class = G_OBJECT_CLASS (klass);
4892
4893   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
4894   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
4895   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
4896
4897   object_class->constructor = clutter_actor_constructor;
4898   object_class->set_property = clutter_actor_set_property;
4899   object_class->get_property = clutter_actor_get_property;
4900   object_class->dispose = clutter_actor_dispose;
4901   object_class->finalize = clutter_actor_finalize;
4902
4903   klass->show = clutter_actor_real_show;
4904   klass->show_all = clutter_actor_show;
4905   klass->hide = clutter_actor_real_hide;
4906   klass->hide_all = clutter_actor_hide;
4907   klass->map = clutter_actor_real_map;
4908   klass->unmap = clutter_actor_real_unmap;
4909   klass->unrealize = clutter_actor_real_unrealize;
4910   klass->pick = clutter_actor_real_pick;
4911   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
4912   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4913   klass->allocate = clutter_actor_real_allocate;
4914   klass->queue_redraw = clutter_actor_real_queue_redraw;
4915   klass->queue_relayout = clutter_actor_real_queue_relayout;
4916   klass->apply_transform = clutter_actor_real_apply_transform;
4917   klass->get_accessible = clutter_actor_real_get_accessible;
4918   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
4919   klass->has_overlaps = clutter_actor_real_has_overlaps;
4920   klass->paint = clutter_actor_real_paint;
4921   klass->destroy = clutter_actor_real_destroy;
4922
4923   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
4924
4925   /**
4926    * ClutterActor:x:
4927    *
4928    * X coordinate of the actor in pixels. If written, forces a fixed
4929    * position for the actor. If read, returns the fixed position if any,
4930    * otherwise the allocation if available, otherwise 0.
4931    */
4932   obj_props[PROP_X] =
4933     g_param_spec_float ("x",
4934                         P_("X coordinate"),
4935                         P_("X coordinate of the actor"),
4936                         -G_MAXFLOAT, G_MAXFLOAT,
4937                         0.0,
4938                         CLUTTER_PARAM_READWRITE);
4939
4940   /**
4941    * ClutterActor:y:
4942    *
4943    * Y coordinate of the actor in pixels. If written, forces a fixed
4944    * position for the actor.  If read, returns the fixed position if
4945    * any, otherwise the allocation if available, otherwise 0.
4946    */
4947   obj_props[PROP_Y] =
4948     g_param_spec_float ("y",
4949                         P_("Y coordinate"),
4950                         P_("Y coordinate of the actor"),
4951                         -G_MAXFLOAT, G_MAXFLOAT,
4952                         0.0,
4953                         CLUTTER_PARAM_READWRITE);
4954
4955   /**
4956    * ClutterActor:width:
4957    *
4958    * Width of the actor (in pixels). If written, forces the minimum and
4959    * natural size request of the actor to the given width. If read, returns
4960    * the allocated width if available, otherwise the width request.
4961    */
4962   obj_props[PROP_WIDTH] =
4963     g_param_spec_float ("width",
4964                         P_("Width"),
4965                         P_("Width of the actor"),
4966                         0.0, G_MAXFLOAT,
4967                         0.0,
4968                         CLUTTER_PARAM_READWRITE);
4969
4970   /**
4971    * ClutterActor:height:
4972    *
4973    * Height of the actor (in pixels).  If written, forces the minimum and
4974    * natural size request of the actor to the given height. If read, returns
4975    * the allocated height if available, otherwise the height request.
4976    */
4977   obj_props[PROP_HEIGHT] =
4978     g_param_spec_float ("height",
4979                         P_("Height"),
4980                         P_("Height of the actor"),
4981                         0.0, G_MAXFLOAT,
4982                         0.0,
4983                         CLUTTER_PARAM_READWRITE);
4984
4985   /**
4986    * ClutterActor:fixed-x:
4987    *
4988    * The fixed X position of the actor in pixels.
4989    *
4990    * Writing this property sets #ClutterActor:fixed-position-set
4991    * property as well, as a side effect
4992    *
4993    * Since: 0.8
4994    */
4995   obj_props[PROP_FIXED_X] =
4996     g_param_spec_float ("fixed-x",
4997                         P_("Fixed X"),
4998                         P_("Forced X position of the actor"),
4999                         -G_MAXFLOAT, G_MAXFLOAT,
5000                         0.0,
5001                         CLUTTER_PARAM_READWRITE);
5002
5003   /**
5004    * ClutterActor:fixed-y:
5005    *
5006    * The fixed Y position of the actor in pixels.
5007    *
5008    * Writing this property sets the #ClutterActor:fixed-position-set
5009    * property as well, as a side effect
5010    *
5011    * Since: 0.8
5012    */
5013   obj_props[PROP_FIXED_Y] =
5014     g_param_spec_float ("fixed-y",
5015                         P_("Fixed Y"),
5016                         P_("Forced Y position of the actor"),
5017                         -G_MAXFLOAT, G_MAXFLOAT,
5018                         0,
5019                         CLUTTER_PARAM_READWRITE);
5020
5021   /**
5022    * ClutterActor:fixed-position-set:
5023    *
5024    * This flag controls whether the #ClutterActor:fixed-x and
5025    * #ClutterActor:fixed-y properties are used
5026    *
5027    * Since: 0.8
5028    */
5029   obj_props[PROP_FIXED_POSITION_SET] =
5030     g_param_spec_boolean ("fixed-position-set",
5031                           P_("Fixed position set"),
5032                           P_("Whether to use fixed positioning for the actor"),
5033                           FALSE,
5034                           CLUTTER_PARAM_READWRITE);
5035
5036   /**
5037    * ClutterActor:min-width:
5038    *
5039    * A forced minimum width request for the actor, in pixels
5040    *
5041    * Writing this property sets the #ClutterActor:min-width-set property
5042    * as well, as a side effect.
5043    *
5044    *This property overrides the usual width request of the actor.
5045    *
5046    * Since: 0.8
5047    */
5048   obj_props[PROP_MIN_WIDTH] =
5049     g_param_spec_float ("min-width",
5050                         P_("Min Width"),
5051                         P_("Forced minimum width request for the actor"),
5052                         0.0, G_MAXFLOAT,
5053                         0.0,
5054                         CLUTTER_PARAM_READWRITE);
5055
5056   /**
5057    * ClutterActor:min-height:
5058    *
5059    * A forced minimum height request for the actor, in pixels
5060    *
5061    * Writing this property sets the #ClutterActor:min-height-set property
5062    * as well, as a side effect. This property overrides the usual height
5063    * request of the actor.
5064    *
5065    * Since: 0.8
5066    */
5067   obj_props[PROP_MIN_HEIGHT] =
5068     g_param_spec_float ("min-height",
5069                         P_("Min Height"),
5070                         P_("Forced minimum height request for the actor"),
5071                         0.0, G_MAXFLOAT,
5072                         0.0,
5073                         CLUTTER_PARAM_READWRITE);
5074
5075   /**
5076    * ClutterActor:natural-width:
5077    *
5078    * A forced natural width request for the actor, in pixels
5079    *
5080    * Writing this property sets the #ClutterActor:natural-width-set
5081    * property as well, as a side effect. This property overrides the
5082    * usual width request of the actor
5083    *
5084    * Since: 0.8
5085    */
5086   obj_props[PROP_NATURAL_WIDTH] =
5087     g_param_spec_float ("natural-width",
5088                         P_("Natural Width"),
5089                         P_("Forced natural width request for the actor"),
5090                         0.0, G_MAXFLOAT,
5091                         0.0,
5092                         CLUTTER_PARAM_READWRITE);
5093
5094   /**
5095    * ClutterActor:natural-height:
5096    *
5097    * A forced natural height request for the actor, in pixels
5098    *
5099    * Writing this property sets the #ClutterActor:natural-height-set
5100    * property as well, as a side effect. This property overrides the
5101    * usual height request of the actor
5102    *
5103    * Since: 0.8
5104    */
5105   obj_props[PROP_NATURAL_HEIGHT] =
5106     g_param_spec_float ("natural-height",
5107                         P_("Natural Height"),
5108                         P_("Forced natural height request for the actor"),
5109                         0.0, G_MAXFLOAT,
5110                         0.0,
5111                         CLUTTER_PARAM_READWRITE);
5112
5113   /**
5114    * ClutterActor:min-width-set:
5115    *
5116    * This flag controls whether the #ClutterActor:min-width property
5117    * is used
5118    *
5119    * Since: 0.8
5120    */
5121   obj_props[PROP_MIN_WIDTH_SET] =
5122     g_param_spec_boolean ("min-width-set",
5123                           P_("Minimum width set"),
5124                           P_("Whether to use the min-width property"),
5125                           FALSE,
5126                           CLUTTER_PARAM_READWRITE);
5127
5128   /**
5129    * ClutterActor:min-height-set:
5130    *
5131    * This flag controls whether the #ClutterActor:min-height property
5132    * is used
5133    *
5134    * Since: 0.8
5135    */
5136   obj_props[PROP_MIN_HEIGHT_SET] =
5137     g_param_spec_boolean ("min-height-set",
5138                           P_("Minimum height set"),
5139                           P_("Whether to use the min-height property"),
5140                           FALSE,
5141                           CLUTTER_PARAM_READWRITE);
5142
5143   /**
5144    * ClutterActor:natural-width-set:
5145    *
5146    * This flag controls whether the #ClutterActor:natural-width property
5147    * is used
5148    *
5149    * Since: 0.8
5150    */
5151   obj_props[PROP_NATURAL_WIDTH_SET] =
5152     g_param_spec_boolean ("natural-width-set",
5153                           P_("Natural width set"),
5154                           P_("Whether to use the natural-width property"),
5155                           FALSE,
5156                           CLUTTER_PARAM_READWRITE);
5157
5158   /**
5159    * ClutterActor:natural-height-set:
5160    *
5161    * This flag controls whether the #ClutterActor:natural-height property
5162    * is used
5163    *
5164    * Since: 0.8
5165    */
5166   obj_props[PROP_NATURAL_HEIGHT_SET] =
5167     g_param_spec_boolean ("natural-height-set",
5168                           P_("Natural height set"),
5169                           P_("Whether to use the natural-height property"),
5170                           FALSE,
5171                           CLUTTER_PARAM_READWRITE);
5172
5173   /**
5174    * ClutterActor:allocation:
5175    *
5176    * The allocation for the actor, in pixels
5177    *
5178    * This is property is read-only, but you might monitor it to know when an
5179    * actor moves or resizes
5180    *
5181    * Since: 0.8
5182    */
5183   obj_props[PROP_ALLOCATION] =
5184     g_param_spec_boxed ("allocation",
5185                         P_("Allocation"),
5186                         P_("The actor's allocation"),
5187                         CLUTTER_TYPE_ACTOR_BOX,
5188                         CLUTTER_PARAM_READABLE);
5189
5190   /**
5191    * ClutterActor:request-mode:
5192    *
5193    * Request mode for the #ClutterActor. The request mode determines the
5194    * type of geometry management used by the actor, either height for width
5195    * (the default) or width for height.
5196    *
5197    * For actors implementing height for width, the parent container should get
5198    * the preferred width first, and then the preferred height for that width.
5199    *
5200    * For actors implementing width for height, the parent container should get
5201    * the preferred height first, and then the preferred width for that height.
5202    *
5203    * For instance:
5204    *
5205    * |[
5206    *   ClutterRequestMode mode;
5207    *   gfloat natural_width, min_width;
5208    *   gfloat natural_height, min_height;
5209    *
5210    *   mode = clutter_actor_get_request_mode (child);
5211    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5212    *     {
5213    *       clutter_actor_get_preferred_width (child, -1,
5214    *                                          &amp;min_width,
5215    *                                          &amp;natural_width);
5216    *       clutter_actor_get_preferred_height (child, natural_width,
5217    *                                           &amp;min_height,
5218    *                                           &amp;natural_height);
5219    *     }
5220    *   else
5221    *     {
5222    *       clutter_actor_get_preferred_height (child, -1,
5223    *                                           &amp;min_height,
5224    *                                           &amp;natural_height);
5225    *       clutter_actor_get_preferred_width (child, natural_height,
5226    *                                          &amp;min_width,
5227    *                                          &amp;natural_width);
5228    *     }
5229    * ]|
5230    *
5231    * will retrieve the minimum and natural width and height depending on the
5232    * preferred request mode of the #ClutterActor "child".
5233    *
5234    * The clutter_actor_get_preferred_size() function will implement this
5235    * check for you.
5236    *
5237    * Since: 0.8
5238    */
5239   obj_props[PROP_REQUEST_MODE] =
5240     g_param_spec_enum ("request-mode",
5241                        P_("Request Mode"),
5242                        P_("The actor's request mode"),
5243                        CLUTTER_TYPE_REQUEST_MODE,
5244                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5245                        CLUTTER_PARAM_READWRITE);
5246
5247   /**
5248    * ClutterActor:depth:
5249    *
5250    * The position of the actor on the Z axis
5251    *
5252    * Since: 0.6
5253    */
5254   obj_props[PROP_DEPTH] =
5255     g_param_spec_float ("depth",
5256                         P_("Depth"),
5257                         P_("Position on the Z axis"),
5258                         -G_MAXFLOAT, G_MAXFLOAT,
5259                         0.0,
5260                         CLUTTER_PARAM_READWRITE);
5261
5262   /**
5263    * ClutterActor:opacity:
5264    *
5265    * Opacity of an actor, between 0 (fully transparent) and
5266    * 255 (fully opaque)
5267    */
5268   obj_props[PROP_OPACITY] =
5269     g_param_spec_uint ("opacity",
5270                        P_("Opacity"),
5271                        P_("Opacity of an actor"),
5272                        0, 255,
5273                        255,
5274                        CLUTTER_PARAM_READWRITE);
5275
5276   /**
5277    * ClutterActor:offscreen-redirect:
5278    *
5279    * Determines the conditions in which the actor will be redirected
5280    * to an offscreen framebuffer while being painted. For example this
5281    * can be used to cache an actor in a framebuffer or for improved
5282    * handling of transparent actors. See
5283    * clutter_actor_set_offscreen_redirect() for details.
5284    *
5285    * Since: 1.8
5286    */
5287   obj_props[PROP_OFFSCREEN_REDIRECT] =
5288     g_param_spec_flags ("offscreen-redirect",
5289                         P_("Offscreen redirect"),
5290                         P_("Flags controlling when to flatten the actor into a single image"),
5291                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5292                         0,
5293                         CLUTTER_PARAM_READWRITE);
5294
5295   /**
5296    * ClutterActor:visible:
5297    *
5298    * Whether the actor is set to be visible or not
5299    *
5300    * See also #ClutterActor:mapped
5301    */
5302   obj_props[PROP_VISIBLE] =
5303     g_param_spec_boolean ("visible",
5304                           P_("Visible"),
5305                           P_("Whether the actor is visible or not"),
5306                           FALSE,
5307                           CLUTTER_PARAM_READWRITE);
5308
5309   /**
5310    * ClutterActor:mapped:
5311    *
5312    * Whether the actor is mapped (will be painted when the stage
5313    * to which it belongs is mapped)
5314    *
5315    * Since: 1.0
5316    */
5317   obj_props[PROP_MAPPED] =
5318     g_param_spec_boolean ("mapped",
5319                           P_("Mapped"),
5320                           P_("Whether the actor will be painted"),
5321                           FALSE,
5322                           CLUTTER_PARAM_READABLE);
5323
5324   /**
5325    * ClutterActor:realized:
5326    *
5327    * Whether the actor has been realized
5328    *
5329    * Since: 1.0
5330    */
5331   obj_props[PROP_REALIZED] =
5332     g_param_spec_boolean ("realized",
5333                           P_("Realized"),
5334                           P_("Whether the actor has been realized"),
5335                           FALSE,
5336                           CLUTTER_PARAM_READABLE);
5337
5338   /**
5339    * ClutterActor:reactive:
5340    *
5341    * Whether the actor is reactive to events or not
5342    *
5343    * Only reactive actors will emit event-related signals
5344    *
5345    * Since: 0.6
5346    */
5347   obj_props[PROP_REACTIVE] =
5348     g_param_spec_boolean ("reactive",
5349                           P_("Reactive"),
5350                           P_("Whether the actor is reactive to events"),
5351                           FALSE,
5352                           CLUTTER_PARAM_READWRITE);
5353
5354   /**
5355    * ClutterActor:has-clip:
5356    *
5357    * Whether the actor has the #ClutterActor:clip property set or not
5358    */
5359   obj_props[PROP_HAS_CLIP] =
5360     g_param_spec_boolean ("has-clip",
5361                           P_("Has Clip"),
5362                           P_("Whether the actor has a clip set"),
5363                           FALSE,
5364                           CLUTTER_PARAM_READABLE);
5365
5366   /**
5367    * ClutterActor:clip:
5368    *
5369    * The clip region for the actor, in actor-relative coordinates
5370    *
5371    * Every part of the actor outside the clip region will not be
5372    * painted
5373    */
5374   obj_props[PROP_CLIP] =
5375     g_param_spec_boxed ("clip",
5376                         P_("Clip"),
5377                         P_("The clip region for the actor"),
5378                         CLUTTER_TYPE_GEOMETRY,
5379                         CLUTTER_PARAM_READWRITE);
5380
5381   /**
5382    * ClutterActor:name:
5383    *
5384    * The name of the actor
5385    *
5386    * Since: 0.2
5387    */
5388   obj_props[PROP_NAME] =
5389     g_param_spec_string ("name",
5390                          P_("Name"),
5391                          P_("Name of the actor"),
5392                          NULL,
5393                          CLUTTER_PARAM_READWRITE);
5394
5395   /**
5396    * ClutterActor:scale-x:
5397    *
5398    * The horizontal scale of the actor
5399    *
5400    * Since: 0.6
5401    */
5402   obj_props[PROP_SCALE_X] =
5403     g_param_spec_double ("scale-x",
5404                          P_("Scale X"),
5405                          P_("Scale factor on the X axis"),
5406                          0.0, G_MAXDOUBLE,
5407                          1.0,
5408                          CLUTTER_PARAM_READWRITE);
5409
5410   /**
5411    * ClutterActor:scale-y:
5412    *
5413    * The vertical scale of the actor
5414    *
5415    * Since: 0.6
5416    */
5417   obj_props[PROP_SCALE_Y] =
5418     g_param_spec_double ("scale-y",
5419                          P_("Scale Y"),
5420                          P_("Scale factor on the Y axis"),
5421                          0.0, G_MAXDOUBLE,
5422                          1.0,
5423                          CLUTTER_PARAM_READWRITE);
5424
5425   /**
5426    * ClutterActor:scale-center-x:
5427    *
5428    * The horizontal center point for scaling
5429    *
5430    * Since: 1.0
5431    */
5432   obj_props[PROP_SCALE_CENTER_X] =
5433     g_param_spec_float ("scale-center-x",
5434                         P_("Scale Center X"),
5435                         P_("Horizontal scale center"),
5436                         -G_MAXFLOAT, G_MAXFLOAT,
5437                         0.0,
5438                         CLUTTER_PARAM_READWRITE);
5439
5440   /**
5441    * ClutterActor:scale-center-y:
5442    *
5443    * The vertical center point for scaling
5444    *
5445    * Since: 1.0
5446    */
5447   obj_props[PROP_SCALE_CENTER_Y] =
5448     g_param_spec_float ("scale-center-y",
5449                         P_("Scale Center Y"),
5450                         P_("Vertical scale center"),
5451                         -G_MAXFLOAT, G_MAXFLOAT,
5452                         0.0,
5453                         CLUTTER_PARAM_READWRITE);
5454
5455   /**
5456    * ClutterActor:scale-gravity:
5457    *
5458    * The center point for scaling expressed as a #ClutterGravity
5459    *
5460    * Since: 1.0
5461    */
5462   obj_props[PROP_SCALE_GRAVITY] =
5463     g_param_spec_enum ("scale-gravity",
5464                        P_("Scale Gravity"),
5465                        P_("The center of scaling"),
5466                        CLUTTER_TYPE_GRAVITY,
5467                        CLUTTER_GRAVITY_NONE,
5468                        CLUTTER_PARAM_READWRITE);
5469
5470   /**
5471    * ClutterActor:rotation-angle-x:
5472    *
5473    * The rotation angle on the X axis
5474    *
5475    * Since: 0.6
5476    */
5477   obj_props[PROP_ROTATION_ANGLE_X] =
5478     g_param_spec_double ("rotation-angle-x",
5479                          P_("Rotation Angle X"),
5480                          P_("The rotation angle on the X axis"),
5481                          -G_MAXDOUBLE, G_MAXDOUBLE,
5482                          0.0,
5483                          CLUTTER_PARAM_READWRITE);
5484
5485   /**
5486    * ClutterActor:rotation-angle-y:
5487    *
5488    * The rotation angle on the Y axis
5489    *
5490    * Since: 0.6
5491    */
5492   obj_props[PROP_ROTATION_ANGLE_Y] =
5493     g_param_spec_double ("rotation-angle-y",
5494                          P_("Rotation Angle Y"),
5495                          P_("The rotation angle on the Y axis"),
5496                          -G_MAXDOUBLE, G_MAXDOUBLE,
5497                          0.0,
5498                          CLUTTER_PARAM_READWRITE);
5499
5500   /**
5501    * ClutterActor:rotation-angle-z:
5502    *
5503    * The rotation angle on the Z axis
5504    *
5505    * Since: 0.6
5506    */
5507   obj_props[PROP_ROTATION_ANGLE_Z] =
5508     g_param_spec_double ("rotation-angle-z",
5509                          P_("Rotation Angle Z"),
5510                          P_("The rotation angle on the Z axis"),
5511                          -G_MAXDOUBLE, G_MAXDOUBLE,
5512                          0.0,
5513                          CLUTTER_PARAM_READWRITE);
5514
5515   /**
5516    * ClutterActor:rotation-center-x:
5517    *
5518    * The rotation center on the X axis.
5519    *
5520    * Since: 0.6
5521    */
5522   obj_props[PROP_ROTATION_CENTER_X] =
5523     g_param_spec_boxed ("rotation-center-x",
5524                         P_("Rotation Center X"),
5525                         P_("The rotation center on the X axis"),
5526                         CLUTTER_TYPE_VERTEX,
5527                         CLUTTER_PARAM_READWRITE);
5528
5529   /**
5530    * ClutterActor:rotation-center-y:
5531    *
5532    * The rotation center on the Y axis.
5533    *
5534    * Since: 0.6
5535    */
5536   obj_props[PROP_ROTATION_CENTER_Y] =
5537     g_param_spec_boxed ("rotation-center-y",
5538                         P_("Rotation Center Y"),
5539                         P_("The rotation center on the Y axis"),
5540                         CLUTTER_TYPE_VERTEX,
5541                         CLUTTER_PARAM_READWRITE);
5542
5543   /**
5544    * ClutterActor:rotation-center-z:
5545    *
5546    * The rotation center on the Z axis.
5547    *
5548    * Since: 0.6
5549    */
5550   obj_props[PROP_ROTATION_CENTER_Z] =
5551     g_param_spec_boxed ("rotation-center-z",
5552                         P_("Rotation Center Z"),
5553                         P_("The rotation center on the Z axis"),
5554                         CLUTTER_TYPE_VERTEX,
5555                         CLUTTER_PARAM_READWRITE);
5556
5557   /**
5558    * ClutterActor:rotation-center-z-gravity:
5559    *
5560    * The rotation center on the Z axis expressed as a #ClutterGravity.
5561    *
5562    * Since: 1.0
5563    */
5564   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5565     g_param_spec_enum ("rotation-center-z-gravity",
5566                        P_("Rotation Center Z Gravity"),
5567                        P_("Center point for rotation around the Z axis"),
5568                        CLUTTER_TYPE_GRAVITY,
5569                        CLUTTER_GRAVITY_NONE,
5570                        CLUTTER_PARAM_READWRITE);
5571
5572   /**
5573    * ClutterActor:anchor-x:
5574    *
5575    * The X coordinate of an actor's anchor point, relative to
5576    * the actor coordinate space, in pixels
5577    *
5578    * Since: 0.8
5579    */
5580   obj_props[PROP_ANCHOR_X] =
5581     g_param_spec_float ("anchor-x",
5582                         P_("Anchor X"),
5583                         P_("X coordinate of the anchor point"),
5584                         -G_MAXFLOAT, G_MAXFLOAT,
5585                         0,
5586                         CLUTTER_PARAM_READWRITE);
5587
5588   /**
5589    * ClutterActor:anchor-y:
5590    *
5591    * The Y coordinate of an actor's anchor point, relative to
5592    * the actor coordinate space, in pixels
5593    *
5594    * Since: 0.8
5595    */
5596   obj_props[PROP_ANCHOR_Y] =
5597     g_param_spec_float ("anchor-y",
5598                         P_("Anchor Y"),
5599                         P_("Y coordinate of the anchor point"),
5600                         -G_MAXFLOAT, G_MAXFLOAT,
5601                         0,
5602                         CLUTTER_PARAM_READWRITE);
5603
5604   /**
5605    * ClutterActor:anchor-gravity:
5606    *
5607    * The anchor point expressed as a #ClutterGravity
5608    *
5609    * Since: 1.0
5610    */
5611   obj_props[PROP_ANCHOR_GRAVITY] =
5612     g_param_spec_enum ("anchor-gravity",
5613                        P_("Anchor Gravity"),
5614                        P_("The anchor point as a ClutterGravity"),
5615                        CLUTTER_TYPE_GRAVITY,
5616                        CLUTTER_GRAVITY_NONE,
5617                        CLUTTER_PARAM_READWRITE);
5618
5619   /**
5620    * ClutterActor:show-on-set-parent:
5621    *
5622    * If %TRUE, the actor is automatically shown when parented.
5623    *
5624    * Calling clutter_actor_hide() on an actor which has not been
5625    * parented will set this property to %FALSE as a side effect.
5626    *
5627    * Since: 0.8
5628    */
5629   obj_props[PROP_SHOW_ON_SET_PARENT] =
5630     g_param_spec_boolean ("show-on-set-parent",
5631                           P_("Show on set parent"),
5632                           P_("Whether the actor is shown when parented"),
5633                           TRUE,
5634                           CLUTTER_PARAM_READWRITE);
5635
5636   /**
5637    * ClutterActor:clip-to-allocation:
5638    *
5639    * Whether the clip region should track the allocated area
5640    * of the actor.
5641    *
5642    * This property is ignored if a clip area has been explicitly
5643    * set using clutter_actor_set_clip().
5644    *
5645    * Since: 1.0
5646    */
5647   obj_props[PROP_CLIP_TO_ALLOCATION] =
5648     g_param_spec_boolean ("clip-to-allocation",
5649                           P_("Clip to Allocation"),
5650                           P_("Sets the clip region to track the actor's allocation"),
5651                           FALSE,
5652                           CLUTTER_PARAM_READWRITE);
5653
5654   /**
5655    * ClutterActor:text-direction:
5656    *
5657    * The direction of the text inside a #ClutterActor.
5658    *
5659    * Since: 1.0
5660    */
5661   obj_props[PROP_TEXT_DIRECTION] =
5662     g_param_spec_enum ("text-direction",
5663                        P_("Text Direction"),
5664                        P_("Direction of the text"),
5665                        CLUTTER_TYPE_TEXT_DIRECTION,
5666                        CLUTTER_TEXT_DIRECTION_LTR,
5667                        CLUTTER_PARAM_READWRITE);
5668
5669   /**
5670    * ClutterActor:has-pointer:
5671    *
5672    * Whether the actor contains the pointer of a #ClutterInputDevice
5673    * or not.
5674    *
5675    * Since: 1.2
5676    */
5677   obj_props[PROP_HAS_POINTER] =
5678     g_param_spec_boolean ("has-pointer",
5679                           P_("Has Pointer"),
5680                           P_("Whether the actor contains the pointer of an input device"),
5681                           FALSE,
5682                           CLUTTER_PARAM_READABLE);
5683
5684   /**
5685    * ClutterActor:actions:
5686    *
5687    * Adds a #ClutterAction to the actor
5688    *
5689    * Since: 1.4
5690    */
5691   obj_props[PROP_ACTIONS] =
5692     g_param_spec_object ("actions",
5693                          P_("Actions"),
5694                          P_("Adds an action to the actor"),
5695                          CLUTTER_TYPE_ACTION,
5696                          CLUTTER_PARAM_WRITABLE);
5697
5698   /**
5699    * ClutterActor:constraints:
5700    *
5701    * Adds a #ClutterConstraint to the actor
5702    *
5703    * Since: 1.4
5704    */
5705   obj_props[PROP_CONSTRAINTS] =
5706     g_param_spec_object ("constraints",
5707                          P_("Constraints"),
5708                          P_("Adds a constraint to the actor"),
5709                          CLUTTER_TYPE_CONSTRAINT,
5710                          CLUTTER_PARAM_WRITABLE);
5711
5712   /**
5713    * ClutterActor:effect:
5714    *
5715    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5716    *
5717    * Since: 1.4
5718    */
5719   obj_props[PROP_EFFECT] =
5720     g_param_spec_object ("effect",
5721                          P_("Effect"),
5722                          P_("Add an effect to be applied on the actor"),
5723                          CLUTTER_TYPE_EFFECT,
5724                          CLUTTER_PARAM_WRITABLE);
5725
5726   /**
5727    * ClutterActor:layout-manager:
5728    *
5729    * A delegate object for controlling the layout of the children of
5730    * an actor.
5731    *
5732    * Since: 1.10
5733    */
5734   obj_props[PROP_LAYOUT_MANAGER] =
5735     g_param_spec_object ("layout-manager",
5736                          P_("Layout Manager"),
5737                          P_("The object controlling the layout of an actor's children"),
5738                          CLUTTER_TYPE_LAYOUT_MANAGER,
5739                          CLUTTER_PARAM_READWRITE);
5740
5741
5742   /**
5743    * ClutterActor:x-align:
5744    *
5745    * The alignment of an actor on the X axis, if the actor has been given
5746    * extra space for its allocation.
5747    *
5748    * Since: 1.10
5749    */
5750   obj_props[PROP_X_ALIGN] =
5751     g_param_spec_enum ("x-align",
5752                        P_("X Alignment"),
5753                        P_("The alignment of the actor on the X axis within its allocation"),
5754                        CLUTTER_TYPE_ACTOR_ALIGN,
5755                        CLUTTER_ACTOR_ALIGN_FILL,
5756                        CLUTTER_PARAM_READWRITE);
5757
5758   /**
5759    * ClutterActor:y-align:
5760    *
5761    * The alignment of an actor on the Y axis, if the actor has been given
5762    * extra space for its allocation.
5763    *
5764    * Since: 1.10
5765    */
5766   obj_props[PROP_Y_ALIGN] =
5767     g_param_spec_enum ("y-align",
5768                        P_("Y Alignment"),
5769                        P_("The alignment of the actor on the Y axis within its allocation"),
5770                        CLUTTER_TYPE_ACTOR_ALIGN,
5771                        CLUTTER_ACTOR_ALIGN_FILL,
5772                        CLUTTER_PARAM_READWRITE);
5773
5774   /**
5775    * ClutterActor:margin-top:
5776    *
5777    * The margin (in pixels) from the top of the actor.
5778    *
5779    * This property adds a margin to the actor's preferred size; the margin
5780    * will be automatically taken into account when allocating the actor.
5781    *
5782    * Since: 1.10
5783    */
5784   obj_props[PROP_MARGIN_TOP] =
5785     g_param_spec_float ("margin-top",
5786                         P_("Margin Top"),
5787                         P_("Extra space at the top"),
5788                         0.0, G_MAXFLOAT,
5789                         0.0,
5790                         CLUTTER_PARAM_READWRITE);
5791
5792   /**
5793    * ClutterActor:margin-bottom:
5794    *
5795    * The margin (in pixels) from the bottom of the actor.
5796    *
5797    * This property adds a margin to the actor's preferred size; the margin
5798    * will be automatically taken into account when allocating the actor.
5799    *
5800    * Since: 1.10
5801    */
5802   obj_props[PROP_MARGIN_BOTTOM] =
5803     g_param_spec_float ("margin-bottom",
5804                         P_("Margin Bottom"),
5805                         P_("Extra space at the bottom"),
5806                         0.0, G_MAXFLOAT,
5807                         0.0,
5808                         CLUTTER_PARAM_READWRITE);
5809
5810   /**
5811    * ClutterActor:margin-left:
5812    *
5813    * The margin (in pixels) from the left of the actor.
5814    *
5815    * This property adds a margin to the actor's preferred size; the margin
5816    * will be automatically taken into account when allocating the actor.
5817    *
5818    * Since: 1.10
5819    */
5820   obj_props[PROP_MARGIN_LEFT] =
5821     g_param_spec_float ("margin-left",
5822                         P_("Margin Left"),
5823                         P_("Extra space at the left"),
5824                         0.0, G_MAXFLOAT,
5825                         0.0,
5826                         CLUTTER_PARAM_READWRITE);
5827
5828   /**
5829    * ClutterActor:margin-right:
5830    *
5831    * The margin (in pixels) from the right of the actor.
5832    *
5833    * This property adds a margin to the actor's preferred size; the margin
5834    * will be automatically taken into account when allocating the actor.
5835    *
5836    * Since: 1.10
5837    */
5838   obj_props[PROP_MARGIN_RIGHT] =
5839     g_param_spec_float ("margin-right",
5840                         P_("Margin Right"),
5841                         P_("Extra space at the right"),
5842                         0.0, G_MAXFLOAT,
5843                         0.0,
5844                         CLUTTER_PARAM_READWRITE);
5845
5846   /**
5847    * ClutterActor:background-color-set:
5848    *
5849    * Whether the #ClutterActor:background-color property has been set.
5850    *
5851    * Since: 1.10
5852    */
5853   obj_props[PROP_BACKGROUND_COLOR_SET] =
5854     g_param_spec_boolean ("background-color-set",
5855                           P_("Background Color Set"),
5856                           P_("Whether the background color is set"),
5857                           FALSE,
5858                           CLUTTER_PARAM_READABLE);
5859
5860   /**
5861    * ClutterActor:background-color:
5862    *
5863    * Paints a solid fill of the actor's allocation using the specified
5864    * color.
5865    *
5866    * Since: 1.10
5867    */
5868   obj_props[PROP_BACKGROUND_COLOR] =
5869     clutter_param_spec_color ("background-color",
5870                               P_("Background color"),
5871                               P_("The actor's background color"),
5872                               CLUTTER_COLOR_Transparent,
5873                               CLUTTER_PARAM_READWRITE);
5874
5875   /**
5876    * ClutterActor:first-child:
5877    *
5878    * The actor's first child.
5879    *
5880    * Since: 1.10
5881    */
5882   obj_props[PROP_FIRST_CHILD] =
5883     g_param_spec_object ("first-child",
5884                          P_("First Child"),
5885                          P_("The actor's first child"),
5886                          CLUTTER_TYPE_ACTOR,
5887                          CLUTTER_PARAM_READABLE);
5888
5889   /**
5890    * ClutterActor:last-child:
5891    *
5892    * The actor's last child.
5893    *
5894    * Since: 1.10
5895    */
5896   obj_props[PROP_LAST_CHILD] =
5897     g_param_spec_object ("last-child",
5898                          P_("Last Child"),
5899                          P_("The actor's last child"),
5900                          CLUTTER_TYPE_ACTOR,
5901                          CLUTTER_PARAM_READABLE);
5902
5903   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
5904
5905   /**
5906    * ClutterActor::destroy:
5907    * @actor: the #ClutterActor which emitted the signal
5908    *
5909    * The ::destroy signal notifies that all references held on the
5910    * actor which emitted it should be released.
5911    *
5912    * The ::destroy signal should be used by all holders of a reference
5913    * on @actor.
5914    *
5915    * This signal might result in the finalization of the #ClutterActor
5916    * if all references are released.
5917    *
5918    * Composite actors and actors implementing the #ClutterContainer
5919    * interface should override the default implementation of the
5920    * class handler of this signal and call clutter_actor_destroy() on
5921    * their children. When overriding the default class handler, it is
5922    * required to chain up to the parent's implementation.
5923    *
5924    * Since: 0.2
5925    */
5926   actor_signals[DESTROY] =
5927     g_signal_new (I_("destroy"),
5928                   G_TYPE_FROM_CLASS (object_class),
5929                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
5930                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
5931                   NULL, NULL,
5932                   _clutter_marshal_VOID__VOID,
5933                   G_TYPE_NONE, 0);
5934   /**
5935    * ClutterActor::show:
5936    * @actor: the object which received the signal
5937    *
5938    * The ::show signal is emitted when an actor is visible and
5939    * rendered on the stage.
5940    *
5941    * Since: 0.2
5942    */
5943   actor_signals[SHOW] =
5944     g_signal_new (I_("show"),
5945                   G_TYPE_FROM_CLASS (object_class),
5946                   G_SIGNAL_RUN_FIRST,
5947                   G_STRUCT_OFFSET (ClutterActorClass, show),
5948                   NULL, NULL,
5949                   _clutter_marshal_VOID__VOID,
5950                   G_TYPE_NONE, 0);
5951   /**
5952    * ClutterActor::hide:
5953    * @actor: the object which received the signal
5954    *
5955    * The ::hide signal is emitted when an actor is no longer rendered
5956    * on the stage.
5957    *
5958    * Since: 0.2
5959    */
5960   actor_signals[HIDE] =
5961     g_signal_new (I_("hide"),
5962                   G_TYPE_FROM_CLASS (object_class),
5963                   G_SIGNAL_RUN_FIRST,
5964                   G_STRUCT_OFFSET (ClutterActorClass, hide),
5965                   NULL, NULL,
5966                   _clutter_marshal_VOID__VOID,
5967                   G_TYPE_NONE, 0);
5968   /**
5969    * ClutterActor::parent-set:
5970    * @actor: the object which received the signal
5971    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
5972    *
5973    * This signal is emitted when the parent of the actor changes.
5974    *
5975    * Since: 0.2
5976    */
5977   actor_signals[PARENT_SET] =
5978     g_signal_new (I_("parent-set"),
5979                   G_TYPE_FROM_CLASS (object_class),
5980                   G_SIGNAL_RUN_LAST,
5981                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
5982                   NULL, NULL,
5983                   _clutter_marshal_VOID__OBJECT,
5984                   G_TYPE_NONE, 1,
5985                   CLUTTER_TYPE_ACTOR);
5986
5987   /**
5988    * ClutterActor::queue-redraw:
5989    * @actor: the actor we're bubbling the redraw request through
5990    * @origin: the actor which initiated the redraw request
5991    *
5992    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
5993    * is called on @origin.
5994    *
5995    * The default implementation for #ClutterActor chains up to the
5996    * parent actor and queues a redraw on the parent, thus "bubbling"
5997    * the redraw queue up through the actor graph. The default
5998    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
5999    * in a main loop idle handler.
6000    *
6001    * Note that the @origin actor may be the stage, or a container; it
6002    * does not have to be a leaf node in the actor graph.
6003    *
6004    * Toolkits embedding a #ClutterStage which require a redraw and
6005    * relayout cycle can stop the emission of this signal using the
6006    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6007    * themselves, like:
6008    *
6009    * |[
6010    *   static void
6011    *   on_redraw_complete (gpointer data)
6012    *   {
6013    *     ClutterStage *stage = data;
6014    *
6015    *     /&ast; execute the Clutter drawing pipeline &ast;/
6016    *     clutter_stage_ensure_redraw (stage);
6017    *   }
6018    *
6019    *   static void
6020    *   on_stage_queue_redraw (ClutterStage *stage)
6021    *   {
6022    *     /&ast; this prevents the default handler to run &ast;/
6023    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6024    *
6025    *     /&ast; queue a redraw with the host toolkit and call
6026    *      &ast; a function when the redraw has been completed
6027    *      &ast;/
6028    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6029    *   }
6030    * ]|
6031    *
6032    * <note><para>This signal is emitted before the Clutter paint
6033    * pipeline is executed. If you want to know when the pipeline has
6034    * been completed you should connect to the ::paint signal on the
6035    * Stage with g_signal_connect_after().</para></note>
6036    *
6037    * Since: 1.0
6038    */
6039   actor_signals[QUEUE_REDRAW] =
6040     g_signal_new (I_("queue-redraw"),
6041                   G_TYPE_FROM_CLASS (object_class),
6042                   G_SIGNAL_RUN_LAST,
6043                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6044                   NULL, NULL,
6045                   _clutter_marshal_VOID__OBJECT,
6046                   G_TYPE_NONE, 1,
6047                   CLUTTER_TYPE_ACTOR);
6048
6049   /**
6050    * ClutterActor::queue-relayout
6051    * @actor: the actor being queued for relayout
6052    *
6053    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6054    * is called on an actor.
6055    *
6056    * The default implementation for #ClutterActor chains up to the
6057    * parent actor and queues a relayout on the parent, thus "bubbling"
6058    * the relayout queue up through the actor graph.
6059    *
6060    * The main purpose of this signal is to allow relayout to be propagated
6061    * properly in the procense of #ClutterClone actors. Applications will
6062    * not normally need to connect to this signal.
6063    *
6064    * Since: 1.2
6065    */
6066   actor_signals[QUEUE_RELAYOUT] =
6067     g_signal_new (I_("queue-relayout"),
6068                   G_TYPE_FROM_CLASS (object_class),
6069                   G_SIGNAL_RUN_LAST,
6070                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6071                   NULL, NULL,
6072                   _clutter_marshal_VOID__VOID,
6073                   G_TYPE_NONE, 0);
6074
6075   /**
6076    * ClutterActor::event:
6077    * @actor: the actor which received the event
6078    * @event: a #ClutterEvent
6079    *
6080    * The ::event signal is emitted each time an event is received
6081    * by the @actor. This signal will be emitted on every actor,
6082    * following the hierarchy chain, until it reaches the top-level
6083    * container (the #ClutterStage).
6084    *
6085    * Return value: %TRUE if the event has been handled by the actor,
6086    *   or %FALSE to continue the emission.
6087    *
6088    * Since: 0.6
6089    */
6090   actor_signals[EVENT] =
6091     g_signal_new (I_("event"),
6092                   G_TYPE_FROM_CLASS (object_class),
6093                   G_SIGNAL_RUN_LAST,
6094                   G_STRUCT_OFFSET (ClutterActorClass, event),
6095                   _clutter_boolean_handled_accumulator, NULL,
6096                   _clutter_marshal_BOOLEAN__BOXED,
6097                   G_TYPE_BOOLEAN, 1,
6098                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6099   /**
6100    * ClutterActor::button-press-event:
6101    * @actor: the actor which received the event
6102    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6103    *
6104    * The ::button-press-event signal is emitted each time a mouse button
6105    * is pressed on @actor.
6106    *
6107    * Return value: %TRUE if the event has been handled by the actor,
6108    *   or %FALSE to continue the emission.
6109    *
6110    * Since: 0.6
6111    */
6112   actor_signals[BUTTON_PRESS_EVENT] =
6113     g_signal_new (I_("button-press-event"),
6114                   G_TYPE_FROM_CLASS (object_class),
6115                   G_SIGNAL_RUN_LAST,
6116                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6117                   _clutter_boolean_handled_accumulator, NULL,
6118                   _clutter_marshal_BOOLEAN__BOXED,
6119                   G_TYPE_BOOLEAN, 1,
6120                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6121   /**
6122    * ClutterActor::button-release-event:
6123    * @actor: the actor which received the event
6124    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6125    *
6126    * The ::button-release-event signal is emitted each time a mouse button
6127    * is released on @actor.
6128    *
6129    * Return value: %TRUE if the event has been handled by the actor,
6130    *   or %FALSE to continue the emission.
6131    *
6132    * Since: 0.6
6133    */
6134   actor_signals[BUTTON_RELEASE_EVENT] =
6135     g_signal_new (I_("button-release-event"),
6136                   G_TYPE_FROM_CLASS (object_class),
6137                   G_SIGNAL_RUN_LAST,
6138                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6139                   _clutter_boolean_handled_accumulator, NULL,
6140                   _clutter_marshal_BOOLEAN__BOXED,
6141                   G_TYPE_BOOLEAN, 1,
6142                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6143   /**
6144    * ClutterActor::scroll-event:
6145    * @actor: the actor which received the event
6146    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6147    *
6148    * The ::scroll-event signal is emitted each time the mouse is
6149    * scrolled on @actor
6150    *
6151    * Return value: %TRUE if the event has been handled by the actor,
6152    *   or %FALSE to continue the emission.
6153    *
6154    * Since: 0.6
6155    */
6156   actor_signals[SCROLL_EVENT] =
6157     g_signal_new (I_("scroll-event"),
6158                   G_TYPE_FROM_CLASS (object_class),
6159                   G_SIGNAL_RUN_LAST,
6160                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6161                   _clutter_boolean_handled_accumulator, NULL,
6162                   _clutter_marshal_BOOLEAN__BOXED,
6163                   G_TYPE_BOOLEAN, 1,
6164                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6165   /**
6166    * ClutterActor::key-press-event:
6167    * @actor: the actor which received the event
6168    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6169    *
6170    * The ::key-press-event signal is emitted each time a keyboard button
6171    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6172    *
6173    * Return value: %TRUE if the event has been handled by the actor,
6174    *   or %FALSE to continue the emission.
6175    *
6176    * Since: 0.6
6177    */
6178   actor_signals[KEY_PRESS_EVENT] =
6179     g_signal_new (I_("key-press-event"),
6180                   G_TYPE_FROM_CLASS (object_class),
6181                   G_SIGNAL_RUN_LAST,
6182                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6183                   _clutter_boolean_handled_accumulator, NULL,
6184                   _clutter_marshal_BOOLEAN__BOXED,
6185                   G_TYPE_BOOLEAN, 1,
6186                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6187   /**
6188    * ClutterActor::key-release-event:
6189    * @actor: the actor which received the event
6190    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6191    *
6192    * The ::key-release-event signal is emitted each time a keyboard button
6193    * is released while @actor has key focus (see
6194    * clutter_stage_set_key_focus()).
6195    *
6196    * Return value: %TRUE if the event has been handled by the actor,
6197    *   or %FALSE to continue the emission.
6198    *
6199    * Since: 0.6
6200    */
6201   actor_signals[KEY_RELEASE_EVENT] =
6202     g_signal_new (I_("key-release-event"),
6203                   G_TYPE_FROM_CLASS (object_class),
6204                   G_SIGNAL_RUN_LAST,
6205                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6206                   _clutter_boolean_handled_accumulator, NULL,
6207                   _clutter_marshal_BOOLEAN__BOXED,
6208                   G_TYPE_BOOLEAN, 1,
6209                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6210   /**
6211    * ClutterActor::motion-event:
6212    * @actor: the actor which received the event
6213    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6214    *
6215    * The ::motion-event signal is emitted each time the mouse pointer is
6216    * moved over @actor.
6217    *
6218    * Return value: %TRUE if the event has been handled by the actor,
6219    *   or %FALSE to continue the emission.
6220    *
6221    * Since: 0.6
6222    */
6223   actor_signals[MOTION_EVENT] =
6224     g_signal_new (I_("motion-event"),
6225                   G_TYPE_FROM_CLASS (object_class),
6226                   G_SIGNAL_RUN_LAST,
6227                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6228                   _clutter_boolean_handled_accumulator, NULL,
6229                   _clutter_marshal_BOOLEAN__BOXED,
6230                   G_TYPE_BOOLEAN, 1,
6231                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6232
6233   /**
6234    * ClutterActor::key-focus-in:
6235    * @actor: the actor which now has key focus
6236    *
6237    * The ::key-focus-in signal is emitted when @actor receives key focus.
6238    *
6239    * Since: 0.6
6240    */
6241   actor_signals[KEY_FOCUS_IN] =
6242     g_signal_new (I_("key-focus-in"),
6243                   G_TYPE_FROM_CLASS (object_class),
6244                   G_SIGNAL_RUN_LAST,
6245                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6246                   NULL, NULL,
6247                   _clutter_marshal_VOID__VOID,
6248                   G_TYPE_NONE, 0);
6249
6250   /**
6251    * ClutterActor::key-focus-out:
6252    * @actor: the actor which now has key focus
6253    *
6254    * The ::key-focus-out signal is emitted when @actor loses key focus.
6255    *
6256    * Since: 0.6
6257    */
6258   actor_signals[KEY_FOCUS_OUT] =
6259     g_signal_new (I_("key-focus-out"),
6260                   G_TYPE_FROM_CLASS (object_class),
6261                   G_SIGNAL_RUN_LAST,
6262                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6263                   NULL, NULL,
6264                   _clutter_marshal_VOID__VOID,
6265                   G_TYPE_NONE, 0);
6266
6267   /**
6268    * ClutterActor::enter-event:
6269    * @actor: the actor which the pointer has entered.
6270    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6271    *
6272    * The ::enter-event signal is emitted when the pointer enters the @actor
6273    *
6274    * Return value: %TRUE if the event has been handled by the actor,
6275    *   or %FALSE to continue the emission.
6276    *
6277    * Since: 0.6
6278    */
6279   actor_signals[ENTER_EVENT] =
6280     g_signal_new (I_("enter-event"),
6281                   G_TYPE_FROM_CLASS (object_class),
6282                   G_SIGNAL_RUN_LAST,
6283                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6284                   _clutter_boolean_handled_accumulator, NULL,
6285                   _clutter_marshal_BOOLEAN__BOXED,
6286                   G_TYPE_BOOLEAN, 1,
6287                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6288
6289   /**
6290    * ClutterActor::leave-event:
6291    * @actor: the actor which the pointer has left
6292    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6293    *
6294    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6295    *
6296    * Return value: %TRUE if the event has been handled by the actor,
6297    *   or %FALSE to continue the emission.
6298    *
6299    * Since: 0.6
6300    */
6301   actor_signals[LEAVE_EVENT] =
6302     g_signal_new (I_("leave-event"),
6303                   G_TYPE_FROM_CLASS (object_class),
6304                   G_SIGNAL_RUN_LAST,
6305                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6306                   _clutter_boolean_handled_accumulator, NULL,
6307                   _clutter_marshal_BOOLEAN__BOXED,
6308                   G_TYPE_BOOLEAN, 1,
6309                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6310
6311   /**
6312    * ClutterActor::captured-event:
6313    * @actor: the actor which received the signal
6314    * @event: a #ClutterEvent
6315    *
6316    * The ::captured-event signal is emitted when an event is captured
6317    * by Clutter. This signal will be emitted starting from the top-level
6318    * container (the #ClutterStage) to the actor which received the event
6319    * going down the hierarchy. This signal can be used to intercept every
6320    * event before the specialized events (like
6321    * ClutterActor::button-press-event or ::key-released-event) are
6322    * emitted.
6323    *
6324    * Return value: %TRUE if the event has been handled by the actor,
6325    *   or %FALSE to continue the emission.
6326    *
6327    * Since: 0.6
6328    */
6329   actor_signals[CAPTURED_EVENT] =
6330     g_signal_new (I_("captured-event"),
6331                   G_TYPE_FROM_CLASS (object_class),
6332                   G_SIGNAL_RUN_LAST,
6333                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6334                   _clutter_boolean_handled_accumulator, NULL,
6335                   _clutter_marshal_BOOLEAN__BOXED,
6336                   G_TYPE_BOOLEAN, 1,
6337                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6338
6339   /**
6340    * ClutterActor::paint:
6341    * @actor: the #ClutterActor that received the signal
6342    *
6343    * The ::paint signal is emitted each time an actor is being painted.
6344    *
6345    * Subclasses of #ClutterActor should override the class signal handler
6346    * and paint themselves in that function.
6347    *
6348    * It is possible to connect a handler to the ::paint signal in order
6349    * to set up some custom aspect of a paint.
6350    *
6351    * Since: 0.8
6352    */
6353   actor_signals[PAINT] =
6354     g_signal_new (I_("paint"),
6355                   G_TYPE_FROM_CLASS (object_class),
6356                   G_SIGNAL_RUN_LAST,
6357                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6358                   NULL, NULL,
6359                   _clutter_marshal_VOID__VOID,
6360                   G_TYPE_NONE, 0);
6361   /**
6362    * ClutterActor::realize:
6363    * @actor: the #ClutterActor that received the signal
6364    *
6365    * The ::realize signal is emitted each time an actor is being
6366    * realized.
6367    *
6368    * Since: 0.8
6369    */
6370   actor_signals[REALIZE] =
6371     g_signal_new (I_("realize"),
6372                   G_TYPE_FROM_CLASS (object_class),
6373                   G_SIGNAL_RUN_LAST,
6374                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6375                   NULL, NULL,
6376                   _clutter_marshal_VOID__VOID,
6377                   G_TYPE_NONE, 0);
6378   /**
6379    * ClutterActor::unrealize:
6380    * @actor: the #ClutterActor that received the signal
6381    *
6382    * The ::unrealize signal is emitted each time an actor is being
6383    * unrealized.
6384    *
6385    * Since: 0.8
6386    */
6387   actor_signals[UNREALIZE] =
6388     g_signal_new (I_("unrealize"),
6389                   G_TYPE_FROM_CLASS (object_class),
6390                   G_SIGNAL_RUN_LAST,
6391                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6392                   NULL, NULL,
6393                   _clutter_marshal_VOID__VOID,
6394                   G_TYPE_NONE, 0);
6395
6396   /**
6397    * ClutterActor::pick:
6398    * @actor: the #ClutterActor that received the signal
6399    * @color: the #ClutterColor to be used when picking
6400    *
6401    * The ::pick signal is emitted each time an actor is being painted
6402    * in "pick mode". The pick mode is used to identify the actor during
6403    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6404    * The actor should paint its shape using the passed @pick_color.
6405    *
6406    * Subclasses of #ClutterActor should override the class signal handler
6407    * and paint themselves in that function.
6408    *
6409    * It is possible to connect a handler to the ::pick signal in order
6410    * to set up some custom aspect of a paint in pick mode.
6411    *
6412    * Since: 1.0
6413    */
6414   actor_signals[PICK] =
6415     g_signal_new (I_("pick"),
6416                   G_TYPE_FROM_CLASS (object_class),
6417                   G_SIGNAL_RUN_LAST,
6418                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6419                   NULL, NULL,
6420                   _clutter_marshal_VOID__BOXED,
6421                   G_TYPE_NONE, 1,
6422                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6423
6424   /**
6425    * ClutterActor::allocation-changed:
6426    * @actor: the #ClutterActor that emitted the signal
6427    * @box: a #ClutterActorBox with the new allocation
6428    * @flags: #ClutterAllocationFlags for the allocation
6429    *
6430    * The ::allocation-changed signal is emitted when the
6431    * #ClutterActor:allocation property changes. Usually, application
6432    * code should just use the notifications for the :allocation property
6433    * but if you want to track the allocation flags as well, for instance
6434    * to know whether the absolute origin of @actor changed, then you might
6435    * want use this signal instead.
6436    *
6437    * Since: 1.0
6438    */
6439   actor_signals[ALLOCATION_CHANGED] =
6440     g_signal_new (I_("allocation-changed"),
6441                   G_TYPE_FROM_CLASS (object_class),
6442                   G_SIGNAL_RUN_LAST,
6443                   0,
6444                   NULL, NULL,
6445                   _clutter_marshal_VOID__BOXED_FLAGS,
6446                   G_TYPE_NONE, 2,
6447                   CLUTTER_TYPE_ACTOR_BOX,
6448                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6449 }
6450
6451 static void
6452 clutter_actor_init (ClutterActor *self)
6453 {
6454   ClutterActorPrivate *priv;
6455
6456   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6457
6458   priv->id = _clutter_context_acquire_id (self);
6459   priv->pick_id = -1;
6460
6461   priv->opacity = 0xff;
6462   priv->show_on_set_parent = TRUE;
6463
6464   priv->needs_width_request = TRUE;
6465   priv->needs_height_request = TRUE;
6466   priv->needs_allocation = TRUE;
6467
6468   priv->cached_width_age = 1;
6469   priv->cached_height_age = 1;
6470
6471   priv->opacity_override = -1;
6472   priv->enable_model_view_transform = TRUE;
6473
6474   /* Initialize an empty paint volume to start with */
6475   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6476   priv->last_paint_volume_valid = TRUE;
6477
6478   priv->transform_valid = FALSE;
6479 }
6480
6481 /**
6482  * clutter_actor_new:
6483  *
6484  * Creates a new #ClutterActor.
6485  *
6486  * A newly created actor has a floating reference, which will be sunk
6487  * when it is added to another actor.
6488  *
6489  * Return value: (transfer full): the newly created #ClutterActor
6490  *
6491  * Since: 1.10
6492  */
6493 ClutterActor *
6494 clutter_actor_new (void)
6495 {
6496   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6497 }
6498
6499 /**
6500  * clutter_actor_destroy:
6501  * @self: a #ClutterActor
6502  *
6503  * Destroys an actor.  When an actor is destroyed, it will break any
6504  * references it holds to other objects.  If the actor is inside a
6505  * container, the actor will be removed.
6506  *
6507  * When you destroy a container, its children will be destroyed as well.
6508  *
6509  * Note: you cannot destroy the #ClutterStage returned by
6510  * clutter_stage_get_default().
6511  */
6512 void
6513 clutter_actor_destroy (ClutterActor *self)
6514 {
6515   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6516
6517   g_object_ref (self);
6518
6519   /* avoid recursion while destroying */
6520   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6521     {
6522       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6523
6524       g_object_run_dispose (G_OBJECT (self));
6525
6526       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6527     }
6528
6529   g_object_unref (self);
6530 }
6531
6532 void
6533 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6534                                     ClutterPaintVolume *clip)
6535 {
6536   ClutterActorPrivate *priv = self->priv;
6537   ClutterPaintVolume *pv;
6538   gboolean clipped;
6539
6540   /* If we've been explicitly passed a clip volume then there's
6541    * nothing more to calculate, but otherwise the only thing we know
6542    * is that the change is constrained to the given actor.
6543    *
6544    * The idea is that if we know the paint volume for where the actor
6545    * was last drawn (in eye coordinates) and we also have the paint
6546    * volume for where it will be drawn next (in actor coordinates)
6547    * then if we queue a redraw for both these volumes that will cover
6548    * everything that needs to be redrawn to clear the old view and
6549    * show the latest view of the actor.
6550    *
6551    * Don't clip this redraw if we don't know what position we had for
6552    * the previous redraw since we don't know where to set the clip so
6553    * it will clear the actor as it is currently.
6554    */
6555   if (clip)
6556     {
6557       _clutter_actor_set_queue_redraw_clip (self, clip);
6558       clipped = TRUE;
6559     }
6560   else if (G_LIKELY (priv->last_paint_volume_valid))
6561     {
6562       pv = _clutter_actor_get_paint_volume_mutable (self);
6563       if (pv)
6564         {
6565           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6566
6567           /* make sure we redraw the actors old position... */
6568           _clutter_actor_set_queue_redraw_clip (stage,
6569                                                 &priv->last_paint_volume);
6570           _clutter_actor_signal_queue_redraw (stage, stage);
6571           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6572
6573           /* XXX: Ideally the redraw signal would take a clip volume
6574            * argument, but that would be an ABI break. Until we can
6575            * break the ABI we pass the argument out-of-band
6576            */
6577
6578           /* setup the clip for the actors new position... */
6579           _clutter_actor_set_queue_redraw_clip (self, pv);
6580           clipped = TRUE;
6581         }
6582       else
6583         clipped = FALSE;
6584     }
6585   else
6586     clipped = FALSE;
6587
6588   _clutter_actor_signal_queue_redraw (self, self);
6589
6590   /* Just in case anyone is manually firing redraw signals without
6591    * using the public queue_redraw() API we are careful to ensure that
6592    * our out-of-band clip member is cleared before returning...
6593    *
6594    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6595    */
6596   if (G_LIKELY (clipped))
6597     _clutter_actor_set_queue_redraw_clip (self, NULL);
6598
6599   priv->queue_redraw_entry = NULL;
6600 }
6601
6602 static void
6603 _clutter_actor_get_allocation_clip (ClutterActor *self,
6604                                     ClutterActorBox *clip)
6605 {
6606   ClutterActorBox allocation;
6607
6608   /* XXX: we don't care if we get an out of date allocation here
6609    * because clutter_actor_queue_redraw_with_clip knows to ignore
6610    * the clip if the actor's allocation is invalid.
6611    *
6612    * This is noted because clutter_actor_get_allocation_box does some
6613    * unnecessary work to support buggy code with a comment suggesting
6614    * that it could be changed later which would be good for this use
6615    * case!
6616    */
6617   clutter_actor_get_allocation_box (self, &allocation);
6618
6619   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6620    * actor's own coordinate space but the allocation is in parent
6621    * coordinates */
6622   clip->x1 = 0;
6623   clip->y1 = 0;
6624   clip->x2 = allocation.x2 - allocation.x1;
6625   clip->y2 = allocation.y2 - allocation.y1;
6626 }
6627
6628 void
6629 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6630                                   ClutterRedrawFlags  flags,
6631                                   ClutterPaintVolume *volume,
6632                                   ClutterEffect      *effect)
6633 {
6634   ClutterActorPrivate *priv = self->priv;
6635   ClutterPaintVolume allocation_pv;
6636   ClutterPaintVolume *pv;
6637   gboolean should_free_pv;
6638   ClutterActor *stage;
6639
6640   /* Here's an outline of the actor queue redraw mechanism:
6641    *
6642    * The process starts in one of the following two functions which
6643    * are wrappers for this function:
6644    * clutter_actor_queue_redraw
6645    * _clutter_actor_queue_redraw_with_clip
6646    *
6647    * additionally, an effect can queue a redraw by wrapping this
6648    * function in clutter_effect_queue_rerun
6649    *
6650    * This functions queues an entry in a list associated with the
6651    * stage which is a list of actors that queued a redraw while
6652    * updating the timelines, performing layouting and processing other
6653    * mainloop sources before the next paint starts.
6654    *
6655    * We aim to minimize the processing done at this point because
6656    * there is a good chance other events will happen while updating
6657    * the scenegraph that would invalidate any expensive work we might
6658    * otherwise try to do here. For example we don't try and resolve
6659    * the screen space bounding box of an actor at this stage so as to
6660    * minimize how much of the screen redraw because it's possible
6661    * something else will happen which will force a full redraw anyway.
6662    *
6663    * When all updates are complete and we come to paint the stage then
6664    * we iterate this list and actually emit the "queue-redraw" signals
6665    * for each of the listed actors which will bubble up to the stage
6666    * for each actor and at that point we will transform the actors
6667    * paint volume into screen coordinates to determine the clip region
6668    * for what needs to be redrawn in the next paint.
6669    *
6670    * Besides minimizing redundant work another reason for this
6671    * deferred design is that it's more likely we will be able to
6672    * determine the paint volume of an actor once we've finished
6673    * updating the scenegraph because its allocation should be up to
6674    * date. NB: If we can't determine an actors paint volume then we
6675    * can't automatically queue a clipped redraw which can make a big
6676    * difference to performance.
6677    *
6678    * So the control flow goes like this:
6679    * One of clutter_actor_queue_redraw,
6680    *        _clutter_actor_queue_redraw_with_clip
6681    *     or clutter_effect_queue_rerun
6682    *
6683    * then control moves to:
6684    *   _clutter_stage_queue_actor_redraw
6685    *
6686    * later during _clutter_stage_do_update, once relayouting is done
6687    * and the scenegraph has been updated we will call:
6688    * _clutter_stage_finish_queue_redraws
6689    *
6690    * _clutter_stage_finish_queue_redraws will call
6691    * _clutter_actor_finish_queue_redraw for each listed actor.
6692    * Note: actors *are* allowed to queue further redraws during this
6693    * process (considering clone actors or texture_new_from_actor which
6694    * respond to their source queueing a redraw by queuing a redraw
6695    * themselves). We repeat the process until the list is empty.
6696    *
6697    * This will result in the "queue-redraw" signal being fired for
6698    * each actor which will pass control to the default signal handler:
6699    * clutter_actor_real_queue_redraw
6700    *
6701    * This will bubble up to the stages handler:
6702    * clutter_stage_real_queue_redraw
6703    *
6704    * clutter_stage_real_queue_redraw will transform the actors paint
6705    * volume into screen space and add it as a clip region for the next
6706    * paint.
6707    */
6708
6709   /* ignore queueing a redraw for actors being destroyed */
6710   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6711     return;
6712
6713   stage = _clutter_actor_get_stage_internal (self);
6714
6715   /* Ignore queueing a redraw for actors not descended from a stage */
6716   if (stage == NULL)
6717     return;
6718
6719   /* ignore queueing a redraw on stages that are being destroyed */
6720   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6721     return;
6722
6723   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6724     {
6725       ClutterActorBox allocation_clip;
6726       ClutterVertex origin;
6727
6728       /* If the actor doesn't have a valid allocation then we will
6729        * queue a full stage redraw. */
6730       if (priv->needs_allocation)
6731         {
6732           /* NB: NULL denotes an undefined clip which will result in a
6733            * full redraw... */
6734           _clutter_actor_set_queue_redraw_clip (self, NULL);
6735           _clutter_actor_signal_queue_redraw (self, self);
6736           return;
6737         }
6738
6739       _clutter_paint_volume_init_static (&allocation_pv, self);
6740       pv = &allocation_pv;
6741
6742       _clutter_actor_get_allocation_clip (self, &allocation_clip);
6743
6744       origin.x = allocation_clip.x1;
6745       origin.y = allocation_clip.y1;
6746       origin.z = 0;
6747       clutter_paint_volume_set_origin (pv, &origin);
6748       clutter_paint_volume_set_width (pv,
6749                                       allocation_clip.x2 - allocation_clip.x1);
6750       clutter_paint_volume_set_height (pv,
6751                                        allocation_clip.y2 -
6752                                        allocation_clip.y1);
6753       should_free_pv = TRUE;
6754     }
6755   else
6756     {
6757       pv = volume;
6758       should_free_pv = FALSE;
6759     }
6760
6761   self->priv->queue_redraw_entry =
6762     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6763                                        priv->queue_redraw_entry,
6764                                        self,
6765                                        pv);
6766
6767   if (should_free_pv)
6768     clutter_paint_volume_free (pv);
6769
6770   /* If this is the first redraw queued then we can directly use the
6771      effect parameter */
6772   if (!priv->is_dirty)
6773     priv->effect_to_redraw = effect;
6774   /* Otherwise we need to merge it with the existing effect parameter */
6775   else if (effect != NULL)
6776     {
6777       /* If there's already an effect then we need to use whichever is
6778          later in the chain of actors. Otherwise a full redraw has
6779          already been queued on the actor so we need to ignore the
6780          effect parameter */
6781       if (priv->effect_to_redraw != NULL)
6782         {
6783           if (priv->effects == NULL)
6784             g_warning ("Redraw queued with an effect that is "
6785                        "not applied to the actor");
6786           else
6787             {
6788               const GList *l;
6789
6790               for (l = _clutter_meta_group_peek_metas (priv->effects);
6791                    l != NULL;
6792                    l = l->next)
6793                 {
6794                   if (l->data == priv->effect_to_redraw ||
6795                       l->data == effect)
6796                     priv->effect_to_redraw = l->data;
6797                 }
6798             }
6799         }
6800     }
6801   else
6802     {
6803       /* If no effect is specified then we need to redraw the whole
6804          actor */
6805       priv->effect_to_redraw = NULL;
6806     }
6807
6808   priv->is_dirty = TRUE;
6809 }
6810
6811 /**
6812  * clutter_actor_queue_redraw:
6813  * @self: A #ClutterActor
6814  *
6815  * Queues up a redraw of an actor and any children. The redraw occurs
6816  * once the main loop becomes idle (after the current batch of events
6817  * has been processed, roughly).
6818  *
6819  * Applications rarely need to call this, as redraws are handled
6820  * automatically by modification functions.
6821  *
6822  * This function will not do anything if @self is not visible, or
6823  * if the actor is inside an invisible part of the scenegraph.
6824  *
6825  * Also be aware that painting is a NOP for actors with an opacity of
6826  * 0
6827  *
6828  * When you are implementing a custom actor you must queue a redraw
6829  * whenever some private state changes that will affect painting or
6830  * picking of your actor.
6831  */
6832 void
6833 clutter_actor_queue_redraw (ClutterActor *self)
6834 {
6835   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6836
6837   _clutter_actor_queue_redraw_full (self,
6838                                     0, /* flags */
6839                                     NULL, /* clip volume */
6840                                     NULL /* effect */);
6841 }
6842
6843 /*< private >
6844  * _clutter_actor_queue_redraw_with_clip:
6845  * @self: A #ClutterActor
6846  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
6847  *   this queue redraw.
6848  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
6849  *   redrawn or %NULL if you are just using a @flag to state your
6850  *   desired clipping.
6851  *
6852  * Queues up a clipped redraw of an actor and any children. The redraw
6853  * occurs once the main loop becomes idle (after the current batch of
6854  * events has been processed, roughly).
6855  *
6856  * If no flags are given the clip volume is defined by @volume
6857  * specified in actor coordinates and tells Clutter that only content
6858  * within this volume has been changed so Clutter can optionally
6859  * optimize the redraw.
6860  *
6861  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
6862  * should be %NULL and this tells Clutter to use the actor's current
6863  * allocation as a clip box. This flag can only be used for 2D actors,
6864  * because any actor with depth may be projected outside its
6865  * allocation.
6866  *
6867  * Applications rarely need to call this, as redraws are handled
6868  * automatically by modification functions.
6869  *
6870  * This function will not do anything if @self is not visible, or if
6871  * the actor is inside an invisible part of the scenegraph.
6872  *
6873  * Also be aware that painting is a NOP for actors with an opacity of
6874  * 0
6875  *
6876  * When you are implementing a custom actor you must queue a redraw
6877  * whenever some private state changes that will affect painting or
6878  * picking of your actor.
6879  */
6880 void
6881 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
6882                                        ClutterRedrawFlags  flags,
6883                                        ClutterPaintVolume *volume)
6884 {
6885   _clutter_actor_queue_redraw_full (self,
6886                                     flags, /* flags */
6887                                     volume, /* clip volume */
6888                                     NULL /* effect */);
6889 }
6890
6891 static void
6892 _clutter_actor_queue_only_relayout (ClutterActor *self)
6893 {
6894   ClutterActorPrivate *priv = self->priv;
6895
6896   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6897     return;
6898
6899   if (priv->needs_width_request &&
6900       priv->needs_height_request &&
6901       priv->needs_allocation)
6902     return; /* save some cpu cycles */
6903
6904 #if CLUTTER_ENABLE_DEBUG
6905   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
6906     {
6907       g_warning ("The actor '%s' is currently inside an allocation "
6908                  "cycle; calling clutter_actor_queue_relayout() is "
6909                  "not recommended",
6910                  _clutter_actor_get_debug_name (self));
6911     }
6912 #endif /* CLUTTER_ENABLE_DEBUG */
6913
6914   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
6915 }
6916
6917 /**
6918  * clutter_actor_queue_redraw_with_clip:
6919  * @self: a #ClutterActor
6920  * @clip: (allow-none): a rectangular clip region, or %NULL
6921  *
6922  * Queues a redraw on @self limited to a specific, actor-relative
6923  * rectangular area.
6924  *
6925  * If @clip is %NULL this function is equivalent to
6926  * clutter_actor_queue_redraw().
6927  *
6928  * Since: 1.10
6929  */
6930 void
6931 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
6932                                       const cairo_rectangle_int_t *clip)
6933 {
6934   ClutterPaintVolume volume;
6935   ClutterVertex origin;
6936
6937   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6938
6939   if (clip == NULL)
6940     {
6941       clutter_actor_queue_redraw (self);
6942       return;
6943     }
6944
6945   _clutter_paint_volume_init_static (&volume, self);
6946
6947   origin.x = clip->x;
6948   origin.y = clip->y;
6949   origin.z = 0.0f;
6950
6951   clutter_paint_volume_set_origin (&volume, &origin);
6952   clutter_paint_volume_set_width (&volume, clip->width);
6953   clutter_paint_volume_set_height (&volume, clip->height);
6954
6955   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
6956
6957   clutter_paint_volume_free (&volume);
6958 }
6959
6960 /**
6961  * clutter_actor_queue_relayout:
6962  * @self: A #ClutterActor
6963  *
6964  * Indicates that the actor's size request or other layout-affecting
6965  * properties may have changed. This function is used inside #ClutterActor
6966  * subclass implementations, not by applications directly.
6967  *
6968  * Queueing a new layout automatically queues a redraw as well.
6969  *
6970  * Since: 0.8
6971  */
6972 void
6973 clutter_actor_queue_relayout (ClutterActor *self)
6974 {
6975   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6976
6977   _clutter_actor_queue_only_relayout (self);
6978   clutter_actor_queue_redraw (self);
6979 }
6980
6981 /**
6982  * clutter_actor_get_preferred_size:
6983  * @self: a #ClutterActor
6984  * @min_width_p: (out) (allow-none): return location for the minimum
6985  *   width, or %NULL
6986  * @min_height_p: (out) (allow-none): return location for the minimum
6987  *   height, or %NULL
6988  * @natural_width_p: (out) (allow-none): return location for the natural
6989  *   width, or %NULL
6990  * @natural_height_p: (out) (allow-none): return location for the natural
6991  *   height, or %NULL
6992  *
6993  * Computes the preferred minimum and natural size of an actor, taking into
6994  * account the actor's geometry management (either height-for-width
6995  * or width-for-height).
6996  *
6997  * The width and height used to compute the preferred height and preferred
6998  * width are the actor's natural ones.
6999  *
7000  * If you need to control the height for the preferred width, or the width for
7001  * the preferred height, you should use clutter_actor_get_preferred_width()
7002  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7003  * geometry management using the #ClutterActor:request-mode property.
7004  *
7005  * Since: 0.8
7006  */
7007 void
7008 clutter_actor_get_preferred_size (ClutterActor *self,
7009                                   gfloat       *min_width_p,
7010                                   gfloat       *min_height_p,
7011                                   gfloat       *natural_width_p,
7012                                   gfloat       *natural_height_p)
7013 {
7014   ClutterActorPrivate *priv;
7015   gfloat min_width, min_height;
7016   gfloat natural_width, natural_height;
7017
7018   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7019
7020   priv = self->priv;
7021
7022   min_width = min_height = 0;
7023   natural_width = natural_height = 0;
7024
7025   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7026     {
7027       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7028       clutter_actor_get_preferred_width (self, -1,
7029                                          &min_width,
7030                                          &natural_width);
7031       clutter_actor_get_preferred_height (self, natural_width,
7032                                           &min_height,
7033                                           &natural_height);
7034     }
7035   else
7036     {
7037       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7038       clutter_actor_get_preferred_height (self, -1,
7039                                           &min_height,
7040                                           &natural_height);
7041       clutter_actor_get_preferred_width (self, natural_height,
7042                                          &min_width,
7043                                          &natural_width);
7044     }
7045
7046   if (min_width_p)
7047     *min_width_p = min_width;
7048
7049   if (min_height_p)
7050     *min_height_p = min_height;
7051
7052   if (natural_width_p)
7053     *natural_width_p = natural_width;
7054
7055   if (natural_height_p)
7056     *natural_height_p = natural_height;
7057 }
7058
7059 /*< private >
7060  * effective_align:
7061  * @align: a #ClutterActorAlign
7062  * @direction: a #ClutterTextDirection
7063  *
7064  * Retrieves the correct alignment depending on the text direction
7065  *
7066  * Return value: the effective alignment
7067  */
7068 static ClutterActorAlign
7069 effective_align (ClutterActorAlign    align,
7070                  ClutterTextDirection direction)
7071 {
7072   ClutterActorAlign res;
7073
7074   switch (align)
7075     {
7076     case CLUTTER_ACTOR_ALIGN_START:
7077       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7078           ? CLUTTER_ACTOR_ALIGN_END
7079           : CLUTTER_ACTOR_ALIGN_START;
7080       break;
7081
7082     case CLUTTER_ACTOR_ALIGN_END:
7083       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7084           ? CLUTTER_ACTOR_ALIGN_START
7085           : CLUTTER_ACTOR_ALIGN_END;
7086       break;
7087
7088     default:
7089       res = align;
7090       break;
7091     }
7092
7093   return res;
7094 }
7095
7096 static inline void
7097 adjust_for_margin (float  margin_start,
7098                    float  margin_end,
7099                    float *minimum_size,
7100                    float *natural_size,
7101                    float *allocated_start,
7102                    float *allocated_end)
7103 {
7104   *minimum_size -= (margin_start + margin_end);
7105   *natural_size -= (margin_start + margin_end);
7106   *allocated_start += margin_start;
7107   *allocated_end -= margin_end;
7108 }
7109
7110 static inline void
7111 adjust_for_alignment (ClutterActorAlign  alignment,
7112                       float              natural_size,
7113                       float             *allocated_start,
7114                       float             *allocated_end)
7115 {
7116   float allocated_size = *allocated_end - *allocated_start;
7117
7118   switch (alignment)
7119     {
7120     case CLUTTER_ACTOR_ALIGN_FILL:
7121       /* do nothing */
7122       break;
7123
7124     case CLUTTER_ACTOR_ALIGN_START:
7125       /* keep start */
7126       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7127       break;
7128
7129     case CLUTTER_ACTOR_ALIGN_END:
7130       if (allocated_size > natural_size)
7131         {
7132           *allocated_start += (allocated_size - natural_size);
7133           *allocated_end = *allocated_start + natural_size;
7134         }
7135       break;
7136
7137     case CLUTTER_ACTOR_ALIGN_CENTER:
7138       if (allocated_size > natural_size)
7139         {
7140           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7141           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7142         }
7143       break;
7144     }
7145 }
7146
7147 /*< private >
7148  * clutter_actor_adjust_width:
7149  * @self: a #ClutterActor
7150  * @minimum_width: (inout): the actor's preferred minimum width, which
7151  *   will be adjusted depending on the margin
7152  * @natural_width: (inout): the actor's preferred natural width, which
7153  *   will be adjusted depending on the margin
7154  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7155  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7156  *
7157  * Adjusts the preferred and allocated position and size of an actor,
7158  * depending on the margin and alignment properties.
7159  */
7160 static void
7161 clutter_actor_adjust_width (ClutterActor *self,
7162                             gfloat       *minimum_width,
7163                             gfloat       *natural_width,
7164                             gfloat       *adjusted_x1,
7165                             gfloat       *adjusted_x2)
7166 {
7167   ClutterTextDirection text_dir;
7168   const ClutterLayoutInfo *info;
7169
7170   info = _clutter_actor_get_layout_info_or_defaults (self);
7171   text_dir = clutter_actor_get_text_direction (self);
7172
7173   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7174
7175   /* this will tweak natural_width to remove the margin, so that
7176    * adjust_for_alignment() will use the correct size
7177    */
7178   adjust_for_margin (info->margin.left, info->margin.right,
7179                      minimum_width, natural_width,
7180                      adjusted_x1, adjusted_x2);
7181
7182   adjust_for_alignment (effective_align (info->x_align, text_dir),
7183                         *natural_width,
7184                         adjusted_x1, adjusted_x2);
7185 }
7186
7187 /*< private >
7188  * clutter_actor_adjust_height:
7189  * @self: a #ClutterActor
7190  * @minimum_height: (inout): the actor's preferred minimum height, which
7191  *   will be adjusted depending on the margin
7192  * @natural_height: (inout): the actor's preferred natural height, which
7193  *   will be adjusted depending on the margin
7194  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7195  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7196  *
7197  * Adjusts the preferred and allocated position and size of an actor,
7198  * depending on the margin and alignment properties.
7199  */
7200 static void
7201 clutter_actor_adjust_height (ClutterActor *self,
7202                              gfloat       *minimum_height,
7203                              gfloat       *natural_height,
7204                              gfloat       *adjusted_y1,
7205                              gfloat       *adjusted_y2)
7206 {
7207   const ClutterLayoutInfo *info;
7208
7209   info = _clutter_actor_get_layout_info_or_defaults (self);
7210
7211   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7212
7213   /* this will tweak natural_height to remove the margin, so that
7214    * adjust_for_alignment() will use the correct size
7215    */
7216   adjust_for_margin (info->margin.top, info->margin.bottom,
7217                      minimum_height, natural_height,
7218                      adjusted_y1,
7219                      adjusted_y2);
7220
7221   /* we don't use effective_align() here, because text direction
7222    * only affects the horizontal axis
7223    */
7224   adjust_for_alignment (info->y_align,
7225                         *natural_height,
7226                         adjusted_y1,
7227                         adjusted_y2);
7228
7229 }
7230
7231 /* looks for a cached size request for this for_size. If not
7232  * found, returns the oldest entry so it can be overwritten */
7233 static gboolean
7234 _clutter_actor_get_cached_size_request (gfloat         for_size,
7235                                         SizeRequest   *cached_size_requests,
7236                                         SizeRequest  **result)
7237 {
7238   guint i;
7239
7240   *result = &cached_size_requests[0];
7241
7242   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7243     {
7244       SizeRequest *sr;
7245
7246       sr = &cached_size_requests[i];
7247
7248       if (sr->age > 0 &&
7249           sr->for_size == for_size)
7250         {
7251           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7252           *result = sr;
7253           return TRUE;
7254         }
7255       else if (sr->age < (*result)->age)
7256         {
7257           *result = sr;
7258         }
7259     }
7260
7261   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7262
7263   return FALSE;
7264 }
7265
7266 /**
7267  * clutter_actor_get_preferred_width:
7268  * @self: A #ClutterActor
7269  * @for_height: available height when computing the preferred width,
7270  *   or a negative value to indicate that no height is defined
7271  * @min_width_p: (out) (allow-none): return location for minimum width,
7272  *   or %NULL
7273  * @natural_width_p: (out) (allow-none): return location for the natural
7274  *   width, or %NULL
7275  *
7276  * Computes the requested minimum and natural widths for an actor,
7277  * optionally depending on the specified height, or if they are
7278  * already computed, returns the cached values.
7279  *
7280  * An actor may not get its request - depending on the layout
7281  * manager that's in effect.
7282  *
7283  * A request should not incorporate the actor's scale or anchor point;
7284  * those transformations do not affect layout, only rendering.
7285  *
7286  * Since: 0.8
7287  */
7288 void
7289 clutter_actor_get_preferred_width (ClutterActor *self,
7290                                    gfloat        for_height,
7291                                    gfloat       *min_width_p,
7292                                    gfloat       *natural_width_p)
7293 {
7294   float request_min_width, request_natural_width;
7295   SizeRequest *cached_size_request;
7296   const ClutterLayoutInfo *info;
7297   ClutterActorPrivate *priv;
7298   gboolean found_in_cache;
7299
7300   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7301
7302   priv = self->priv;
7303
7304   info = _clutter_actor_get_layout_info_or_defaults (self);
7305
7306   /* we shortcircuit the case of a fixed size set using set_width() */
7307   if (priv->min_width_set && priv->natural_width_set)
7308     {
7309       if (min_width_p != NULL)
7310         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7311
7312       if (natural_width_p != NULL)
7313         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7314
7315       return;
7316     }
7317
7318   /* the remaining cases are:
7319    *
7320    *   - either min_width or natural_width have been set
7321    *   - neither min_width or natural_width have been set
7322    *
7323    * in both cases, we go through the cache (and through the actor in case
7324    * of cache misses) and determine the authoritative value depending on
7325    * the *_set flags.
7326    */
7327
7328   if (!priv->needs_width_request)
7329     {
7330       found_in_cache =
7331         _clutter_actor_get_cached_size_request (for_height,
7332                                                 priv->width_requests,
7333                                                 &cached_size_request);
7334     }
7335   else
7336     {
7337       /* if the actor needs a width request we use the first slot */
7338       found_in_cache = FALSE;
7339       cached_size_request = &priv->width_requests[0];
7340     }
7341
7342   if (!found_in_cache)
7343     {
7344       gfloat minimum_width, natural_width;
7345       ClutterActorClass *klass;
7346
7347       minimum_width = natural_width = 0;
7348
7349       /* adjust for the margin */
7350       if (for_height >= 0)
7351         {
7352           for_height -= (info->margin.top + info->margin.bottom);
7353           if (for_height < 0)
7354             for_height = 0;
7355         }
7356
7357       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7358
7359       klass = CLUTTER_ACTOR_GET_CLASS (self);
7360       klass->get_preferred_width (self, for_height,
7361                                   &minimum_width,
7362                                   &natural_width);
7363
7364       /* adjust for the margin */
7365       minimum_width += (info->margin.left + info->margin.right);
7366       natural_width += (info->margin.left + info->margin.right);
7367
7368       /* Due to accumulated float errors, it's better not to warn
7369        * on this, but just fix it.
7370        */
7371       if (natural_width < minimum_width)
7372         natural_width = minimum_width;
7373
7374       cached_size_request->min_size = minimum_width;
7375       cached_size_request->natural_size = natural_width;
7376       cached_size_request->for_size = for_height;
7377       cached_size_request->age = priv->cached_width_age;
7378
7379       priv->cached_width_age += 1;
7380       priv->needs_width_request = FALSE;
7381     }
7382
7383   if (!priv->min_width_set)
7384     request_min_width = cached_size_request->min_size;
7385   else
7386     request_min_width = info->min_width;
7387
7388   if (!priv->natural_width_set)
7389     request_natural_width = cached_size_request->natural_size;
7390   else
7391     request_natural_width = info->natural_width;
7392
7393   if (min_width_p)
7394     *min_width_p = request_min_width;
7395
7396   if (natural_width_p)
7397     *natural_width_p = request_natural_width;
7398 }
7399
7400 /**
7401  * clutter_actor_get_preferred_height:
7402  * @self: A #ClutterActor
7403  * @for_width: available width to assume in computing desired height,
7404  *   or a negative value to indicate that no width is defined
7405  * @min_height_p: (out) (allow-none): return location for minimum height,
7406  *   or %NULL
7407  * @natural_height_p: (out) (allow-none): return location for natural
7408  *   height, or %NULL
7409  *
7410  * Computes the requested minimum and natural heights for an actor,
7411  * or if they are already computed, returns the cached values.
7412  *
7413  * An actor may not get its request - depending on the layout
7414  * manager that's in effect.
7415  *
7416  * A request should not incorporate the actor's scale or anchor point;
7417  * those transformations do not affect layout, only rendering.
7418  *
7419  * Since: 0.8
7420  */
7421 void
7422 clutter_actor_get_preferred_height (ClutterActor *self,
7423                                     gfloat        for_width,
7424                                     gfloat       *min_height_p,
7425                                     gfloat       *natural_height_p)
7426 {
7427   float request_min_height, request_natural_height;
7428   SizeRequest *cached_size_request;
7429   const ClutterLayoutInfo *info;
7430   ClutterActorPrivate *priv;
7431   gboolean found_in_cache;
7432
7433   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7434
7435   priv = self->priv;
7436
7437   info = _clutter_actor_get_layout_info_or_defaults (self);
7438
7439   /* we shortcircuit the case of a fixed size set using set_height() */
7440   if (priv->min_height_set && priv->natural_height_set)
7441     {
7442       if (min_height_p != NULL)
7443         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7444
7445       if (natural_height_p != NULL)
7446         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7447
7448       return;
7449     }
7450
7451   /* the remaining cases are:
7452    *
7453    *   - either min_height or natural_height have been set
7454    *   - neither min_height or natural_height have been set
7455    *
7456    * in both cases, we go through the cache (and through the actor in case
7457    * of cache misses) and determine the authoritative value depending on
7458    * the *_set flags.
7459    */
7460
7461   if (!priv->needs_height_request)
7462     {
7463       found_in_cache =
7464         _clutter_actor_get_cached_size_request (for_width,
7465                                                 priv->height_requests,
7466                                                 &cached_size_request);
7467     }
7468   else
7469     {
7470       found_in_cache = FALSE;
7471       cached_size_request = &priv->height_requests[0];
7472     }
7473
7474   if (!found_in_cache)
7475     {
7476       gfloat minimum_height, natural_height;
7477       ClutterActorClass *klass;
7478
7479       minimum_height = natural_height = 0;
7480
7481       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7482
7483       /* adjust for margin */
7484       if (for_width >= 0)
7485         {
7486           for_width -= (info->margin.left + info->margin.right);
7487           if (for_width < 0)
7488             for_width = 0;
7489         }
7490
7491       klass = CLUTTER_ACTOR_GET_CLASS (self);
7492       klass->get_preferred_height (self, for_width,
7493                                    &minimum_height,
7494                                    &natural_height);
7495
7496       /* adjust for margin */
7497       minimum_height += (info->margin.top + info->margin.bottom);
7498       natural_height += (info->margin.top + info->margin.bottom);
7499
7500       /* Due to accumulated float errors, it's better not to warn
7501        * on this, but just fix it.
7502        */
7503       if (natural_height < minimum_height)
7504         natural_height = minimum_height;
7505
7506       cached_size_request->min_size = minimum_height;
7507       cached_size_request->natural_size = natural_height;
7508       cached_size_request->for_size = for_width;
7509       cached_size_request->age = priv->cached_height_age;
7510
7511       priv->cached_height_age += 1;
7512       priv->needs_height_request = FALSE;
7513     }
7514
7515   if (!priv->min_height_set)
7516     request_min_height = cached_size_request->min_size;
7517   else
7518     request_min_height = info->min_height;
7519
7520   if (!priv->natural_height_set)
7521     request_natural_height = cached_size_request->natural_size;
7522   else
7523     request_natural_height = info->natural_height;
7524
7525   if (min_height_p)
7526     *min_height_p = request_min_height;
7527
7528   if (natural_height_p)
7529     *natural_height_p = request_natural_height;
7530 }
7531
7532 /**
7533  * clutter_actor_get_allocation_box:
7534  * @self: A #ClutterActor
7535  * @box: (out): the function fills this in with the actor's allocation
7536  *
7537  * Gets the layout box an actor has been assigned. The allocation can
7538  * only be assumed valid inside a paint() method; anywhere else, it
7539  * may be out-of-date.
7540  *
7541  * An allocation does not incorporate the actor's scale or anchor point;
7542  * those transformations do not affect layout, only rendering.
7543  *
7544  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7545  * of functions inside the implementation of the get_preferred_width()
7546  * or get_preferred_height() virtual functions.</note>
7547  *
7548  * Since: 0.8
7549  */
7550 void
7551 clutter_actor_get_allocation_box (ClutterActor    *self,
7552                                   ClutterActorBox *box)
7553 {
7554   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7555
7556   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7557    * which limits calling get_allocation to inside paint() basically; or
7558    * we can 2) force a layout, which could be expensive if someone calls
7559    * get_allocation somewhere silly; or we can 3) just return the latest
7560    * value, allowing it to be out-of-date, and assume people know what
7561    * they are doing.
7562    *
7563    * The least-surprises approach that keeps existing code working is
7564    * likely to be 2). People can end up doing some inefficient things,
7565    * though, and in general code that requires 2) is probably broken.
7566    */
7567
7568   /* this implements 2) */
7569   if (G_UNLIKELY (self->priv->needs_allocation))
7570     {
7571       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7572
7573       /* do not queue a relayout on an unparented actor */
7574       if (stage)
7575         _clutter_stage_maybe_relayout (stage);
7576     }
7577
7578   /* commenting out the code above and just keeping this assigment
7579    * implements 3)
7580    */
7581   *box = self->priv->allocation;
7582 }
7583
7584 /**
7585  * clutter_actor_get_allocation_geometry:
7586  * @self: A #ClutterActor
7587  * @geom: (out): allocation geometry in pixels
7588  *
7589  * Gets the layout box an actor has been assigned.  The allocation can
7590  * only be assumed valid inside a paint() method; anywhere else, it
7591  * may be out-of-date.
7592  *
7593  * An allocation does not incorporate the actor's scale or anchor point;
7594  * those transformations do not affect layout, only rendering.
7595  *
7596  * The returned rectangle is in pixels.
7597  *
7598  * Since: 0.8
7599  */
7600 void
7601 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7602                                        ClutterGeometry *geom)
7603 {
7604   ClutterActorBox box;
7605
7606   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7607   g_return_if_fail (geom != NULL);
7608
7609   clutter_actor_get_allocation_box (self, &box);
7610
7611   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7612   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7613   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7614   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7615 }
7616
7617 static void
7618 clutter_actor_update_constraints (ClutterActor    *self,
7619                                   ClutterActorBox *allocation)
7620 {
7621   ClutterActorPrivate *priv = self->priv;
7622   const GList *constraints, *l;
7623
7624   if (priv->constraints == NULL)
7625     return;
7626
7627   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7628   for (l = constraints; l != NULL; l = l->next)
7629     {
7630       ClutterConstraint *constraint = l->data;
7631       ClutterActorMeta *meta = l->data;
7632
7633       if (clutter_actor_meta_get_enabled (meta))
7634         {
7635           _clutter_constraint_update_allocation (constraint,
7636                                                  self,
7637                                                  allocation);
7638         }
7639     }
7640 }
7641
7642 /*< private >
7643  * clutter_actor_adjust_allocation:
7644  * @self: a #ClutterActor
7645  * @allocation: (inout): the allocation to adjust
7646  *
7647  * Adjusts the passed allocation box taking into account the actor's
7648  * layout information, like alignment, expansion, and margin.
7649  */
7650 static void
7651 clutter_actor_adjust_allocation (ClutterActor    *self,
7652                                  ClutterActorBox *allocation)
7653 {
7654   ClutterActorBox adj_allocation;
7655   float alloc_width, alloc_height;
7656   float min_width, min_height;
7657   float nat_width, nat_height;
7658   ClutterRequestMode req_mode;
7659
7660   adj_allocation = *allocation;
7661
7662   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7663
7664   /* we want to hit the cache, so we use the public API */
7665   req_mode = clutter_actor_get_request_mode (self);
7666
7667   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7668     {
7669       clutter_actor_get_preferred_width (self, -1,
7670                                          &min_width,
7671                                          &nat_width);
7672       clutter_actor_get_preferred_height (self, alloc_width,
7673                                           &min_height,
7674                                           &nat_height);
7675     }
7676   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7677     {
7678       clutter_actor_get_preferred_height (self, -1,
7679                                           &min_height,
7680                                           &nat_height);
7681       clutter_actor_get_preferred_height (self, alloc_height,
7682                                           &min_width,
7683                                           &nat_width);
7684     }
7685
7686 #ifdef CLUTTER_ENABLE_DEBUG
7687   /* warn about underallocations */
7688   if (_clutter_diagnostic_enabled () &&
7689       (floorf (min_width - alloc_width) > 0 ||
7690        floorf (min_height - alloc_height) > 0))
7691     {
7692       ClutterActor *parent = clutter_actor_get_parent (self);
7693
7694       /* the only actors that are allowed to be underallocated are the Stage,
7695        * as it doesn't have an implicit size, and Actors that specifically
7696        * told us that they want to opt-out from layout control mechanisms
7697        * through the NO_LAYOUT escape hatch.
7698        */
7699       if (parent != NULL &&
7700           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7701         {
7702           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7703                      "of %.2f x %.2f from its parent actor '%s', but its "
7704                      "requested minimum size is of %.2f x %.2f",
7705                      _clutter_actor_get_debug_name (self),
7706                      alloc_width, alloc_height,
7707                      _clutter_actor_get_debug_name (parent),
7708                      min_width, min_height);
7709         }
7710     }
7711 #endif
7712
7713   clutter_actor_adjust_width (self,
7714                               &min_width,
7715                               &nat_width,
7716                               &adj_allocation.x1,
7717                               &adj_allocation.x2);
7718
7719   clutter_actor_adjust_height (self,
7720                                &min_height,
7721                                &nat_height,
7722                                &adj_allocation.y1,
7723                                &adj_allocation.y2);
7724
7725   /* we maintain the invariant that an allocation cannot be adjusted
7726    * to be outside the parent-given box
7727    */
7728   if (adj_allocation.x1 < allocation->x1 ||
7729       adj_allocation.y1 < allocation->y1 ||
7730       adj_allocation.x2 > allocation->x2 ||
7731       adj_allocation.y2 > allocation->y2)
7732     {
7733       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7734                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7735                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7736                  _clutter_actor_get_debug_name (self),
7737                  adj_allocation.x1, adj_allocation.y1,
7738                  adj_allocation.x2 - adj_allocation.x1,
7739                  adj_allocation.y2 - adj_allocation.y1,
7740                  allocation->x1, allocation->y1,
7741                  allocation->x2 - allocation->x1,
7742                  allocation->y2 - allocation->y1);
7743       return;
7744     }
7745
7746   *allocation = adj_allocation;
7747 }
7748
7749 /**
7750  * clutter_actor_allocate:
7751  * @self: A #ClutterActor
7752  * @box: new allocation of the actor, in parent-relative coordinates
7753  * @flags: flags that control the allocation
7754  *
7755  * Called by the parent of an actor to assign the actor its size.
7756  * Should never be called by applications (except when implementing
7757  * a container or layout manager).
7758  *
7759  * Actors can know from their allocation box whether they have moved
7760  * with respect to their parent actor. The @flags parameter describes
7761  * additional information about the allocation, for instance whether
7762  * the parent has moved with respect to the stage, for example because
7763  * a grandparent's origin has moved.
7764  *
7765  * Since: 0.8
7766  */
7767 void
7768 clutter_actor_allocate (ClutterActor           *self,
7769                         const ClutterActorBox  *box,
7770                         ClutterAllocationFlags  flags)
7771 {
7772   ClutterActorPrivate *priv;
7773   ClutterActorClass *klass;
7774   ClutterActorBox old_allocation, real_allocation;
7775   gboolean origin_changed, child_moved, size_changed;
7776   gboolean stage_allocation_changed;
7777
7778   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7779   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
7780     {
7781       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
7782                  "which isn't a descendent of the stage!\n",
7783                  self, _clutter_actor_get_debug_name (self));
7784       return;
7785     }
7786
7787   priv = self->priv;
7788
7789   old_allocation = priv->allocation;
7790   real_allocation = *box;
7791
7792   /* constraints are allowed to modify the allocation only here; we do
7793    * this prior to all the other checks so that we can bail out if the
7794    * allocation did not change
7795    */
7796   clutter_actor_update_constraints (self, &real_allocation);
7797
7798   /* adjust the allocation depending on the align/margin properties */
7799   clutter_actor_adjust_allocation (self, &real_allocation);
7800
7801   if (real_allocation.x2 < real_allocation.x1 ||
7802       real_allocation.y2 < real_allocation.y1)
7803     {
7804       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
7805                  _clutter_actor_get_debug_name (self),
7806                  real_allocation.x2 - real_allocation.x1,
7807                  real_allocation.y2 - real_allocation.y1);
7808     }
7809
7810   /* we allow 0-sized actors, but not negative-sized ones */
7811   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
7812   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
7813
7814   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
7815
7816   child_moved = (real_allocation.x1 != old_allocation.x1 ||
7817                  real_allocation.y1 != old_allocation.y1);
7818
7819   size_changed = (real_allocation.x2 != old_allocation.x2 ||
7820                   real_allocation.y2 != old_allocation.y2);
7821
7822   if (origin_changed || child_moved || size_changed)
7823     stage_allocation_changed = TRUE;
7824   else
7825     stage_allocation_changed = FALSE;
7826
7827   /* If we get an allocation "out of the blue"
7828    * (we did not queue relayout), then we want to
7829    * ignore it. But if we have needs_allocation set,
7830    * we want to guarantee that allocate() virtual
7831    * method is always called, i.e. that queue_relayout()
7832    * always results in an allocate() invocation on
7833    * an actor.
7834    *
7835    * The optimization here is to avoid re-allocating
7836    * actors that did not queue relayout and were
7837    * not moved.
7838    */
7839   if (!priv->needs_allocation && !stage_allocation_changed)
7840     {
7841       CLUTTER_NOTE (LAYOUT, "No allocation needed");
7842       return;
7843     }
7844
7845   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
7846    * clutter_actor_allocate(), it indicates whether the parent has its
7847    * absolute origin moved; when passed in to ClutterActor::allocate()
7848    * virtual method though, it indicates whether the child has its
7849    * absolute origin moved.  So we set it when child_moved is TRUE
7850    */
7851   if (child_moved)
7852     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
7853
7854   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7855
7856   klass = CLUTTER_ACTOR_GET_CLASS (self);
7857   klass->allocate (self, &real_allocation, flags);
7858
7859   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7860
7861   if (stage_allocation_changed)
7862     clutter_actor_queue_redraw (self);
7863 }
7864
7865 /**
7866  * clutter_actor_set_allocation:
7867  * @self: a #ClutterActor
7868  * @box: a #ClutterActorBox
7869  * @flags: allocation flags
7870  *
7871  * Stores the allocation of @self as defined by @box.
7872  *
7873  * This function can only be called from within the implementation of
7874  * the #ClutterActorClass.allocate() virtual function.
7875  *
7876  * The allocation should have been adjusted to take into account constraints,
7877  * alignment, and margin properties. If you are implementing a #ClutterActor
7878  * subclass that provides its own layout management policy for its children
7879  * instead of using a #ClutterLayoutManager delegate, you should not call
7880  * this function on the children of @self; instead, you should call
7881  * clutter_actor_allocate(), which will adjust the allocation box for
7882  * you.
7883  *
7884  * This function should only be used by subclasses of #ClutterActor
7885  * that wish to store their allocation but cannot chain up to the
7886  * parent's implementation; the default implementation of the
7887  * #ClutterActorClass.allocate() virtual function will call this
7888  * function.
7889  *
7890  * It is important to note that, while chaining up was the recommended
7891  * behaviour for #ClutterActor subclasses prior to the introduction of
7892  * this function, it is recommended to call clutter_actor_set_allocation()
7893  * instead.
7894  *
7895  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
7896  * to handle the allocation of its children, this function will call
7897  * the clutter_layout_manager_allocate() function only if the
7898  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
7899  * expected that the subclass will call clutter_layout_manager_allocate()
7900  * by itself. For instance, the following code:
7901  *
7902  * |[
7903  * static void
7904  * my_actor_allocate (ClutterActor *actor,
7905  *                    const ClutterActorBox *allocation,
7906  *                    ClutterAllocationFlags flags)
7907  * {
7908  *   ClutterActorBox new_alloc;
7909  *   ClutterAllocationFlags new_flags;
7910  *
7911  *   adjust_allocation (allocation, &amp;new_alloc);
7912  *
7913  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
7914  *
7915  *   /&ast; this will use the layout manager set on the actor &ast;/
7916  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
7917  * }
7918  * ]|
7919  *
7920  * is equivalent to this:
7921  *
7922  * |[
7923  * static void
7924  * my_actor_allocate (ClutterActor *actor,
7925  *                    const ClutterActorBox *allocation,
7926  *                    ClutterAllocationFlags flags)
7927  * {
7928  *   ClutterLayoutManager *layout;
7929  *   ClutterActorBox new_alloc;
7930  *
7931  *   adjust_allocation (allocation, &amp;new_alloc);
7932  *
7933  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
7934  *
7935  *   layout = clutter_actor_get_layout_manager (actor);
7936  *   clutter_layout_manager_allocate (layout,
7937  *                                    CLUTTER_CONTAINER (actor),
7938  *                                    &amp;new_alloc,
7939  *                                    flags);
7940  * }
7941  * ]|
7942  *
7943  * Since: 1.10
7944  */
7945 void
7946 clutter_actor_set_allocation (ClutterActor           *self,
7947                               const ClutterActorBox  *box,
7948                               ClutterAllocationFlags  flags)
7949 {
7950   ClutterActorPrivate *priv;
7951   gboolean changed;
7952
7953   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7954   g_return_if_fail (box != NULL);
7955
7956   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
7957     {
7958       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
7959                   "can only be called from within the implementation of "
7960                   "the ClutterActor::allocate() virtual function.");
7961       return;
7962     }
7963
7964   priv = self->priv;
7965
7966   g_object_freeze_notify (G_OBJECT (self));
7967
7968   changed = clutter_actor_set_allocation_internal (self, box, flags);
7969
7970   /* we allocate our children before we notify changes in our geometry,
7971    * so that people connecting to properties will be able to get valid
7972    * data out of the sub-tree of the scene graph that has this actor at
7973    * the root.
7974    */
7975   clutter_actor_maybe_layout_children (self, box, flags);
7976
7977   if (changed)
7978     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
7979                    &priv->allocation,
7980                    priv->allocation_flags);
7981
7982   g_object_thaw_notify (G_OBJECT (self));
7983 }
7984
7985 /**
7986  * clutter_actor_set_geometry:
7987  * @self: A #ClutterActor
7988  * @geometry: A #ClutterGeometry
7989  *
7990  * Sets the actor's fixed position and forces its minimum and natural
7991  * size, in pixels. This means the untransformed actor will have the
7992  * given geometry. This is the same as calling clutter_actor_set_position()
7993  * and clutter_actor_set_size().
7994  *
7995  * Deprecated: 1.10: Use clutter_actor_set_position() and
7996  *   clutter_actor_set_size() instead.
7997  */
7998 void
7999 clutter_actor_set_geometry (ClutterActor          *self,
8000                             const ClutterGeometry *geometry)
8001 {
8002   g_object_freeze_notify (G_OBJECT (self));
8003
8004   clutter_actor_set_position (self, geometry->x, geometry->y);
8005   clutter_actor_set_size (self, geometry->width, geometry->height);
8006
8007   g_object_thaw_notify (G_OBJECT (self));
8008 }
8009
8010 /**
8011  * clutter_actor_get_geometry:
8012  * @self: A #ClutterActor
8013  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8014  *
8015  * Gets the size and position of an actor relative to its parent
8016  * actor. This is the same as calling clutter_actor_get_position() and
8017  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8018  * requested size and position if the actor's allocation is invalid.
8019  *
8020  * Deprecated: 1.10: Use clutter_actor_get_position() and
8021  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8022  *   instead.
8023  */
8024 void
8025 clutter_actor_get_geometry (ClutterActor    *self,
8026                             ClutterGeometry *geometry)
8027 {
8028   gfloat x, y, width, height;
8029
8030   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8031   g_return_if_fail (geometry != NULL);
8032
8033   clutter_actor_get_position (self, &x, &y);
8034   clutter_actor_get_size (self, &width, &height);
8035
8036   geometry->x = (int) x;
8037   geometry->y = (int) y;
8038   geometry->width = (int) width;
8039   geometry->height = (int) height;
8040 }
8041
8042 /**
8043  * clutter_actor_set_position:
8044  * @self: A #ClutterActor
8045  * @x: New left position of actor in pixels.
8046  * @y: New top position of actor in pixels.
8047  *
8048  * Sets the actor's fixed position in pixels relative to any parent
8049  * actor.
8050  *
8051  * If a layout manager is in use, this position will override the
8052  * layout manager and force a fixed position.
8053  */
8054 void
8055 clutter_actor_set_position (ClutterActor *self,
8056                             gfloat        x,
8057                             gfloat        y)
8058 {
8059   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8060
8061   g_object_freeze_notify (G_OBJECT (self));
8062
8063   clutter_actor_set_x (self, x);
8064   clutter_actor_set_y (self, y);
8065
8066   g_object_thaw_notify (G_OBJECT (self));
8067 }
8068
8069 /**
8070  * clutter_actor_get_fixed_position_set:
8071  * @self: A #ClutterActor
8072  *
8073  * Checks whether an actor has a fixed position set (and will thus be
8074  * unaffected by any layout manager).
8075  *
8076  * Return value: %TRUE if the fixed position is set on the actor
8077  *
8078  * Since: 0.8
8079  */
8080 gboolean
8081 clutter_actor_get_fixed_position_set (ClutterActor *self)
8082 {
8083   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8084
8085   return self->priv->position_set;
8086 }
8087
8088 /**
8089  * clutter_actor_set_fixed_position_set:
8090  * @self: A #ClutterActor
8091  * @is_set: whether to use fixed position
8092  *
8093  * Sets whether an actor has a fixed position set (and will thus be
8094  * unaffected by any layout manager).
8095  *
8096  * Since: 0.8
8097  */
8098 void
8099 clutter_actor_set_fixed_position_set (ClutterActor *self,
8100                                       gboolean      is_set)
8101 {
8102   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8103
8104   if (self->priv->position_set == (is_set != FALSE))
8105     return;
8106
8107   self->priv->position_set = is_set != FALSE;
8108   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8109
8110   clutter_actor_queue_relayout (self);
8111 }
8112
8113 /**
8114  * clutter_actor_move_by:
8115  * @self: A #ClutterActor
8116  * @dx: Distance to move Actor on X axis.
8117  * @dy: Distance to move Actor on Y axis.
8118  *
8119  * Moves an actor by the specified distance relative to its current
8120  * position in pixels.
8121  *
8122  * This function modifies the fixed position of an actor and thus removes
8123  * it from any layout management. Another way to move an actor is with an
8124  * anchor point, see clutter_actor_set_anchor_point().
8125  *
8126  * Since: 0.2
8127  */
8128 void
8129 clutter_actor_move_by (ClutterActor *self,
8130                        gfloat        dx,
8131                        gfloat        dy)
8132 {
8133   const ClutterLayoutInfo *info;
8134   gfloat x, y;
8135
8136   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8137
8138   info = _clutter_actor_get_layout_info_or_defaults (self);
8139   x = info->fixed_x;
8140   y = info->fixed_y;
8141
8142   clutter_actor_set_position (self, x + dx, y + dy);
8143 }
8144
8145 static void
8146 clutter_actor_set_min_width (ClutterActor *self,
8147                              gfloat        min_width)
8148 {
8149   ClutterActorPrivate *priv = self->priv;
8150   ClutterActorBox old = { 0, };
8151   ClutterLayoutInfo *info;
8152
8153   /* if we are setting the size on a top-level actor and the
8154    * backend only supports static top-levels (e.g. framebuffers)
8155    * then we ignore the passed value and we override it with
8156    * the stage implementation's preferred size.
8157    */
8158   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8159       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8160     return;
8161
8162   info = _clutter_actor_get_layout_info (self);
8163
8164   if (priv->min_width_set && min_width == info->min_width)
8165     return;
8166
8167   g_object_freeze_notify (G_OBJECT (self));
8168
8169   clutter_actor_store_old_geometry (self, &old);
8170
8171   info->min_width = min_width;
8172   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8173   clutter_actor_set_min_width_set (self, TRUE);
8174
8175   clutter_actor_notify_if_geometry_changed (self, &old);
8176
8177   g_object_thaw_notify (G_OBJECT (self));
8178
8179   clutter_actor_queue_relayout (self);
8180 }
8181
8182 static void
8183 clutter_actor_set_min_height (ClutterActor *self,
8184                               gfloat        min_height)
8185
8186 {
8187   ClutterActorPrivate *priv = self->priv;
8188   ClutterActorBox old = { 0, };
8189   ClutterLayoutInfo *info;
8190
8191   /* if we are setting the size on a top-level actor and the
8192    * backend only supports static top-levels (e.g. framebuffers)
8193    * then we ignore the passed value and we override it with
8194    * the stage implementation's preferred size.
8195    */
8196   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8197       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8198     return;
8199
8200   info = _clutter_actor_get_layout_info (self);
8201
8202   if (priv->min_height_set && min_height == info->min_height)
8203     return;
8204
8205   g_object_freeze_notify (G_OBJECT (self));
8206
8207   clutter_actor_store_old_geometry (self, &old);
8208
8209   info->min_height = min_height;
8210   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8211   clutter_actor_set_min_height_set (self, TRUE);
8212
8213   clutter_actor_notify_if_geometry_changed (self, &old);
8214
8215   g_object_thaw_notify (G_OBJECT (self));
8216
8217   clutter_actor_queue_relayout (self);
8218 }
8219
8220 static void
8221 clutter_actor_set_natural_width (ClutterActor *self,
8222                                  gfloat        natural_width)
8223 {
8224   ClutterActorPrivate *priv = self->priv;
8225   ClutterActorBox old = { 0, };
8226   ClutterLayoutInfo *info;
8227
8228   /* if we are setting the size on a top-level actor and the
8229    * backend only supports static top-levels (e.g. framebuffers)
8230    * then we ignore the passed value and we override it with
8231    * the stage implementation's preferred size.
8232    */
8233   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8234       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8235     return;
8236
8237   info = _clutter_actor_get_layout_info (self);
8238
8239   if (priv->natural_width_set && natural_width == info->natural_width)
8240     return;
8241
8242   g_object_freeze_notify (G_OBJECT (self));
8243
8244   clutter_actor_store_old_geometry (self, &old);
8245
8246   info->natural_width = natural_width;
8247   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8248   clutter_actor_set_natural_width_set (self, TRUE);
8249
8250   clutter_actor_notify_if_geometry_changed (self, &old);
8251
8252   g_object_thaw_notify (G_OBJECT (self));
8253
8254   clutter_actor_queue_relayout (self);
8255 }
8256
8257 static void
8258 clutter_actor_set_natural_height (ClutterActor *self,
8259                                   gfloat        natural_height)
8260 {
8261   ClutterActorPrivate *priv = self->priv;
8262   ClutterActorBox old = { 0, };
8263   ClutterLayoutInfo *info;
8264
8265   /* if we are setting the size on a top-level actor and the
8266    * backend only supports static top-levels (e.g. framebuffers)
8267    * then we ignore the passed value and we override it with
8268    * the stage implementation's preferred size.
8269    */
8270   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8271       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8272     return;
8273
8274   info = _clutter_actor_get_layout_info (self);
8275
8276   if (priv->natural_height_set && natural_height == info->natural_height)
8277     return;
8278
8279   g_object_freeze_notify (G_OBJECT (self));
8280
8281   clutter_actor_store_old_geometry (self, &old);
8282
8283   info->natural_height = natural_height;
8284   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8285   clutter_actor_set_natural_height_set (self, TRUE);
8286
8287   clutter_actor_notify_if_geometry_changed (self, &old);
8288
8289   g_object_thaw_notify (G_OBJECT (self));
8290
8291   clutter_actor_queue_relayout (self);
8292 }
8293
8294 static void
8295 clutter_actor_set_min_width_set (ClutterActor *self,
8296                                  gboolean      use_min_width)
8297 {
8298   ClutterActorPrivate *priv = self->priv;
8299   ClutterActorBox old = { 0, };
8300
8301   if (priv->min_width_set == (use_min_width != FALSE))
8302     return;
8303
8304   clutter_actor_store_old_geometry (self, &old);
8305
8306   priv->min_width_set = use_min_width != FALSE;
8307   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8308
8309   clutter_actor_notify_if_geometry_changed (self, &old);
8310
8311   clutter_actor_queue_relayout (self);
8312 }
8313
8314 static void
8315 clutter_actor_set_min_height_set (ClutterActor *self,
8316                                   gboolean      use_min_height)
8317 {
8318   ClutterActorPrivate *priv = self->priv;
8319   ClutterActorBox old = { 0, };
8320
8321   if (priv->min_height_set == (use_min_height != FALSE))
8322     return;
8323
8324   clutter_actor_store_old_geometry (self, &old);
8325
8326   priv->min_height_set = use_min_height != FALSE;
8327   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8328
8329   clutter_actor_notify_if_geometry_changed (self, &old);
8330
8331   clutter_actor_queue_relayout (self);
8332 }
8333
8334 static void
8335 clutter_actor_set_natural_width_set (ClutterActor *self,
8336                                      gboolean      use_natural_width)
8337 {
8338   ClutterActorPrivate *priv = self->priv;
8339   ClutterActorBox old = { 0, };
8340
8341   if (priv->natural_width_set == (use_natural_width != FALSE))
8342     return;
8343
8344   clutter_actor_store_old_geometry (self, &old);
8345
8346   priv->natural_width_set = use_natural_width != FALSE;
8347   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8348
8349   clutter_actor_notify_if_geometry_changed (self, &old);
8350
8351   clutter_actor_queue_relayout (self);
8352 }
8353
8354 static void
8355 clutter_actor_set_natural_height_set (ClutterActor *self,
8356                                       gboolean      use_natural_height)
8357 {
8358   ClutterActorPrivate *priv = self->priv;
8359   ClutterActorBox old = { 0, };
8360
8361   if (priv->natural_height_set == (use_natural_height != FALSE))
8362     return;
8363
8364   clutter_actor_store_old_geometry (self, &old);
8365
8366   priv->natural_height_set = use_natural_height != FALSE;
8367   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8368
8369   clutter_actor_notify_if_geometry_changed (self, &old);
8370
8371   clutter_actor_queue_relayout (self);
8372 }
8373
8374 /**
8375  * clutter_actor_set_request_mode:
8376  * @self: a #ClutterActor
8377  * @mode: the request mode
8378  *
8379  * Sets the geometry request mode of @self.
8380  *
8381  * The @mode determines the order for invoking
8382  * clutter_actor_get_preferred_width() and
8383  * clutter_actor_get_preferred_height()
8384  *
8385  * Since: 1.2
8386  */
8387 void
8388 clutter_actor_set_request_mode (ClutterActor       *self,
8389                                 ClutterRequestMode  mode)
8390 {
8391   ClutterActorPrivate *priv;
8392
8393   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8394
8395   priv = self->priv;
8396
8397   if (priv->request_mode == mode)
8398     return;
8399
8400   priv->request_mode = mode;
8401
8402   priv->needs_width_request = TRUE;
8403   priv->needs_height_request = TRUE;
8404
8405   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8406
8407   clutter_actor_queue_relayout (self);
8408 }
8409
8410 /**
8411  * clutter_actor_get_request_mode:
8412  * @self: a #ClutterActor
8413  *
8414  * Retrieves the geometry request mode of @self
8415  *
8416  * Return value: the request mode for the actor
8417  *
8418  * Since: 1.2
8419  */
8420 ClutterRequestMode
8421 clutter_actor_get_request_mode (ClutterActor *self)
8422 {
8423   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8424                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8425
8426   return self->priv->request_mode;
8427 }
8428
8429 /* variant of set_width() without checks and without notification
8430  * freeze+thaw, for internal usage only
8431  */
8432 static inline void
8433 clutter_actor_set_width_internal (ClutterActor *self,
8434                                   gfloat        width)
8435 {
8436   if (width >= 0)
8437     {
8438       /* the Stage will use the :min-width to control the minimum
8439        * width to be resized to, so we should not be setting it
8440        * along with the :natural-width
8441        */
8442       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8443         clutter_actor_set_min_width (self, width);
8444
8445       clutter_actor_set_natural_width (self, width);
8446     }
8447   else
8448     {
8449       /* we only unset the :natural-width for the Stage */
8450       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8451         clutter_actor_set_min_width_set (self, FALSE);
8452
8453       clutter_actor_set_natural_width_set (self, FALSE);
8454     }
8455 }
8456
8457 /* variant of set_height() without checks and without notification
8458  * freeze+thaw, for internal usage only
8459  */
8460 static inline void
8461 clutter_actor_set_height_internal (ClutterActor *self,
8462                                    gfloat        height)
8463 {
8464   if (height >= 0)
8465     {
8466       /* see the comment above in set_width_internal() */
8467       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8468         clutter_actor_set_min_height (self, height);
8469
8470       clutter_actor_set_natural_height (self, height);
8471     }
8472   else
8473     {
8474       /* see the comment above in set_width_internal() */
8475       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8476         clutter_actor_set_min_height_set (self, FALSE);
8477
8478       clutter_actor_set_natural_height_set (self, FALSE);
8479     }
8480 }
8481
8482 /**
8483  * clutter_actor_set_size:
8484  * @self: A #ClutterActor
8485  * @width: New width of actor in pixels, or -1
8486  * @height: New height of actor in pixels, or -1
8487  *
8488  * Sets the actor's size request in pixels. This overrides any
8489  * "normal" size request the actor would have. For example
8490  * a text actor might normally request the size of the text;
8491  * this function would force a specific size instead.
8492  *
8493  * If @width and/or @height are -1 the actor will use its
8494  * "normal" size request instead of overriding it, i.e.
8495  * you can "unset" the size with -1.
8496  *
8497  * This function sets or unsets both the minimum and natural size.
8498  */
8499 void
8500 clutter_actor_set_size (ClutterActor *self,
8501                         gfloat        width,
8502                         gfloat        height)
8503 {
8504   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8505
8506   g_object_freeze_notify (G_OBJECT (self));
8507
8508   clutter_actor_set_width_internal (self, width);
8509   clutter_actor_set_height_internal (self, height);
8510
8511   g_object_thaw_notify (G_OBJECT (self));
8512 }
8513
8514 /**
8515  * clutter_actor_get_size:
8516  * @self: A #ClutterActor
8517  * @width: (out) (allow-none): return location for the width, or %NULL.
8518  * @height: (out) (allow-none): return location for the height, or %NULL.
8519  *
8520  * This function tries to "do what you mean" and return
8521  * the size an actor will have. If the actor has a valid
8522  * allocation, the allocation will be returned; otherwise,
8523  * the actors natural size request will be returned.
8524  *
8525  * If you care whether you get the request vs. the allocation, you
8526  * should probably call a different function like
8527  * clutter_actor_get_allocation_box() or
8528  * clutter_actor_get_preferred_width().
8529  *
8530  * Since: 0.2
8531  */
8532 void
8533 clutter_actor_get_size (ClutterActor *self,
8534                         gfloat       *width,
8535                         gfloat       *height)
8536 {
8537   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8538
8539   if (width)
8540     *width = clutter_actor_get_width (self);
8541
8542   if (height)
8543     *height = clutter_actor_get_height (self);
8544 }
8545
8546 /**
8547  * clutter_actor_get_position:
8548  * @self: a #ClutterActor
8549  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8550  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8551  *
8552  * This function tries to "do what you mean" and tell you where the
8553  * actor is, prior to any transformations. Retrieves the fixed
8554  * position of an actor in pixels, if one has been set; otherwise, if
8555  * the allocation is valid, returns the actor's allocated position;
8556  * otherwise, returns 0,0.
8557  *
8558  * The returned position is in pixels.
8559  *
8560  * Since: 0.6
8561  */
8562 void
8563 clutter_actor_get_position (ClutterActor *self,
8564                             gfloat       *x,
8565                             gfloat       *y)
8566 {
8567   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8568
8569   if (x)
8570     *x = clutter_actor_get_x (self);
8571
8572   if (y)
8573     *y = clutter_actor_get_y (self);
8574 }
8575
8576 /**
8577  * clutter_actor_get_transformed_position:
8578  * @self: A #ClutterActor
8579  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8580  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8581  *
8582  * Gets the absolute position of an actor, in pixels relative to the stage.
8583  *
8584  * Since: 0.8
8585  */
8586 void
8587 clutter_actor_get_transformed_position (ClutterActor *self,
8588                                         gfloat       *x,
8589                                         gfloat       *y)
8590 {
8591   ClutterVertex v1;
8592   ClutterVertex v2;
8593
8594   v1.x = v1.y = v1.z = 0;
8595   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8596
8597   if (x)
8598     *x = v2.x;
8599
8600   if (y)
8601     *y = v2.y;
8602 }
8603
8604 /**
8605  * clutter_actor_get_transformed_size:
8606  * @self: A #ClutterActor
8607  * @width: (out) (allow-none): return location for the width, or %NULL
8608  * @height: (out) (allow-none): return location for the height, or %NULL
8609  *
8610  * Gets the absolute size of an actor in pixels, taking into account the
8611  * scaling factors.
8612  *
8613  * If the actor has a valid allocation, the allocated size will be used.
8614  * If the actor has not a valid allocation then the preferred size will
8615  * be transformed and returned.
8616  *
8617  * If you want the transformed allocation, see
8618  * clutter_actor_get_abs_allocation_vertices() instead.
8619  *
8620  * <note>When the actor (or one of its ancestors) is rotated around the
8621  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8622  * as a generic quadrangle; in that case this function returns the size
8623  * of the smallest rectangle that encapsulates the entire quad. Please
8624  * note that in this case no assumptions can be made about the relative
8625  * position of this envelope to the absolute position of the actor, as
8626  * returned by clutter_actor_get_transformed_position(); if you need this
8627  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8628  * to get the coords of the actual quadrangle.</note>
8629  *
8630  * Since: 0.8
8631  */
8632 void
8633 clutter_actor_get_transformed_size (ClutterActor *self,
8634                                     gfloat       *width,
8635                                     gfloat       *height)
8636 {
8637   ClutterActorPrivate *priv;
8638   ClutterVertex v[4];
8639   gfloat x_min, x_max, y_min, y_max;
8640   gint i;
8641
8642   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8643
8644   priv = self->priv;
8645
8646   /* if the actor hasn't been allocated yet, get the preferred
8647    * size and transform that
8648    */
8649   if (priv->needs_allocation)
8650     {
8651       gfloat natural_width, natural_height;
8652       ClutterActorBox box;
8653
8654       /* Make a fake allocation to transform.
8655        *
8656        * NB: _clutter_actor_transform_and_project_box expects a box in
8657        * the actor's coordinate space... */
8658
8659       box.x1 = 0;
8660       box.y1 = 0;
8661
8662       natural_width = natural_height = 0;
8663       clutter_actor_get_preferred_size (self, NULL, NULL,
8664                                         &natural_width,
8665                                         &natural_height);
8666
8667       box.x2 = natural_width;
8668       box.y2 = natural_height;
8669
8670       _clutter_actor_transform_and_project_box (self, &box, v);
8671     }
8672   else
8673     clutter_actor_get_abs_allocation_vertices (self, v);
8674
8675   x_min = x_max = v[0].x;
8676   y_min = y_max = v[0].y;
8677
8678   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8679     {
8680       if (v[i].x < x_min)
8681         x_min = v[i].x;
8682
8683       if (v[i].x > x_max)
8684         x_max = v[i].x;
8685
8686       if (v[i].y < y_min)
8687         y_min = v[i].y;
8688
8689       if (v[i].y > y_max)
8690         y_max = v[i].y;
8691     }
8692
8693   if (width)
8694     *width  = x_max - x_min;
8695
8696   if (height)
8697     *height = y_max - y_min;
8698 }
8699
8700 /**
8701  * clutter_actor_get_width:
8702  * @self: A #ClutterActor
8703  *
8704  * Retrieves the width of a #ClutterActor.
8705  *
8706  * If the actor has a valid allocation, this function will return the
8707  * width of the allocated area given to the actor.
8708  *
8709  * If the actor does not have a valid allocation, this function will
8710  * return the actor's natural width, that is the preferred width of
8711  * the actor.
8712  *
8713  * If you care whether you get the preferred width or the width that
8714  * has been assigned to the actor, you should probably call a different
8715  * function like clutter_actor_get_allocation_box() to retrieve the
8716  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8717  * preferred width.
8718  *
8719  * If an actor has a fixed width, for instance a width that has been
8720  * assigned using clutter_actor_set_width(), the width returned will
8721  * be the same value.
8722  *
8723  * Return value: the width of the actor, in pixels
8724  */
8725 gfloat
8726 clutter_actor_get_width (ClutterActor *self)
8727 {
8728   ClutterActorPrivate *priv;
8729
8730   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8731
8732   priv = self->priv;
8733
8734   if (priv->needs_allocation)
8735     {
8736       gfloat natural_width = 0;
8737
8738       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8739         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8740       else
8741         {
8742           gfloat natural_height = 0;
8743
8744           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8745           clutter_actor_get_preferred_width (self, natural_height,
8746                                              NULL,
8747                                              &natural_width);
8748         }
8749
8750       return natural_width;
8751     }
8752   else
8753     return priv->allocation.x2 - priv->allocation.x1;
8754 }
8755
8756 /**
8757  * clutter_actor_get_height:
8758  * @self: A #ClutterActor
8759  *
8760  * Retrieves the height of a #ClutterActor.
8761  *
8762  * If the actor has a valid allocation, this function will return the
8763  * height of the allocated area given to the actor.
8764  *
8765  * If the actor does not have a valid allocation, this function will
8766  * return the actor's natural height, that is the preferred height of
8767  * the actor.
8768  *
8769  * If you care whether you get the preferred height or the height that
8770  * has been assigned to the actor, you should probably call a different
8771  * function like clutter_actor_get_allocation_box() to retrieve the
8772  * allocated size or clutter_actor_get_preferred_height() to retrieve the
8773  * preferred height.
8774  *
8775  * If an actor has a fixed height, for instance a height that has been
8776  * assigned using clutter_actor_set_height(), the height returned will
8777  * be the same value.
8778  *
8779  * Return value: the height of the actor, in pixels
8780  */
8781 gfloat
8782 clutter_actor_get_height (ClutterActor *self)
8783 {
8784   ClutterActorPrivate *priv;
8785
8786   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8787
8788   priv = self->priv;
8789
8790   if (priv->needs_allocation)
8791     {
8792       gfloat natural_height = 0;
8793
8794       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8795         {
8796           gfloat natural_width = 0;
8797
8798           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8799           clutter_actor_get_preferred_height (self, natural_width,
8800                                               NULL, &natural_height);
8801         }
8802       else
8803         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8804
8805       return natural_height;
8806     }
8807   else
8808     return priv->allocation.y2 - priv->allocation.y1;
8809 }
8810
8811 /**
8812  * clutter_actor_set_width:
8813  * @self: A #ClutterActor
8814  * @width: Requested new width for the actor, in pixels, or -1
8815  *
8816  * Forces a width on an actor, causing the actor's preferred width
8817  * and height (if any) to be ignored.
8818  *
8819  * If @width is -1 the actor will use its preferred width request
8820  * instead of overriding it, i.e. you can "unset" the width with -1.
8821  *
8822  * This function sets both the minimum and natural size of the actor.
8823  *
8824  * since: 0.2
8825  */
8826 void
8827 clutter_actor_set_width (ClutterActor *self,
8828                          gfloat        width)
8829 {
8830   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8831
8832   g_object_freeze_notify (G_OBJECT (self));
8833
8834   clutter_actor_set_width_internal (self, width);
8835
8836   g_object_thaw_notify (G_OBJECT (self));
8837 }
8838
8839 /**
8840  * clutter_actor_set_height:
8841  * @self: A #ClutterActor
8842  * @height: Requested new height for the actor, in pixels, or -1
8843  *
8844  * Forces a height on an actor, causing the actor's preferred width
8845  * and height (if any) to be ignored.
8846  *
8847  * If @height is -1 the actor will use its preferred height instead of
8848  * overriding it, i.e. you can "unset" the height with -1.
8849  *
8850  * This function sets both the minimum and natural size of the actor.
8851  *
8852  * since: 0.2
8853  */
8854 void
8855 clutter_actor_set_height (ClutterActor *self,
8856                           gfloat        height)
8857 {
8858   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8859
8860   g_object_freeze_notify (G_OBJECT (self));
8861
8862   clutter_actor_set_height_internal (self, height);
8863
8864   g_object_thaw_notify (G_OBJECT (self));
8865 }
8866
8867 /**
8868  * clutter_actor_set_x:
8869  * @self: a #ClutterActor
8870  * @x: the actor's position on the X axis
8871  *
8872  * Sets the actor's X coordinate, relative to its parent, in pixels.
8873  *
8874  * Overrides any layout manager and forces a fixed position for
8875  * the actor.
8876  *
8877  * Since: 0.6
8878  */
8879 void
8880 clutter_actor_set_x (ClutterActor *self,
8881                      gfloat        x)
8882 {
8883   ClutterActorBox old = { 0, };
8884   ClutterActorPrivate *priv;
8885   ClutterLayoutInfo *info;
8886
8887   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8888
8889   priv = self->priv;
8890
8891   info = _clutter_actor_get_layout_info (self);
8892
8893   if (priv->position_set && info->fixed_x == x)
8894     return;
8895
8896   clutter_actor_store_old_geometry (self, &old);
8897
8898   info->fixed_x = x;
8899   clutter_actor_set_fixed_position_set (self, TRUE);
8900
8901   clutter_actor_notify_if_geometry_changed (self, &old);
8902
8903   clutter_actor_queue_relayout (self);
8904 }
8905
8906 /**
8907  * clutter_actor_set_y:
8908  * @self: a #ClutterActor
8909  * @y: the actor's position on the Y axis
8910  *
8911  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
8912  *
8913  * Overrides any layout manager and forces a fixed position for
8914  * the actor.
8915  *
8916  * Since: 0.6
8917  */
8918 void
8919 clutter_actor_set_y (ClutterActor *self,
8920                      gfloat        y)
8921 {
8922   ClutterActorBox old = { 0, };
8923   ClutterActorPrivate *priv;
8924   ClutterLayoutInfo *info;
8925
8926   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8927
8928   priv = self->priv;
8929
8930   info = _clutter_actor_get_layout_info (self);
8931
8932   if (priv->position_set && info->fixed_y == y)
8933     return;
8934
8935   clutter_actor_store_old_geometry (self, &old);
8936
8937   info->fixed_y = y;
8938   clutter_actor_set_fixed_position_set (self, TRUE);
8939
8940   clutter_actor_notify_if_geometry_changed (self, &old);
8941
8942   clutter_actor_queue_relayout (self);
8943 }
8944
8945 /**
8946  * clutter_actor_get_x:
8947  * @self: A #ClutterActor
8948  *
8949  * Retrieves the X coordinate of a #ClutterActor.
8950  *
8951  * This function tries to "do what you mean", by returning the
8952  * correct value depending on the actor's state.
8953  *
8954  * If the actor has a valid allocation, this function will return
8955  * the X coordinate of the origin of the allocation box.
8956  *
8957  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
8958  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8959  * function will return that coordinate.
8960  *
8961  * If both the allocation and a fixed position are missing, this function
8962  * will return 0.
8963  *
8964  * Return value: the X coordinate, in pixels, ignoring any
8965  *   transformation (i.e. scaling, rotation)
8966  */
8967 gfloat
8968 clutter_actor_get_x (ClutterActor *self)
8969 {
8970   ClutterActorPrivate *priv;
8971
8972   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8973
8974   priv = self->priv;
8975
8976   if (priv->needs_allocation)
8977     {
8978       if (priv->position_set)
8979         {
8980           const ClutterLayoutInfo *info;
8981
8982           info = _clutter_actor_get_layout_info_or_defaults (self);
8983
8984           return info->fixed_x;
8985         }
8986       else
8987         return 0;
8988     }
8989   else
8990     return priv->allocation.x1;
8991 }
8992
8993 /**
8994  * clutter_actor_get_y:
8995  * @self: A #ClutterActor
8996  *
8997  * Retrieves the Y coordinate of a #ClutterActor.
8998  *
8999  * This function tries to "do what you mean", by returning the
9000  * correct value depending on the actor's state.
9001  *
9002  * If the actor has a valid allocation, this function will return
9003  * the Y coordinate of the origin of the allocation box.
9004  *
9005  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9006  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9007  * function will return that coordinate.
9008  *
9009  * If both the allocation and a fixed position are missing, this function
9010  * will return 0.
9011  *
9012  * Return value: the Y coordinate, in pixels, ignoring any
9013  *   transformation (i.e. scaling, rotation)
9014  */
9015 gfloat
9016 clutter_actor_get_y (ClutterActor *self)
9017 {
9018   ClutterActorPrivate *priv;
9019
9020   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9021
9022   priv = self->priv;
9023
9024   if (priv->needs_allocation)
9025     {
9026       if (priv->position_set)
9027         {
9028           const ClutterLayoutInfo *info;
9029
9030           info = _clutter_actor_get_layout_info_or_defaults (self);
9031
9032           return info->fixed_y;
9033         }
9034       else
9035         return 0;
9036     }
9037   else
9038     return priv->allocation.y1;
9039 }
9040
9041 /**
9042  * clutter_actor_set_scale:
9043  * @self: A #ClutterActor
9044  * @scale_x: double factor to scale actor by horizontally.
9045  * @scale_y: double factor to scale actor by vertically.
9046  *
9047  * Scales an actor with the given factors. The scaling is relative to
9048  * the scale center and the anchor point. The scale center is
9049  * unchanged by this function and defaults to 0,0.
9050  *
9051  * Since: 0.2
9052  */
9053 void
9054 clutter_actor_set_scale (ClutterActor *self,
9055                          gdouble       scale_x,
9056                          gdouble       scale_y)
9057 {
9058   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9059
9060   g_object_freeze_notify (G_OBJECT (self));
9061
9062   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9063   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9064
9065   g_object_thaw_notify (G_OBJECT (self));
9066 }
9067
9068 /**
9069  * clutter_actor_set_scale_full:
9070  * @self: A #ClutterActor
9071  * @scale_x: double factor to scale actor by horizontally.
9072  * @scale_y: double factor to scale actor by vertically.
9073  * @center_x: X coordinate of the center of the scale.
9074  * @center_y: Y coordinate of the center of the scale
9075  *
9076  * Scales an actor with the given factors around the given center
9077  * point. The center point is specified in pixels relative to the
9078  * anchor point (usually the top left corner of the actor).
9079  *
9080  * Since: 1.0
9081  */
9082 void
9083 clutter_actor_set_scale_full (ClutterActor *self,
9084                               gdouble       scale_x,
9085                               gdouble       scale_y,
9086                               gfloat        center_x,
9087                               gfloat        center_y)
9088 {
9089   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9090
9091   g_object_freeze_notify (G_OBJECT (self));
9092
9093   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9094   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9095   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9096   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9097
9098   g_object_thaw_notify (G_OBJECT (self));
9099 }
9100
9101 /**
9102  * clutter_actor_set_scale_with_gravity:
9103  * @self: A #ClutterActor
9104  * @scale_x: double factor to scale actor by horizontally.
9105  * @scale_y: double factor to scale actor by vertically.
9106  * @gravity: the location of the scale center expressed as a compass
9107  * direction.
9108  *
9109  * Scales an actor with the given factors around the given
9110  * center point. The center point is specified as one of the compass
9111  * directions in #ClutterGravity. For example, setting it to north
9112  * will cause the top of the actor to remain unchanged and the rest of
9113  * the actor to expand left, right and downwards.
9114  *
9115  * Since: 1.0
9116  */
9117 void
9118 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9119                                       gdouble         scale_x,
9120                                       gdouble         scale_y,
9121                                       ClutterGravity  gravity)
9122 {
9123   ClutterTransformInfo *info;
9124   GObject *obj;
9125
9126   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9127
9128   obj = G_OBJECT (self);
9129
9130   g_object_freeze_notify (obj);
9131
9132   info = _clutter_actor_get_transform_info (self);
9133   info->scale_x = scale_x;
9134   info->scale_y = scale_y;
9135
9136   if (gravity == CLUTTER_GRAVITY_NONE)
9137     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9138   else
9139     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9140
9141   self->priv->transform_valid = FALSE;
9142
9143   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9144   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9145   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9146   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9147   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9148
9149   clutter_actor_queue_redraw (self);
9150
9151   g_object_thaw_notify (obj);
9152 }
9153
9154 /**
9155  * clutter_actor_get_scale:
9156  * @self: A #ClutterActor
9157  * @scale_x: (out) (allow-none): Location to store horizonal
9158  *   scale factor, or %NULL.
9159  * @scale_y: (out) (allow-none): Location to store vertical
9160  *   scale factor, or %NULL.
9161  *
9162  * Retrieves an actors scale factors.
9163  *
9164  * Since: 0.2
9165  */
9166 void
9167 clutter_actor_get_scale (ClutterActor *self,
9168                          gdouble      *scale_x,
9169                          gdouble      *scale_y)
9170 {
9171   const ClutterTransformInfo *info;
9172
9173   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9174
9175   info = _clutter_actor_get_transform_info_or_defaults (self);
9176
9177   if (scale_x)
9178     *scale_x = info->scale_x;
9179
9180   if (scale_y)
9181     *scale_y = info->scale_y;
9182 }
9183
9184 /**
9185  * clutter_actor_get_scale_center:
9186  * @self: A #ClutterActor
9187  * @center_x: (out) (allow-none): Location to store the X position
9188  *   of the scale center, or %NULL.
9189  * @center_y: (out) (allow-none): Location to store the Y position
9190  *   of the scale center, or %NULL.
9191  *
9192  * Retrieves the scale center coordinate in pixels relative to the top
9193  * left corner of the actor. If the scale center was specified using a
9194  * #ClutterGravity this will calculate the pixel offset using the
9195  * current size of the actor.
9196  *
9197  * Since: 1.0
9198  */
9199 void
9200 clutter_actor_get_scale_center (ClutterActor *self,
9201                                 gfloat       *center_x,
9202                                 gfloat       *center_y)
9203 {
9204   const ClutterTransformInfo *info;
9205
9206   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9207
9208   info = _clutter_actor_get_transform_info_or_defaults (self);
9209
9210   clutter_anchor_coord_get_units (self, &info->scale_center,
9211                                   center_x,
9212                                   center_y,
9213                                   NULL);
9214 }
9215
9216 /**
9217  * clutter_actor_get_scale_gravity:
9218  * @self: A #ClutterActor
9219  *
9220  * Retrieves the scale center as a compass direction. If the scale
9221  * center was specified in pixels or units this will return
9222  * %CLUTTER_GRAVITY_NONE.
9223  *
9224  * Return value: the scale gravity
9225  *
9226  * Since: 1.0
9227  */
9228 ClutterGravity
9229 clutter_actor_get_scale_gravity (ClutterActor *self)
9230 {
9231   const ClutterTransformInfo *info;
9232
9233   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9234
9235   info = _clutter_actor_get_transform_info_or_defaults (self);
9236
9237   return clutter_anchor_coord_get_gravity (&info->scale_center);
9238 }
9239
9240 /**
9241  * clutter_actor_set_opacity:
9242  * @self: A #ClutterActor
9243  * @opacity: New opacity value for the actor.
9244  *
9245  * Sets the actor's opacity, with zero being completely transparent and
9246  * 255 (0xff) being fully opaque.
9247  */
9248 void
9249 clutter_actor_set_opacity (ClutterActor *self,
9250                            guint8        opacity)
9251 {
9252   ClutterActorPrivate *priv;
9253
9254   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9255
9256   priv = self->priv;
9257
9258   if (priv->opacity != opacity)
9259     {
9260       priv->opacity = opacity;
9261
9262       /* Queue a redraw from the flatten effect so that it can use
9263          its cached image if available instead of having to redraw the
9264          actual actor. If it doesn't end up using the FBO then the
9265          effect is still able to continue the paint anyway. If there
9266          is no flatten effect yet then this is equivalent to queueing
9267          a full redraw */
9268       _clutter_actor_queue_redraw_full (self,
9269                                         0, /* flags */
9270                                         NULL, /* clip */
9271                                         priv->flatten_effect);
9272
9273       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9274     }
9275 }
9276
9277 /*
9278  * clutter_actor_get_paint_opacity_internal:
9279  * @self: a #ClutterActor
9280  *
9281  * Retrieves the absolute opacity of the actor, as it appears on the stage
9282  *
9283  * This function does not do type checks
9284  *
9285  * Return value: the absolute opacity of the actor
9286  */
9287 static guint8
9288 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9289 {
9290   ClutterActorPrivate *priv = self->priv;
9291   ClutterActor *parent;
9292
9293   /* override the top-level opacity to always be 255; even in
9294    * case of ClutterStage:use-alpha being TRUE we want the rest
9295    * of the scene to be painted
9296    */
9297   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9298     return 255;
9299
9300   if (priv->opacity_override >= 0)
9301     return priv->opacity_override;
9302
9303   parent = priv->parent;
9304
9305   /* Factor in the actual actors opacity with parents */
9306   if (parent != NULL)
9307     {
9308       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9309
9310       if (opacity != 0xff)
9311         return (opacity * priv->opacity) / 0xff;
9312     }
9313
9314   return priv->opacity;
9315
9316 }
9317
9318 /**
9319  * clutter_actor_get_paint_opacity:
9320  * @self: A #ClutterActor
9321  *
9322  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9323  *
9324  * This function traverses the hierarchy chain and composites the opacity of
9325  * the actor with that of its parents.
9326  *
9327  * This function is intended for subclasses to use in the paint virtual
9328  * function, to paint themselves with the correct opacity.
9329  *
9330  * Return value: The actor opacity value.
9331  *
9332  * Since: 0.8
9333  */
9334 guint8
9335 clutter_actor_get_paint_opacity (ClutterActor *self)
9336 {
9337   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9338
9339   return clutter_actor_get_paint_opacity_internal (self);
9340 }
9341
9342 /**
9343  * clutter_actor_get_opacity:
9344  * @self: a #ClutterActor
9345  *
9346  * Retrieves the opacity value of an actor, as set by
9347  * clutter_actor_set_opacity().
9348  *
9349  * For retrieving the absolute opacity of the actor inside a paint
9350  * virtual function, see clutter_actor_get_paint_opacity().
9351  *
9352  * Return value: the opacity of the actor
9353  */
9354 guint8
9355 clutter_actor_get_opacity (ClutterActor *self)
9356 {
9357   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9358
9359   return self->priv->opacity;
9360 }
9361
9362 /**
9363  * clutter_actor_set_offscreen_redirect:
9364  * @self: A #ClutterActor
9365  * @redirect: New offscreen redirect flags for the actor.
9366  *
9367  * Defines the circumstances where the actor should be redirected into
9368  * an offscreen image. The offscreen image is used to flatten the
9369  * actor into a single image while painting for two main reasons.
9370  * Firstly, when the actor is painted a second time without any of its
9371  * contents changing it can simply repaint the cached image without
9372  * descending further down the actor hierarchy. Secondly, it will make
9373  * the opacity look correct even if there are overlapping primitives
9374  * in the actor.
9375  *
9376  * Caching the actor could in some cases be a performance win and in
9377  * some cases be a performance lose so it is important to determine
9378  * which value is right for an actor before modifying this value. For
9379  * example, there is never any reason to flatten an actor that is just
9380  * a single texture (such as a #ClutterTexture) because it is
9381  * effectively already cached in an image so the offscreen would be
9382  * redundant. Also if the actor contains primitives that are far apart
9383  * with a large transparent area in the middle (such as a large
9384  * CluterGroup with a small actor in the top left and a small actor in
9385  * the bottom right) then the cached image will contain the entire
9386  * image of the large area and the paint will waste time blending all
9387  * of the transparent pixels in the middle.
9388  *
9389  * The default method of implementing opacity on a container simply
9390  * forwards on the opacity to all of the children. If the children are
9391  * overlapping then it will appear as if they are two separate glassy
9392  * objects and there will be a break in the color where they
9393  * overlap. By redirecting to an offscreen buffer it will be as if the
9394  * two opaque objects are combined into one and then made transparent
9395  * which is usually what is expected.
9396  *
9397  * The image below demonstrates the difference between redirecting and
9398  * not. The image shows two Clutter groups, each containing a red and
9399  * a green rectangle which overlap. The opacity on the group is set to
9400  * 128 (which is 50%). When the offscreen redirect is not used, the
9401  * red rectangle can be seen through the blue rectangle as if the two
9402  * rectangles were separately transparent. When the redirect is used
9403  * the group as a whole is transparent instead so the red rectangle is
9404  * not visible where they overlap.
9405  *
9406  * <figure id="offscreen-redirect">
9407  *   <title>Sample of using an offscreen redirect for transparency</title>
9408  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9409  * </figure>
9410  *
9411  * The default value for this property is 0, so we effectively will
9412  * never redirect an actor offscreen by default. This means that there
9413  * are times that transparent actors may look glassy as described
9414  * above. The reason this is the default is because there is a
9415  * performance trade off between quality and performance here. In many
9416  * cases the default form of glassy opacity looks good enough, but if
9417  * it's not you will need to set the
9418  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9419  * redirection for opacity.
9420  *
9421  * Custom actors that don't contain any overlapping primitives are
9422  * recommended to override the has_overlaps() virtual to return %FALSE
9423  * for maximum efficiency.
9424  *
9425  * Since: 1.8
9426  */
9427 void
9428 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9429                                       ClutterOffscreenRedirect redirect)
9430 {
9431   ClutterActorPrivate *priv;
9432
9433   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9434
9435   priv = self->priv;
9436
9437   if (priv->offscreen_redirect != redirect)
9438     {
9439       priv->offscreen_redirect = redirect;
9440
9441       /* Queue a redraw from the effect so that it can use its cached
9442          image if available instead of having to redraw the actual
9443          actor. If it doesn't end up using the FBO then the effect is
9444          still able to continue the paint anyway. If there is no
9445          effect then this is equivalent to queuing a full redraw */
9446       _clutter_actor_queue_redraw_full (self,
9447                                         0, /* flags */
9448                                         NULL, /* clip */
9449                                         priv->flatten_effect);
9450
9451       g_object_notify_by_pspec (G_OBJECT (self),
9452                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9453     }
9454 }
9455
9456 /**
9457  * clutter_actor_get_offscreen_redirect:
9458  * @self: a #ClutterActor
9459  *
9460  * Retrieves whether to redirect the actor to an offscreen buffer, as
9461  * set by clutter_actor_set_offscreen_redirect().
9462  *
9463  * Return value: the value of the offscreen-redirect property of the actor
9464  *
9465  * Since: 1.8
9466  */
9467 ClutterOffscreenRedirect
9468 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9469 {
9470   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9471
9472   return self->priv->offscreen_redirect;
9473 }
9474
9475 /**
9476  * clutter_actor_set_name:
9477  * @self: A #ClutterActor
9478  * @name: Textual tag to apply to actor
9479  *
9480  * Sets the given name to @self. The name can be used to identify
9481  * a #ClutterActor.
9482  */
9483 void
9484 clutter_actor_set_name (ClutterActor *self,
9485                         const gchar  *name)
9486 {
9487   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9488
9489   g_free (self->priv->name);
9490   self->priv->name = g_strdup (name);
9491
9492   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9493 }
9494
9495 /**
9496  * clutter_actor_get_name:
9497  * @self: A #ClutterActor
9498  *
9499  * Retrieves the name of @self.
9500  *
9501  * Return value: the name of the actor, or %NULL. The returned string is
9502  *   owned by the actor and should not be modified or freed.
9503  */
9504 const gchar *
9505 clutter_actor_get_name (ClutterActor *self)
9506 {
9507   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9508
9509   return self->priv->name;
9510 }
9511
9512 /**
9513  * clutter_actor_get_gid:
9514  * @self: A #ClutterActor
9515  *
9516  * Retrieves the unique id for @self.
9517  *
9518  * Return value: Globally unique value for this object instance.
9519  *
9520  * Since: 0.6
9521  *
9522  * Deprecated: 1.8: The id is not used any longer.
9523  */
9524 guint32
9525 clutter_actor_get_gid (ClutterActor *self)
9526 {
9527   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9528
9529   return self->priv->id;
9530 }
9531
9532 /**
9533  * clutter_actor_set_depth:
9534  * @self: a #ClutterActor
9535  * @depth: Z co-ord
9536  *
9537  * Sets the Z coordinate of @self to @depth.
9538  *
9539  * The unit used by @depth is dependant on the perspective setup. See
9540  * also clutter_stage_set_perspective().
9541  */
9542 void
9543 clutter_actor_set_depth (ClutterActor *self,
9544                          gfloat        depth)
9545 {
9546   ClutterActorPrivate *priv;
9547
9548   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9549
9550   priv = self->priv;
9551
9552   if (priv->z != depth)
9553     {
9554       /* Sets Z value - XXX 2.0: should we invert? */
9555       priv->z = depth;
9556
9557       priv->transform_valid = FALSE;
9558
9559       /* FIXME - remove this crap; sadly, there are still containers
9560        * in Clutter that depend on this utter brain damage
9561        */
9562       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9563
9564       clutter_actor_queue_redraw (self);
9565
9566       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9567     }
9568 }
9569
9570 /**
9571  * clutter_actor_get_depth:
9572  * @self: a #ClutterActor
9573  *
9574  * Retrieves the depth of @self.
9575  *
9576  * Return value: the depth of the actor
9577  */
9578 gfloat
9579 clutter_actor_get_depth (ClutterActor *self)
9580 {
9581   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
9582
9583   return self->priv->z;
9584 }
9585
9586 /**
9587  * clutter_actor_set_rotation:
9588  * @self: a #ClutterActor
9589  * @axis: the axis of rotation
9590  * @angle: the angle of rotation
9591  * @x: X coordinate of the rotation center
9592  * @y: Y coordinate of the rotation center
9593  * @z: Z coordinate of the rotation center
9594  *
9595  * Sets the rotation angle of @self around the given axis.
9596  *
9597  * The rotation center coordinates used depend on the value of @axis:
9598  * <itemizedlist>
9599  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
9600  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
9601  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
9602  * </itemizedlist>
9603  *
9604  * The rotation coordinates are relative to the anchor point of the
9605  * actor, set using clutter_actor_set_anchor_point(). If no anchor
9606  * point is set, the upper left corner is assumed as the origin.
9607  *
9608  * Since: 0.8
9609  */
9610 void
9611 clutter_actor_set_rotation (ClutterActor      *self,
9612                             ClutterRotateAxis  axis,
9613                             gdouble            angle,
9614                             gfloat             x,
9615                             gfloat             y,
9616                             gfloat             z)
9617 {
9618   ClutterVertex v;
9619
9620   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9621
9622   v.x = x;
9623   v.y = y;
9624   v.z = z;
9625
9626   g_object_freeze_notify (G_OBJECT (self));
9627
9628   clutter_actor_set_rotation_angle_internal (self, axis, angle);
9629   clutter_actor_set_rotation_center_internal (self, axis, &v);
9630
9631   g_object_thaw_notify (G_OBJECT (self));
9632 }
9633
9634 /**
9635  * clutter_actor_set_z_rotation_from_gravity:
9636  * @self: a #ClutterActor
9637  * @angle: the angle of rotation
9638  * @gravity: the center point of the rotation
9639  *
9640  * Sets the rotation angle of @self around the Z axis using the center
9641  * point specified as a compass point. For example to rotate such that
9642  * the center of the actor remains static you can use
9643  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
9644  * will move accordingly.
9645  *
9646  * Since: 1.0
9647  */
9648 void
9649 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
9650                                            gdouble         angle,
9651                                            ClutterGravity  gravity)
9652 {
9653   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9654
9655   if (gravity == CLUTTER_GRAVITY_NONE)
9656     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
9657   else
9658     {
9659       GObject *obj = G_OBJECT (self);
9660       ClutterTransformInfo *info;
9661
9662       info = _clutter_actor_get_transform_info (self);
9663
9664       g_object_freeze_notify (obj);
9665
9666       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
9667
9668       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
9669       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
9670       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
9671
9672       g_object_thaw_notify (obj);
9673     }
9674 }
9675
9676 /**
9677  * clutter_actor_get_rotation:
9678  * @self: a #ClutterActor
9679  * @axis: the axis of rotation
9680  * @x: (out): return value for the X coordinate of the center of rotation
9681  * @y: (out): return value for the Y coordinate of the center of rotation
9682  * @z: (out): return value for the Z coordinate of the center of rotation
9683  *
9684  * Retrieves the angle and center of rotation on the given axis,
9685  * set using clutter_actor_set_rotation().
9686  *
9687  * Return value: the angle of rotation
9688  *
9689  * Since: 0.8
9690  */
9691 gdouble
9692 clutter_actor_get_rotation (ClutterActor      *self,
9693                             ClutterRotateAxis  axis,
9694                             gfloat            *x,
9695                             gfloat            *y,
9696                             gfloat            *z)
9697 {
9698   const ClutterTransformInfo *info;
9699   const AnchorCoord *anchor_coord;
9700   gdouble retval = 0;
9701
9702   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9703
9704   info = _clutter_actor_get_transform_info_or_defaults (self);
9705
9706   switch (axis)
9707     {
9708     case CLUTTER_X_AXIS:
9709       anchor_coord = &info->rx_center;
9710       retval = info->rx_angle;
9711       break;
9712
9713     case CLUTTER_Y_AXIS:
9714       anchor_coord = &info->ry_center;
9715       retval = info->ry_angle;
9716       break;
9717
9718     case CLUTTER_Z_AXIS:
9719       anchor_coord = &info->rz_center;
9720       retval = info->rz_angle;
9721       break;
9722
9723     default:
9724       anchor_coord = NULL;
9725       retval = 0.0;
9726       break;
9727     }
9728
9729   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
9730
9731   return retval;
9732 }
9733
9734 /**
9735  * clutter_actor_get_z_rotation_gravity:
9736  * @self: A #ClutterActor
9737  *
9738  * Retrieves the center for the rotation around the Z axis as a
9739  * compass direction. If the center was specified in pixels or units
9740  * this will return %CLUTTER_GRAVITY_NONE.
9741  *
9742  * Return value: the Z rotation center
9743  *
9744  * Since: 1.0
9745  */
9746 ClutterGravity
9747 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
9748 {
9749   const ClutterTransformInfo *info;
9750
9751   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9752
9753   info = _clutter_actor_get_transform_info_or_defaults (self);
9754
9755   return clutter_anchor_coord_get_gravity (&info->rz_center);
9756 }
9757
9758 /**
9759  * clutter_actor_set_clip:
9760  * @self: A #ClutterActor
9761  * @xoff: X offset of the clip rectangle
9762  * @yoff: Y offset of the clip rectangle
9763  * @width: Width of the clip rectangle
9764  * @height: Height of the clip rectangle
9765  *
9766  * Sets clip area for @self. The clip area is always computed from the
9767  * upper left corner of the actor, even if the anchor point is set
9768  * otherwise.
9769  *
9770  * Since: 0.6
9771  */
9772 void
9773 clutter_actor_set_clip (ClutterActor *self,
9774                         gfloat        xoff,
9775                         gfloat        yoff,
9776                         gfloat        width,
9777                         gfloat        height)
9778 {
9779   ClutterActorPrivate *priv;
9780
9781   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9782
9783   priv = self->priv;
9784
9785   if (priv->has_clip &&
9786       priv->clip.x == xoff &&
9787       priv->clip.y == yoff &&
9788       priv->clip.width == width &&
9789       priv->clip.height == height)
9790     return;
9791
9792   priv->clip.x = xoff;
9793   priv->clip.y = yoff;
9794   priv->clip.width = width;
9795   priv->clip.height = height;
9796
9797   priv->has_clip = TRUE;
9798
9799   clutter_actor_queue_redraw (self);
9800
9801   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9802   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
9803 }
9804
9805 /**
9806  * clutter_actor_remove_clip:
9807  * @self: A #ClutterActor
9808  *
9809  * Removes clip area from @self.
9810  */
9811 void
9812 clutter_actor_remove_clip (ClutterActor *self)
9813 {
9814   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9815
9816   if (!self->priv->has_clip)
9817     return;
9818
9819   self->priv->has_clip = FALSE;
9820
9821   clutter_actor_queue_redraw (self);
9822
9823   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9824 }
9825
9826 /**
9827  * clutter_actor_has_clip:
9828  * @self: a #ClutterActor
9829  *
9830  * Determines whether the actor has a clip area set or not.
9831  *
9832  * Return value: %TRUE if the actor has a clip area set.
9833  *
9834  * Since: 0.1.1
9835  */
9836 gboolean
9837 clutter_actor_has_clip (ClutterActor *self)
9838 {
9839   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9840
9841   return self->priv->has_clip;
9842 }
9843
9844 /**
9845  * clutter_actor_get_clip:
9846  * @self: a #ClutterActor
9847  * @xoff: (out) (allow-none): return location for the X offset of
9848  *   the clip rectangle, or %NULL
9849  * @yoff: (out) (allow-none): return location for the Y offset of
9850  *   the clip rectangle, or %NULL
9851  * @width: (out) (allow-none): return location for the width of
9852  *   the clip rectangle, or %NULL
9853  * @height: (out) (allow-none): return location for the height of
9854  *   the clip rectangle, or %NULL
9855  *
9856  * Gets the clip area for @self, if any is set
9857  *
9858  * Since: 0.6
9859  */
9860 void
9861 clutter_actor_get_clip (ClutterActor *self,
9862                         gfloat       *xoff,
9863                         gfloat       *yoff,
9864                         gfloat       *width,
9865                         gfloat       *height)
9866 {
9867   ClutterActorPrivate *priv;
9868
9869   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9870
9871   priv = self->priv;
9872
9873   if (!priv->has_clip)
9874     return;
9875
9876   if (xoff != NULL)
9877     *xoff = priv->clip.x;
9878
9879   if (yoff != NULL)
9880     *yoff = priv->clip.y;
9881
9882   if (width != NULL)
9883     *width = priv->clip.width;
9884
9885   if (height != NULL)
9886     *height = priv->clip.height;
9887 }
9888
9889 /**
9890  * clutter_actor_get_children:
9891  * @self: a #ClutterActor
9892  *
9893  * Retrieves the list of children of @self.
9894  *
9895  * Return value: (transfer container) (element-type ClutterActor): A newly
9896  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
9897  *   done.
9898  *
9899  * Since: 1.10
9900  */
9901 GList *
9902 clutter_actor_get_children (ClutterActor *self)
9903 {
9904   ClutterActor *iter;
9905   GList *res;
9906
9907   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9908
9909   /* we walk the list backward so that we can use prepend(),
9910    * which is O(1)
9911    */
9912   for (iter = self->priv->last_child, res = NULL;
9913        iter != NULL;
9914        iter = iter->priv->prev_sibling)
9915     {
9916       res = g_list_prepend (res, iter);
9917     }
9918
9919   return res;
9920 }
9921
9922 /*< private >
9923  * insert_child_at_depth:
9924  * @self: a #ClutterActor
9925  * @child: a #ClutterActor
9926  *
9927  * Inserts @child inside the list of children held by @self, using
9928  * the depth as the insertion criteria.
9929  *
9930  * This sadly makes the insertion not O(1), but we can keep the
9931  * list sorted so that the painters algorithm we use for painting
9932  * the children will work correctly.
9933  */
9934 static void
9935 insert_child_at_depth (ClutterActor *self,
9936                        ClutterActor *child,
9937                        gpointer      dummy G_GNUC_UNUSED)
9938 {
9939   ClutterActor *iter;
9940
9941   child->priv->parent = self;
9942
9943   /* special-case the first child */
9944   if (self->priv->n_children == 0)
9945     {
9946       self->priv->first_child = child;
9947       self->priv->last_child = child;
9948
9949       child->priv->next_sibling = NULL;
9950       child->priv->prev_sibling = NULL;
9951
9952       return;
9953     }
9954
9955   /* Find the right place to insert the child so that it will still be
9956      sorted and the child will be after all of the actors at the same
9957      dept */
9958   for (iter = self->priv->first_child;
9959        iter != NULL;
9960        iter = iter->priv->next_sibling)
9961     {
9962       if (iter->priv->z > child->priv->z)
9963         break;
9964     }
9965
9966   if (iter != NULL)
9967     {
9968       ClutterActor *tmp = iter->priv->prev_sibling;
9969
9970       if (tmp != NULL)
9971         tmp->priv->next_sibling = child;
9972
9973       /* Insert the node before the found one */
9974       child->priv->prev_sibling = iter->priv->prev_sibling;
9975       child->priv->next_sibling = iter;
9976       iter->priv->prev_sibling = child;
9977     }
9978   else
9979     {
9980       ClutterActor *tmp = self->priv->last_child;
9981
9982       if (tmp != NULL)
9983         tmp->priv->next_sibling = child;
9984
9985       /* insert the node at the end of the list */
9986       child->priv->prev_sibling = self->priv->last_child;
9987       child->priv->next_sibling = NULL;
9988     }
9989
9990   if (child->priv->prev_sibling == NULL)
9991     self->priv->first_child = child;
9992
9993   if (child->priv->next_sibling == NULL)
9994     self->priv->last_child = child;
9995 }
9996
9997 static void
9998 insert_child_at_index (ClutterActor *self,
9999                        ClutterActor *child,
10000                        gpointer      data_)
10001 {
10002   gint index_ = GPOINTER_TO_INT (data_);
10003
10004   child->priv->parent = self;
10005
10006   if (index_ == 0)
10007     {
10008       ClutterActor *tmp = self->priv->first_child;
10009
10010       if (tmp != NULL)
10011         tmp->priv->prev_sibling = child;
10012
10013       child->priv->prev_sibling = NULL;
10014       child->priv->next_sibling = tmp;
10015     }
10016   else if (index_ < 0 || index_ >= self->priv->n_children)
10017     {
10018       ClutterActor *tmp = self->priv->last_child;
10019
10020       if (tmp != NULL)
10021         tmp->priv->next_sibling = child;
10022
10023       child->priv->prev_sibling = tmp;
10024       child->priv->next_sibling = NULL;
10025     }
10026   else
10027     {
10028       ClutterActor *iter;
10029       int i;
10030
10031       for (iter = self->priv->first_child, i = 0;
10032            iter != NULL;
10033            iter = iter->priv->next_sibling, i += 1)
10034         {
10035           if (index_ == i)
10036             {
10037               ClutterActor *tmp = iter->priv->prev_sibling;
10038
10039               child->priv->prev_sibling = tmp;
10040               child->priv->next_sibling = iter;
10041
10042               iter->priv->prev_sibling = child;
10043
10044               if (tmp != NULL)
10045                 tmp->priv->next_sibling = child;
10046
10047               break;
10048             }
10049         }
10050     }
10051
10052   if (child->priv->prev_sibling == NULL)
10053     self->priv->first_child = child;
10054
10055   if (child->priv->next_sibling == NULL)
10056     self->priv->last_child = child;
10057 }
10058
10059 static void
10060 insert_child_above (ClutterActor *self,
10061                     ClutterActor *child,
10062                     gpointer      data)
10063 {
10064   ClutterActor *sibling = data;
10065
10066   child->priv->parent = self;
10067
10068   if (sibling == NULL)
10069     sibling = self->priv->last_child;
10070
10071   child->priv->prev_sibling = sibling;
10072
10073   if (sibling != NULL)
10074     {
10075       ClutterActor *tmp = sibling->priv->next_sibling;
10076
10077       child->priv->next_sibling = tmp;
10078
10079       if (tmp != NULL)
10080         tmp->priv->prev_sibling = child;
10081
10082       sibling->priv->next_sibling = child;
10083     }
10084   else
10085     child->priv->next_sibling = NULL;
10086
10087   if (child->priv->prev_sibling == NULL)
10088     self->priv->first_child = child;
10089
10090   if (child->priv->next_sibling == NULL)
10091     self->priv->last_child = child;
10092 }
10093
10094 static void
10095 insert_child_below (ClutterActor *self,
10096                     ClutterActor *child,
10097                     gpointer      data)
10098 {
10099   ClutterActor *sibling = data;
10100
10101   child->priv->parent = self;
10102
10103   if (sibling == NULL)
10104     sibling = self->priv->first_child;
10105
10106   child->priv->next_sibling = sibling;
10107
10108   if (sibling != NULL)
10109     {
10110       ClutterActor *tmp = sibling->priv->prev_sibling;
10111
10112       child->priv->prev_sibling = tmp;
10113
10114       if (tmp != NULL)
10115         tmp->priv->next_sibling = child;
10116
10117       sibling->priv->prev_sibling = child;
10118     }
10119   else
10120     child->priv->prev_sibling = NULL;
10121
10122   if (child->priv->prev_sibling == NULL)
10123     self->priv->first_child = child;
10124
10125   if (child->priv->next_sibling == NULL)
10126     self->priv->last_child = child;
10127 }
10128
10129 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10130                                            ClutterActor *child,
10131                                            gpointer      data);
10132
10133 typedef enum {
10134   ADD_CHILD_CREATE_META       = 1 << 0,
10135   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10136   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10137   ADD_CHILD_CHECK_STATE       = 1 << 3,
10138   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10139
10140   /* default flags for public API */
10141   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10142                                ADD_CHILD_EMIT_PARENT_SET |
10143                                ADD_CHILD_EMIT_ACTOR_ADDED |
10144                                ADD_CHILD_CHECK_STATE |
10145                                ADD_CHILD_NOTIFY_FIRST_LAST,
10146
10147   /* flags for legacy/deprecated API */
10148   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10149                                ADD_CHILD_CHECK_STATE |
10150                                ADD_CHILD_NOTIFY_FIRST_LAST
10151 } ClutterActorAddChildFlags;
10152
10153 /*< private >
10154  * clutter_actor_add_child_internal:
10155  * @self: a #ClutterActor
10156  * @child: a #ClutterActor
10157  * @flags: control flags for actions
10158  * @add_func: delegate function
10159  * @data: (closure): data to pass to @add_func
10160  *
10161  * Adds @child to the list of children of @self.
10162  *
10163  * The actual insertion inside the list is delegated to @add_func: this
10164  * function will just set up the state, perform basic checks, and emit
10165  * signals.
10166  *
10167  * The @flags argument is used to perform additional operations.
10168  */
10169 static inline void
10170 clutter_actor_add_child_internal (ClutterActor              *self,
10171                                   ClutterActor              *child,
10172                                   ClutterActorAddChildFlags  flags,
10173                                   ClutterActorAddChildFunc   add_func,
10174                                   gpointer                   data)
10175 {
10176   ClutterTextDirection text_dir;
10177   gboolean create_meta;
10178   gboolean emit_parent_set, emit_actor_added;
10179   gboolean check_state;
10180   gboolean notify_first_last;
10181   ClutterActor *old_first_child, *old_last_child;
10182
10183   if (child->priv->parent != NULL)
10184     {
10185       g_warning ("Cannot set a parent on an actor which has a parent. "
10186                  "You must use clutter_actor_remove_child() first.");
10187       return;
10188     }
10189
10190   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10191     {
10192       g_warning ("Cannot set a parent on a toplevel actor\n");
10193       return;
10194     }
10195
10196   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10197     {
10198       g_warning ("Cannot set a parent currently being destroyed");
10199       return;
10200     }
10201
10202   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10203   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10204   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10205   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10206   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10207
10208   old_first_child = self->priv->first_child;
10209   old_last_child = self->priv->last_child;
10210
10211   g_object_freeze_notify (G_OBJECT (self));
10212
10213   if (create_meta)
10214     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10215
10216   g_object_ref_sink (child);
10217   child->priv->parent = NULL;
10218   child->priv->next_sibling = NULL;
10219   child->priv->prev_sibling = NULL;
10220
10221   /* delegate the actual insertion */
10222   add_func (self, child, data);
10223
10224   g_assert (child->priv->parent == self);
10225
10226   self->priv->n_children += 1;
10227
10228   self->priv->age += 1;
10229
10230   /* if push_internal() has been called then we automatically set
10231    * the flag on the actor
10232    */
10233   if (self->priv->internal_child)
10234     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10235
10236   /* clutter_actor_reparent() will emit ::parent-set for us */
10237   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10238     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10239
10240   if (check_state)
10241     {
10242       /* If parent is mapped or realized, we need to also be mapped or
10243        * realized once we're inside the parent.
10244        */
10245       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10246
10247       /* propagate the parent's text direction to the child */
10248       text_dir = clutter_actor_get_text_direction (self);
10249       clutter_actor_set_text_direction (child, text_dir);
10250     }
10251
10252   if (child->priv->show_on_set_parent)
10253     clutter_actor_show (child);
10254
10255   if (CLUTTER_ACTOR_IS_MAPPED (child))
10256     clutter_actor_queue_redraw (child);
10257
10258   /* maintain the invariant that if an actor needs layout,
10259    * its parents do as well
10260    */
10261   if (child->priv->needs_width_request ||
10262       child->priv->needs_height_request ||
10263       child->priv->needs_allocation)
10264     {
10265       /* we work around the short-circuiting we do
10266        * in clutter_actor_queue_relayout() since we
10267        * want to force a relayout
10268        */
10269       child->priv->needs_width_request = TRUE;
10270       child->priv->needs_height_request = TRUE;
10271       child->priv->needs_allocation = TRUE;
10272
10273       clutter_actor_queue_relayout (child->priv->parent);
10274     }
10275
10276   if (emit_actor_added)
10277     g_signal_emit_by_name (self, "actor-added", child);
10278
10279   if (notify_first_last)
10280     {
10281       if (old_first_child != self->priv->first_child)
10282         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10283
10284       if (old_last_child != self->priv->last_child)
10285         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10286     }
10287
10288   g_object_thaw_notify (G_OBJECT (self));
10289 }
10290
10291 /**
10292  * clutter_actor_add_child:
10293  * @self: a #ClutterActor
10294  * @child: a #ClutterActor
10295  *
10296  * Adds @child to the children of @self.
10297  *
10298  * This function will acquire a reference on @child that will only
10299  * be released when calling clutter_actor_remove_child().
10300  *
10301  * This function will take into consideration the #ClutterActor:depth
10302  * of @child, and will keep the list of children sorted.
10303  *
10304  * This function will emit the #ClutterContainer::actor-added signal
10305  * on @self.
10306  *
10307  * Since: 1.10
10308  */
10309 void
10310 clutter_actor_add_child (ClutterActor *self,
10311                          ClutterActor *child)
10312 {
10313   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10314   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10315   g_return_if_fail (self != child);
10316   g_return_if_fail (child->priv->parent == NULL);
10317
10318   clutter_actor_add_child_internal (self, child,
10319                                     ADD_CHILD_DEFAULT_FLAGS,
10320                                     insert_child_at_depth,
10321                                     NULL);
10322 }
10323
10324 /**
10325  * clutter_actor_insert_child_at_index:
10326  * @self: a #ClutterActor
10327  * @child: a #ClutterActor
10328  * @index_: the index
10329  *
10330  * Inserts @child into the list of children of @self, using the
10331  * given @index_. If @index_ is greater than the number of children
10332  * in @self, or is less than 0, then the new child is added at the end.
10333  *
10334  * This function will acquire a reference on @child that will only
10335  * be released when calling clutter_actor_remove_child().
10336  *
10337  * This function will not take into consideration the #ClutterActor:depth
10338  * of @child.
10339  *
10340  * This function will emit the #ClutterContainer::actor-added signal
10341  * on @self.
10342  *
10343  * Since: 1.10
10344  */
10345 void
10346 clutter_actor_insert_child_at_index (ClutterActor *self,
10347                                      ClutterActor *child,
10348                                      gint          index_)
10349 {
10350   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10351   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10352   g_return_if_fail (self != child);
10353   g_return_if_fail (child->priv->parent == NULL);
10354
10355   clutter_actor_add_child_internal (self, child,
10356                                     ADD_CHILD_DEFAULT_FLAGS,
10357                                     insert_child_at_index,
10358                                     GINT_TO_POINTER (index_));
10359 }
10360
10361 /**
10362  * clutter_actor_insert_child_above:
10363  * @self: a #ClutterActor
10364  * @child: a #ClutterActor
10365  * @sibling: (allow-none): a child of @self, or %NULL
10366  *
10367  * Inserts @child into the list of children of @self, above another
10368  * child of @self or, if @sibling is %NULL, above all the children
10369  * of @self.
10370  *
10371  * This function will acquire a reference on @child that will only
10372  * be released when calling clutter_actor_remove_child().
10373  *
10374  * This function will not take into consideration the #ClutterActor:depth
10375  * of @child.
10376  *
10377  * This function will emit the #ClutterContainer::actor-added signal
10378  * on @self.
10379  *
10380  * Since: 1.10
10381  */
10382 void
10383 clutter_actor_insert_child_above (ClutterActor *self,
10384                                   ClutterActor *child,
10385                                   ClutterActor *sibling)
10386 {
10387   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10388   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10389   g_return_if_fail (self != child);
10390   g_return_if_fail (child != sibling);
10391   g_return_if_fail (child->priv->parent == NULL);
10392   g_return_if_fail (sibling == NULL ||
10393                     (CLUTTER_IS_ACTOR (sibling) &&
10394                      sibling->priv->parent == self));
10395
10396   clutter_actor_add_child_internal (self, child,
10397                                     ADD_CHILD_DEFAULT_FLAGS,
10398                                     insert_child_above,
10399                                     sibling);
10400 }
10401
10402 /**
10403  * clutter_actor_insert_child_below:
10404  * @self: a #ClutterActor
10405  * @child: a #ClutterActor
10406  * @sibling: (allow-none): a child of @self, or %NULL
10407  *
10408  * Inserts @child into the list of children of @self, below another
10409  * child of @self or, if @sibling is %NULL, below all the children
10410  * of @self.
10411  *
10412  * This function will acquire a reference on @child that will only
10413  * be released when calling clutter_actor_remove_child().
10414  *
10415  * This function will not take into consideration the #ClutterActor:depth
10416  * of @child.
10417  *
10418  * This function will emit the #ClutterContainer::actor-added signal
10419  * on @self.
10420  *
10421  * Since: 1.10
10422  */
10423 void
10424 clutter_actor_insert_child_below (ClutterActor *self,
10425                                   ClutterActor *child,
10426                                   ClutterActor *sibling)
10427 {
10428   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10429   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10430   g_return_if_fail (self != child);
10431   g_return_if_fail (child != sibling);
10432   g_return_if_fail (child->priv->parent == NULL);
10433   g_return_if_fail (sibling == NULL ||
10434                     (CLUTTER_IS_ACTOR (sibling) &&
10435                      sibling->priv->parent == self));
10436
10437   clutter_actor_add_child_internal (self, child,
10438                                     ADD_CHILD_DEFAULT_FLAGS,
10439                                     insert_child_below,
10440                                     sibling);
10441 }
10442
10443 /**
10444  * clutter_actor_set_parent:
10445  * @self: A #ClutterActor
10446  * @parent: A new #ClutterActor parent
10447  *
10448  * Sets the parent of @self to @parent.
10449  *
10450  * This function will result in @parent acquiring a reference on @self,
10451  * eventually by sinking its floating reference first. The reference
10452  * will be released by clutter_actor_unparent().
10453  *
10454  * This function should only be called by legacy #ClutterActor<!-- -->s
10455  * implementing the #ClutterContainer interface.
10456  *
10457  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10458  */
10459 void
10460 clutter_actor_set_parent (ClutterActor *self,
10461                           ClutterActor *parent)
10462 {
10463   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10464   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10465   g_return_if_fail (self != parent);
10466   g_return_if_fail (self->priv->parent == NULL);
10467
10468   /* as this function will be called inside ClutterContainer::add
10469    * implementations or when building up a composite actor, we have
10470    * to preserve the old behaviour, and not create child meta or
10471    * emit the ::actor-added signal, to avoid recursion or double
10472    * emissions
10473    */
10474   clutter_actor_add_child_internal (parent, self,
10475                                     ADD_CHILD_LEGACY_FLAGS,
10476                                     insert_child_at_depth,
10477                                     NULL);
10478 }
10479
10480 /**
10481  * clutter_actor_get_parent:
10482  * @self: A #ClutterActor
10483  *
10484  * Retrieves the parent of @self.
10485  *
10486  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10487  *  if no parent is set
10488  */
10489 ClutterActor *
10490 clutter_actor_get_parent (ClutterActor *self)
10491 {
10492   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10493
10494   return self->priv->parent;
10495 }
10496
10497 /**
10498  * clutter_actor_get_paint_visibility:
10499  * @self: A #ClutterActor
10500  *
10501  * Retrieves the 'paint' visibility of an actor recursively checking for non
10502  * visible parents.
10503  *
10504  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10505  *
10506  * Return Value: %TRUE if the actor is visibile and will be painted.
10507  *
10508  * Since: 0.8.4
10509  */
10510 gboolean
10511 clutter_actor_get_paint_visibility (ClutterActor *actor)
10512 {
10513   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10514
10515   return CLUTTER_ACTOR_IS_MAPPED (actor);
10516 }
10517
10518 /**
10519  * clutter_actor_remove_child:
10520  * @self: a #ClutterActor
10521  * @child: a #ClutterActor
10522  *
10523  * Removes @child from the children of @self.
10524  *
10525  * This function will release the reference added by
10526  * clutter_actor_add_child(), so if you want to keep using @child
10527  * you will have to acquire a referenced on it before calling this
10528  * function.
10529  *
10530  * This function will emit the #ClutterContainer::actor-removed
10531  * signal on @self.
10532  *
10533  * Since: 1.10
10534  */
10535 void
10536 clutter_actor_remove_child (ClutterActor *self,
10537                             ClutterActor *child)
10538 {
10539   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10540   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10541   g_return_if_fail (self != child);
10542   g_return_if_fail (child->priv->parent != NULL);
10543   g_return_if_fail (child->priv->parent == self);
10544
10545   clutter_actor_remove_child_internal (self, child,
10546                                        REMOVE_CHILD_DEFAULT_FLAGS);
10547 }
10548
10549 /**
10550  * clutter_actor_remove_all_children:
10551  * @self: a #ClutterActor
10552  *
10553  * Removes all children of @self.
10554  *
10555  * This function releases the reference added by inserting a child actor
10556  * in the list of children of @self.
10557  *
10558  * If the reference count of a child drops to zero, the child will be
10559  * destroyed. If you want to ensure the destruction of all the children
10560  * of @self, use clutter_actor_destroy_all_children().
10561  *
10562  * Since: 1.10
10563  */
10564 void
10565 clutter_actor_remove_all_children (ClutterActor *self)
10566 {
10567   ClutterActorIter iter;
10568
10569   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10570
10571   if (self->priv->n_children == 0)
10572     return;
10573
10574   g_object_freeze_notify (G_OBJECT (self));
10575
10576   clutter_actor_iter_init (&iter, self);
10577   while (clutter_actor_iter_next (&iter, NULL))
10578     clutter_actor_iter_remove (&iter);
10579
10580   g_object_thaw_notify (G_OBJECT (self));
10581
10582   /* sanity check */
10583   g_assert (self->priv->first_child == NULL);
10584   g_assert (self->priv->last_child == NULL);
10585   g_assert (self->priv->n_children == 0);
10586 }
10587
10588 /**
10589  * clutter_actor_destroy_all_children:
10590  * @self: a #ClutterActor
10591  *
10592  * Destroys all children of @self.
10593  *
10594  * This function releases the reference added by inserting a child
10595  * actor in the list of children of @self, and ensures that the
10596  * #ClutterActor::destroy signal is emitted on each child of the
10597  * actor.
10598  *
10599  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
10600  * when its reference count drops to 0; the default handler of the
10601  * #ClutterActor::destroy signal will destroy all the children of an
10602  * actor. This function ensures that all children are destroyed, instead
10603  * of just removed from @self, unlike clutter_actor_remove_all_children()
10604  * which will merely release the reference and remove each child.
10605  *
10606  * Unless you acquired an additional reference on each child of @self
10607  * prior to calling clutter_actor_remove_all_children() and want to reuse
10608  * the actors, you should use clutter_actor_destroy_all_children() in
10609  * order to make sure that children are destroyed and signal handlers
10610  * are disconnected even in cases where circular references prevent this
10611  * from automatically happening through reference counting alone.
10612  *
10613  * Since: 1.10
10614  */
10615 void
10616 clutter_actor_destroy_all_children (ClutterActor *self)
10617 {
10618   ClutterActorIter iter;
10619
10620   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10621
10622   if (self->priv->n_children == 0)
10623     return;
10624
10625   g_object_freeze_notify (G_OBJECT (self));
10626
10627   clutter_actor_iter_init (&iter, self);
10628   while (clutter_actor_iter_next (&iter, NULL))
10629     clutter_actor_iter_destroy (&iter);
10630
10631   g_object_thaw_notify (G_OBJECT (self));
10632
10633   /* sanity check */
10634   g_assert (self->priv->first_child == NULL);
10635   g_assert (self->priv->last_child == NULL);
10636   g_assert (self->priv->n_children == 0);
10637 }
10638
10639 typedef struct _InsertBetweenData {
10640   ClutterActor *prev_sibling;
10641   ClutterActor *next_sibling;
10642 } InsertBetweenData;
10643
10644 static void
10645 insert_child_between (ClutterActor *self,
10646                       ClutterActor *child,
10647                       gpointer      data_)
10648 {
10649   InsertBetweenData *data = data_;
10650   ClutterActor *prev_sibling = data->prev_sibling;
10651   ClutterActor *next_sibling = data->next_sibling;
10652
10653   child->priv->parent = self;
10654   child->priv->prev_sibling = prev_sibling;
10655   child->priv->next_sibling = next_sibling;
10656
10657   if (prev_sibling != NULL)
10658     prev_sibling->priv->next_sibling = child;
10659
10660   if (next_sibling != NULL)
10661     next_sibling->priv->prev_sibling = child;
10662
10663   if (child->priv->prev_sibling == NULL)
10664     self->priv->first_child = child;
10665
10666   if (child->priv->next_sibling == NULL)
10667     self->priv->last_child = child;
10668 }
10669
10670 /**
10671  * clutter_actor_replace_child:
10672  * @self: a #ClutterActor
10673  * @old_child: the child of @self to replace
10674  * @new_child: the #ClutterActor to replace @old_child
10675  *
10676  * Replaces @old_child with @new_child in the list of children of @self.
10677  *
10678  * Since: 1.10
10679  */
10680 void
10681 clutter_actor_replace_child (ClutterActor *self,
10682                              ClutterActor *old_child,
10683                              ClutterActor *new_child)
10684 {
10685   ClutterActor *prev_sibling, *next_sibling;
10686   InsertBetweenData clos;
10687
10688   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10689   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
10690   g_return_if_fail (old_child->priv->parent == self);
10691   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
10692   g_return_if_fail (old_child != new_child);
10693   g_return_if_fail (new_child != self);
10694   g_return_if_fail (new_child->priv->parent == NULL);
10695
10696   prev_sibling = old_child->priv->prev_sibling;
10697   next_sibling = old_child->priv->next_sibling;
10698   clutter_actor_remove_child_internal (self, old_child,
10699                                        REMOVE_CHILD_DEFAULT_FLAGS);
10700
10701   clos.prev_sibling = prev_sibling;
10702   clos.next_sibling = next_sibling;
10703   clutter_actor_add_child_internal (self, new_child,
10704                                     ADD_CHILD_DEFAULT_FLAGS,
10705                                     insert_child_between,
10706                                     &clos);
10707 }
10708
10709 /**
10710  * clutter_actor_unparent:
10711  * @self: a #ClutterActor
10712  *
10713  * Removes the parent of @self.
10714  *
10715  * This will cause the parent of @self to release the reference
10716  * acquired when calling clutter_actor_set_parent(), so if you
10717  * want to keep @self you will have to acquire a reference of
10718  * your own, through g_object_ref().
10719  *
10720  * This function should only be called by legacy #ClutterActor<!-- -->s
10721  * implementing the #ClutterContainer interface.
10722  *
10723  * Since: 0.1.1
10724  *
10725  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
10726  */
10727 void
10728 clutter_actor_unparent (ClutterActor *self)
10729 {
10730   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10731
10732   if (self->priv->parent == NULL)
10733     return;
10734
10735   clutter_actor_remove_child_internal (self->priv->parent, self,
10736                                        REMOVE_CHILD_LEGACY_FLAGS);
10737 }
10738
10739 /**
10740  * clutter_actor_reparent:
10741  * @self: a #ClutterActor
10742  * @new_parent: the new #ClutterActor parent
10743  *
10744  * Resets the parent actor of @self.
10745  *
10746  * This function is logically equivalent to calling clutter_actor_unparent()
10747  * and clutter_actor_set_parent(), but more efficiently implemented, as it
10748  * ensures the child is not finalized when unparented, and emits the
10749  * #ClutterActor::parent-set signal only once.
10750  *
10751  * In reality, calling this function is less useful than it sounds, as some
10752  * application code may rely on changes in the intermediate state between
10753  * removal and addition of the actor from its old parent to the @new_parent.
10754  * Thus, it is strongly encouraged to avoid using this function in application
10755  * code.
10756  *
10757  * Since: 0.2
10758  *
10759  * Deprecated: 1.10: Use clutter_actor_remove_child() and
10760  *   clutter_actor_add_child() instead; remember to take a reference on
10761  *   the actor being removed before calling clutter_actor_remove_child()
10762  *   to avoid the reference count dropping to zero and the actor being
10763  *   destroyed.
10764  */
10765 void
10766 clutter_actor_reparent (ClutterActor *self,
10767                         ClutterActor *new_parent)
10768 {
10769   ClutterActorPrivate *priv;
10770
10771   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10772   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
10773   g_return_if_fail (self != new_parent);
10774
10775   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10776     {
10777       g_warning ("Cannot set a parent on a toplevel actor");
10778       return;
10779     }
10780
10781   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
10782     {
10783       g_warning ("Cannot set a parent currently being destroyed");
10784       return;
10785     }
10786
10787   priv = self->priv;
10788
10789   if (priv->parent != new_parent)
10790     {
10791       ClutterActor *old_parent;
10792
10793       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10794
10795       old_parent = priv->parent;
10796
10797       g_object_ref (self);
10798
10799       if (old_parent != NULL)
10800         {
10801          /* go through the Container implementation if this is a regular
10802           * child and not an internal one
10803           */
10804          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10805            {
10806              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
10807
10808              /* this will have to call unparent() */
10809              clutter_container_remove_actor (parent, self);
10810            }
10811          else
10812            clutter_actor_remove_child_internal (old_parent, self,
10813                                                 REMOVE_CHILD_LEGACY_FLAGS);
10814         }
10815
10816       /* Note, will call set_parent() */
10817       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10818         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
10819       else
10820         clutter_actor_add_child_internal (new_parent, self,
10821                                           ADD_CHILD_LEGACY_FLAGS,
10822                                           insert_child_at_depth,
10823                                           NULL);
10824
10825       /* we emit the ::parent-set signal once */
10826       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
10827
10828       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10829
10830       /* the IN_REPARENT flag suspends state updates */
10831       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
10832
10833       g_object_unref (self);
10834    }
10835 }
10836
10837 /**
10838  * clutter_actor_contains:
10839  * @self: A #ClutterActor
10840  * @descendant: A #ClutterActor, possibly contained in @self
10841  *
10842  * Determines if @descendant is contained inside @self (either as an
10843  * immediate child, or as a deeper descendant). If @self and
10844  * @descendant point to the same actor then it will also return %TRUE.
10845  *
10846  * Return value: whether @descendent is contained within @self
10847  *
10848  * Since: 1.4
10849  */
10850 gboolean
10851 clutter_actor_contains (ClutterActor *self,
10852                         ClutterActor *descendant)
10853 {
10854   ClutterActor *actor;
10855
10856   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10857   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
10858
10859   for (actor = descendant; actor; actor = actor->priv->parent)
10860     if (actor == self)
10861       return TRUE;
10862
10863   return FALSE;
10864 }
10865
10866 /**
10867  * clutter_actor_set_child_above_sibling:
10868  * @self: a #ClutterActor
10869  * @child: a #ClutterActor child of @self
10870  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10871  *
10872  * Sets @child to be above @sibling in the list of children of @self.
10873  *
10874  * If @sibling is %NULL, @child will be the new last child of @self.
10875  *
10876  * This function is logically equivalent to removing @child and using
10877  * clutter_actor_insert_child_above(), but it will not emit signals
10878  * or change state on @child.
10879  *
10880  * Since: 1.10
10881  */
10882 void
10883 clutter_actor_set_child_above_sibling (ClutterActor *self,
10884                                        ClutterActor *child,
10885                                        ClutterActor *sibling)
10886 {
10887   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10888   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10889   g_return_if_fail (child->priv->parent == self);
10890   g_return_if_fail (child != sibling);
10891   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10892
10893   if (sibling != NULL)
10894     g_return_if_fail (sibling->priv->parent == self);
10895
10896   /* we don't want to change the state of child, or emit signals, or
10897    * regenerate ChildMeta instances here, but we still want to follow
10898    * the correct sequence of steps encoded in remove_child() and
10899    * add_child(), so that correctness is ensured, and we only go
10900    * through one known code path.
10901    */
10902   g_object_ref (child);
10903   clutter_actor_remove_child_internal (self, child, 0);
10904   clutter_actor_add_child_internal (self, child,
10905                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10906                                     insert_child_above,
10907                                     sibling);
10908
10909   clutter_actor_queue_relayout (self);
10910 }
10911
10912 /**
10913  * clutter_actor_set_child_below_sibling:
10914  * @self: a #ClutterActor
10915  * @child: a #ClutterActor child of @self
10916  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10917  *
10918  * Sets @child to be below @sibling in the list of children of @self.
10919  *
10920  * If @sibling is %NULL, @child will be the new first child of @self.
10921  *
10922  * This function is logically equivalent to removing @self and using
10923  * clutter_actor_insert_child_below(), but it will not emit signals
10924  * or change state on @child.
10925  *
10926  * Since: 1.10
10927  */
10928 void
10929 clutter_actor_set_child_below_sibling (ClutterActor *self,
10930                                        ClutterActor *child,
10931                                        ClutterActor *sibling)
10932 {
10933   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10934   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10935   g_return_if_fail (child->priv->parent == self);
10936   g_return_if_fail (child != sibling);
10937   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10938
10939   if (sibling != NULL)
10940     g_return_if_fail (sibling->priv->parent == self);
10941
10942   /* see the comment in set_child_above_sibling() */
10943   g_object_ref (child);
10944   clutter_actor_remove_child_internal (self, child, 0);
10945   clutter_actor_add_child_internal (self, child,
10946                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10947                                     insert_child_below,
10948                                     sibling);
10949
10950   clutter_actor_queue_relayout (self);
10951 }
10952
10953 /**
10954  * clutter_actor_set_child_at_index:
10955  * @self: a #ClutterActor
10956  * @child: a #ClutterActor child of @self
10957  * @index_: the new index for @child
10958  *
10959  * Changes the index of @child in the list of children of @self.
10960  *
10961  * This function is logically equivalent to removing @child and
10962  * calling clutter_actor_insert_child_at_index(), but it will not
10963  * emit signals or change state on @child.
10964  *
10965  * Since: 1.10
10966  */
10967 void
10968 clutter_actor_set_child_at_index (ClutterActor *self,
10969                                   ClutterActor *child,
10970                                   gint          index_)
10971 {
10972   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10973   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10974   g_return_if_fail (child->priv->parent == self);
10975   g_return_if_fail (index_ <= self->priv->n_children);
10976
10977   g_object_ref (child);
10978   clutter_actor_remove_child_internal (self, child, 0);
10979   clutter_actor_add_child_internal (self, child,
10980                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10981                                     insert_child_at_index,
10982                                     GINT_TO_POINTER (index_));
10983
10984   clutter_actor_queue_relayout (self);
10985 }
10986
10987 /**
10988  * clutter_actor_raise:
10989  * @self: A #ClutterActor
10990  * @below: (allow-none): A #ClutterActor to raise above.
10991  *
10992  * Puts @self above @below.
10993  *
10994  * Both actors must have the same parent, and the parent must implement
10995  * the #ClutterContainer interface
10996  *
10997  * This function calls clutter_container_raise_child() internally.
10998  *
10999  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11000  */
11001 void
11002 clutter_actor_raise (ClutterActor *self,
11003                      ClutterActor *below)
11004 {
11005   ClutterActor *parent;
11006
11007   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11008
11009   parent = clutter_actor_get_parent (self);
11010   if (parent == NULL)
11011     {
11012       g_warning ("%s: Actor '%s' is not inside a container",
11013                  G_STRFUNC,
11014                  _clutter_actor_get_debug_name (self));
11015       return;
11016     }
11017
11018   if (below != NULL)
11019     {
11020       if (parent != clutter_actor_get_parent (below))
11021         {
11022           g_warning ("%s Actor '%s' is not in the same container as "
11023                      "actor '%s'",
11024                      G_STRFUNC,
11025                      _clutter_actor_get_debug_name (self),
11026                      _clutter_actor_get_debug_name (below));
11027           return;
11028         }
11029     }
11030
11031   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11032 }
11033
11034 /**
11035  * clutter_actor_lower:
11036  * @self: A #ClutterActor
11037  * @above: (allow-none): A #ClutterActor to lower below
11038  *
11039  * Puts @self below @above.
11040  *
11041  * Both actors must have the same parent, and the parent must implement
11042  * the #ClutterContainer interface.
11043  *
11044  * This function calls clutter_container_lower_child() internally.
11045  *
11046  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11047  */
11048 void
11049 clutter_actor_lower (ClutterActor *self,
11050                      ClutterActor *above)
11051 {
11052   ClutterActor *parent;
11053
11054   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11055
11056   parent = clutter_actor_get_parent (self);
11057   if (parent == NULL)
11058     {
11059       g_warning ("%s: Actor of type %s is not inside a container",
11060                  G_STRFUNC,
11061                  _clutter_actor_get_debug_name (self));
11062       return;
11063     }
11064
11065   if (above)
11066     {
11067       if (parent != clutter_actor_get_parent (above))
11068         {
11069           g_warning ("%s: Actor '%s' is not in the same container as "
11070                      "actor '%s'",
11071                      G_STRFUNC,
11072                      _clutter_actor_get_debug_name (self),
11073                      _clutter_actor_get_debug_name (above));
11074           return;
11075         }
11076     }
11077
11078   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11079 }
11080
11081 /**
11082  * clutter_actor_raise_top:
11083  * @self: A #ClutterActor
11084  *
11085  * Raises @self to the top.
11086  *
11087  * This function calls clutter_actor_raise() internally.
11088  *
11089  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11090  *   a %NULL sibling, instead.
11091  */
11092 void
11093 clutter_actor_raise_top (ClutterActor *self)
11094 {
11095   clutter_actor_raise (self, NULL);
11096 }
11097
11098 /**
11099  * clutter_actor_lower_bottom:
11100  * @self: A #ClutterActor
11101  *
11102  * Lowers @self to the bottom.
11103  *
11104  * This function calls clutter_actor_lower() internally.
11105  *
11106  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11107  *   a %NULL sibling, instead.
11108  */
11109 void
11110 clutter_actor_lower_bottom (ClutterActor *self)
11111 {
11112   clutter_actor_lower (self, NULL);
11113 }
11114
11115 /*
11116  * Event handling
11117  */
11118
11119 /**
11120  * clutter_actor_event:
11121  * @actor: a #ClutterActor
11122  * @event: a #ClutterEvent
11123  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11124  *
11125  * This function is used to emit an event on the main stage.
11126  * You should rarely need to use this function, except for
11127  * synthetising events.
11128  *
11129  * Return value: the return value from the signal emission: %TRUE
11130  *   if the actor handled the event, or %FALSE if the event was
11131  *   not handled
11132  *
11133  * Since: 0.6
11134  */
11135 gboolean
11136 clutter_actor_event (ClutterActor *actor,
11137                      ClutterEvent *event,
11138                      gboolean      capture)
11139 {
11140   gboolean retval = FALSE;
11141   gint signal_num = -1;
11142
11143   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11144   g_return_val_if_fail (event != NULL, FALSE);
11145
11146   g_object_ref (actor);
11147
11148   if (capture)
11149     {
11150       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11151                      event,
11152                      &retval);
11153       goto out;
11154     }
11155
11156   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11157
11158   if (!retval)
11159     {
11160       switch (event->type)
11161         {
11162         case CLUTTER_NOTHING:
11163           break;
11164         case CLUTTER_BUTTON_PRESS:
11165           signal_num = BUTTON_PRESS_EVENT;
11166           break;
11167         case CLUTTER_BUTTON_RELEASE:
11168           signal_num = BUTTON_RELEASE_EVENT;
11169           break;
11170         case CLUTTER_SCROLL:
11171           signal_num = SCROLL_EVENT;
11172           break;
11173         case CLUTTER_KEY_PRESS:
11174           signal_num = KEY_PRESS_EVENT;
11175           break;
11176         case CLUTTER_KEY_RELEASE:
11177           signal_num = KEY_RELEASE_EVENT;
11178           break;
11179         case CLUTTER_MOTION:
11180           signal_num = MOTION_EVENT;
11181           break;
11182         case CLUTTER_ENTER:
11183           signal_num = ENTER_EVENT;
11184           break;
11185         case CLUTTER_LEAVE:
11186           signal_num = LEAVE_EVENT;
11187           break;
11188         case CLUTTER_DELETE:
11189         case CLUTTER_DESTROY_NOTIFY:
11190         case CLUTTER_CLIENT_MESSAGE:
11191         default:
11192           signal_num = -1;
11193           break;
11194         }
11195
11196       if (signal_num != -1)
11197         g_signal_emit (actor, actor_signals[signal_num], 0,
11198                        event, &retval);
11199     }
11200
11201 out:
11202   g_object_unref (actor);
11203
11204   return retval;
11205 }
11206
11207 /**
11208  * clutter_actor_set_reactive:
11209  * @actor: a #ClutterActor
11210  * @reactive: whether the actor should be reactive to events
11211  *
11212  * Sets @actor as reactive. Reactive actors will receive events.
11213  *
11214  * Since: 0.6
11215  */
11216 void
11217 clutter_actor_set_reactive (ClutterActor *actor,
11218                             gboolean      reactive)
11219 {
11220   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11221
11222   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11223     return;
11224
11225   if (reactive)
11226     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11227   else
11228     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11229
11230   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11231 }
11232
11233 /**
11234  * clutter_actor_get_reactive:
11235  * @actor: a #ClutterActor
11236  *
11237  * Checks whether @actor is marked as reactive.
11238  *
11239  * Return value: %TRUE if the actor is reactive
11240  *
11241  * Since: 0.6
11242  */
11243 gboolean
11244 clutter_actor_get_reactive (ClutterActor *actor)
11245 {
11246   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11247
11248   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11249 }
11250
11251 /**
11252  * clutter_actor_get_anchor_point:
11253  * @self: a #ClutterActor
11254  * @anchor_x: (out): return location for the X coordinate of the anchor point
11255  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11256  *
11257  * Gets the current anchor point of the @actor in pixels.
11258  *
11259  * Since: 0.6
11260  */
11261 void
11262 clutter_actor_get_anchor_point (ClutterActor *self,
11263                                 gfloat       *anchor_x,
11264                                 gfloat       *anchor_y)
11265 {
11266   const ClutterTransformInfo *info;
11267
11268   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11269
11270   info = _clutter_actor_get_transform_info_or_defaults (self);
11271   clutter_anchor_coord_get_units (self, &info->anchor,
11272                                   anchor_x,
11273                                   anchor_y,
11274                                   NULL);
11275 }
11276
11277 /**
11278  * clutter_actor_set_anchor_point:
11279  * @self: a #ClutterActor
11280  * @anchor_x: X coordinate of the anchor point
11281  * @anchor_y: Y coordinate of the anchor point
11282  *
11283  * Sets an anchor point for @self. The anchor point is a point in the
11284  * coordinate space of an actor to which the actor position within its
11285  * parent is relative; the default is (0, 0), i.e. the top-left corner
11286  * of the actor.
11287  *
11288  * Since: 0.6
11289  */
11290 void
11291 clutter_actor_set_anchor_point (ClutterActor *self,
11292                                 gfloat        anchor_x,
11293                                 gfloat        anchor_y)
11294 {
11295   ClutterTransformInfo *info;
11296   ClutterActorPrivate *priv;
11297   gboolean changed = FALSE;
11298   gfloat old_anchor_x, old_anchor_y;
11299   GObject *obj;
11300
11301   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11302
11303   obj = G_OBJECT (self);
11304   priv = self->priv;
11305   info = _clutter_actor_get_transform_info (self);
11306
11307   g_object_freeze_notify (obj);
11308
11309   clutter_anchor_coord_get_units (self, &info->anchor,
11310                                   &old_anchor_x,
11311                                   &old_anchor_y,
11312                                   NULL);
11313
11314   if (info->anchor.is_fractional)
11315     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11316
11317   if (old_anchor_x != anchor_x)
11318     {
11319       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11320       changed = TRUE;
11321     }
11322
11323   if (old_anchor_y != anchor_y)
11324     {
11325       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11326       changed = TRUE;
11327     }
11328
11329   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11330
11331   if (changed)
11332     {
11333       priv->transform_valid = FALSE;
11334       clutter_actor_queue_redraw (self);
11335     }
11336
11337   g_object_thaw_notify (obj);
11338 }
11339
11340 /**
11341  * clutter_actor_get_anchor_point_gravity:
11342  * @self: a #ClutterActor
11343  *
11344  * Retrieves the anchor position expressed as a #ClutterGravity. If
11345  * the anchor point was specified using pixels or units this will
11346  * return %CLUTTER_GRAVITY_NONE.
11347  *
11348  * Return value: the #ClutterGravity used by the anchor point
11349  *
11350  * Since: 1.0
11351  */
11352 ClutterGravity
11353 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11354 {
11355   const ClutterTransformInfo *info;
11356
11357   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11358
11359   info = _clutter_actor_get_transform_info_or_defaults (self);
11360
11361   return clutter_anchor_coord_get_gravity (&info->anchor);
11362 }
11363
11364 /**
11365  * clutter_actor_move_anchor_point:
11366  * @self: a #ClutterActor
11367  * @anchor_x: X coordinate of the anchor point
11368  * @anchor_y: Y coordinate of the anchor point
11369  *
11370  * Sets an anchor point for the actor, and adjusts the actor postion so that
11371  * the relative position of the actor toward its parent remains the same.
11372  *
11373  * Since: 0.6
11374  */
11375 void
11376 clutter_actor_move_anchor_point (ClutterActor *self,
11377                                  gfloat        anchor_x,
11378                                  gfloat        anchor_y)
11379 {
11380   gfloat old_anchor_x, old_anchor_y;
11381   const ClutterTransformInfo *info;
11382
11383   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11384
11385   info = _clutter_actor_get_transform_info (self);
11386   clutter_anchor_coord_get_units (self, &info->anchor,
11387                                   &old_anchor_x,
11388                                   &old_anchor_y,
11389                                   NULL);
11390
11391   g_object_freeze_notify (G_OBJECT (self));
11392
11393   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11394
11395   if (self->priv->position_set)
11396     clutter_actor_move_by (self,
11397                            anchor_x - old_anchor_x,
11398                            anchor_y - old_anchor_y);
11399
11400   g_object_thaw_notify (G_OBJECT (self));
11401 }
11402
11403 /**
11404  * clutter_actor_move_anchor_point_from_gravity:
11405  * @self: a #ClutterActor
11406  * @gravity: #ClutterGravity.
11407  *
11408  * Sets an anchor point on the actor based on the given gravity, adjusting the
11409  * actor postion so that its relative position within its parent remains
11410  * unchanged.
11411  *
11412  * Since version 1.0 the anchor point will be stored as a gravity so
11413  * that if the actor changes size then the anchor point will move. For
11414  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11415  * and later double the size of the actor, the anchor point will move
11416  * to the bottom right.
11417  *
11418  * Since: 0.6
11419  */
11420 void
11421 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11422                                               ClutterGravity  gravity)
11423 {
11424   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11425   const ClutterTransformInfo *info;
11426   ClutterActorPrivate *priv;
11427
11428   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11429
11430   priv = self->priv;
11431   info = _clutter_actor_get_transform_info (self);
11432
11433   g_object_freeze_notify (G_OBJECT (self));
11434
11435   clutter_anchor_coord_get_units (self, &info->anchor,
11436                                   &old_anchor_x,
11437                                   &old_anchor_y,
11438                                   NULL);
11439   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11440   clutter_anchor_coord_get_units (self, &info->anchor,
11441                                   &new_anchor_x,
11442                                   &new_anchor_y,
11443                                   NULL);
11444
11445   if (priv->position_set)
11446     clutter_actor_move_by (self,
11447                            new_anchor_x - old_anchor_x,
11448                            new_anchor_y - old_anchor_y);
11449
11450   g_object_thaw_notify (G_OBJECT (self));
11451 }
11452
11453 /**
11454  * clutter_actor_set_anchor_point_from_gravity:
11455  * @self: a #ClutterActor
11456  * @gravity: #ClutterGravity.
11457  *
11458  * Sets an anchor point on the actor, based on the given gravity (this is a
11459  * convenience function wrapping clutter_actor_set_anchor_point()).
11460  *
11461  * Since version 1.0 the anchor point will be stored as a gravity so
11462  * that if the actor changes size then the anchor point will move. For
11463  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11464  * and later double the size of the actor, the anchor point will move
11465  * to the bottom right.
11466  *
11467  * Since: 0.6
11468  */
11469 void
11470 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11471                                              ClutterGravity  gravity)
11472 {
11473   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11474
11475   if (gravity == CLUTTER_GRAVITY_NONE)
11476     clutter_actor_set_anchor_point (self, 0, 0);
11477   else
11478     {
11479       GObject *obj = G_OBJECT (self);
11480       ClutterTransformInfo *info;
11481
11482       g_object_freeze_notify (obj);
11483
11484       info = _clutter_actor_get_transform_info (self);
11485       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11486
11487       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11488       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11489       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11490
11491       self->priv->transform_valid = FALSE;
11492
11493       clutter_actor_queue_redraw (self);
11494
11495       g_object_thaw_notify (obj);
11496     }
11497 }
11498
11499 static void
11500 clutter_container_iface_init (ClutterContainerIface *iface)
11501 {
11502   /* we don't override anything, as ClutterContainer already has a default
11503    * implementation that we can use, and which calls into our own API.
11504    */
11505 }
11506
11507 typedef enum
11508 {
11509   PARSE_X,
11510   PARSE_Y,
11511   PARSE_WIDTH,
11512   PARSE_HEIGHT,
11513   PARSE_ANCHOR_X,
11514   PARSE_ANCHOR_Y
11515 } ParseDimension;
11516
11517 static gfloat
11518 parse_units (ClutterActor   *self,
11519              ParseDimension  dimension,
11520              JsonNode       *node)
11521 {
11522   GValue value = { 0, };
11523   gfloat retval = 0;
11524
11525   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11526     return 0;
11527
11528   json_node_get_value (node, &value);
11529
11530   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11531     {
11532       retval = (gfloat) g_value_get_int64 (&value);
11533     }
11534   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
11535     {
11536       retval = g_value_get_double (&value);
11537     }
11538   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
11539     {
11540       ClutterUnits units;
11541       gboolean res;
11542
11543       res = clutter_units_from_string (&units, g_value_get_string (&value));
11544       if (res)
11545         retval = clutter_units_to_pixels (&units);
11546       else
11547         {
11548           g_warning ("Invalid value '%s': integers, strings or floating point "
11549                      "values can be used for the x, y, width and height "
11550                      "properties. Valid modifiers for strings are 'px', 'mm', "
11551                      "'pt' and 'em'.",
11552                      g_value_get_string (&value));
11553           retval = 0;
11554         }
11555     }
11556   else
11557     {
11558       g_warning ("Invalid value of type '%s': integers, strings of floating "
11559                  "point values can be used for the x, y, width, height "
11560                  "anchor-x and anchor-y properties.",
11561                  g_type_name (G_VALUE_TYPE (&value)));
11562     }
11563
11564   g_value_unset (&value);
11565
11566   return retval;
11567 }
11568
11569 typedef struct {
11570   ClutterRotateAxis axis;
11571
11572   gdouble angle;
11573
11574   gfloat center_x;
11575   gfloat center_y;
11576   gfloat center_z;
11577 } RotationInfo;
11578
11579 static inline gboolean
11580 parse_rotation_array (ClutterActor *actor,
11581                       JsonArray    *array,
11582                       RotationInfo *info)
11583 {
11584   JsonNode *element;
11585
11586   if (json_array_get_length (array) != 2)
11587     return FALSE;
11588
11589   /* angle */
11590   element = json_array_get_element (array, 0);
11591   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
11592     info->angle = json_node_get_double (element);
11593   else
11594     return FALSE;
11595
11596   /* center */
11597   element = json_array_get_element (array, 1);
11598   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
11599     {
11600       JsonArray *center = json_node_get_array (element);
11601
11602       if (json_array_get_length (center) != 2)
11603         return FALSE;
11604
11605       switch (info->axis)
11606         {
11607         case CLUTTER_X_AXIS:
11608           info->center_y = parse_units (actor, PARSE_Y,
11609                                         json_array_get_element (center, 0));
11610           info->center_z = parse_units (actor, PARSE_Y,
11611                                         json_array_get_element (center, 1));
11612           return TRUE;
11613
11614         case CLUTTER_Y_AXIS:
11615           info->center_x = parse_units (actor, PARSE_X,
11616                                         json_array_get_element (center, 0));
11617           info->center_z = parse_units (actor, PARSE_X,
11618                                         json_array_get_element (center, 1));
11619           return TRUE;
11620
11621         case CLUTTER_Z_AXIS:
11622           info->center_x = parse_units (actor, PARSE_X,
11623                                         json_array_get_element (center, 0));
11624           info->center_y = parse_units (actor, PARSE_Y,
11625                                         json_array_get_element (center, 1));
11626           return TRUE;
11627         }
11628     }
11629
11630   return FALSE;
11631 }
11632
11633 static gboolean
11634 parse_rotation (ClutterActor *actor,
11635                 JsonNode     *node,
11636                 RotationInfo *info)
11637 {
11638   JsonArray *array;
11639   guint len, i;
11640   gboolean retval = FALSE;
11641
11642   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
11643     {
11644       g_warning ("Invalid node of type '%s' found, expecting an array",
11645                  json_node_type_name (node));
11646       return FALSE;
11647     }
11648
11649   array = json_node_get_array (node);
11650   len = json_array_get_length (array);
11651
11652   for (i = 0; i < len; i++)
11653     {
11654       JsonNode *element = json_array_get_element (array, i);
11655       JsonObject *object;
11656       JsonNode *member;
11657
11658       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
11659         {
11660           g_warning ("Invalid node of type '%s' found, expecting an object",
11661                      json_node_type_name (element));
11662           return FALSE;
11663         }
11664
11665       object = json_node_get_object (element);
11666
11667       if (json_object_has_member (object, "x-axis"))
11668         {
11669           member = json_object_get_member (object, "x-axis");
11670
11671           info->axis = CLUTTER_X_AXIS;
11672
11673           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11674             {
11675               info->angle = json_node_get_double (member);
11676               retval = TRUE;
11677             }
11678           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11679             retval = parse_rotation_array (actor,
11680                                            json_node_get_array (member),
11681                                            info);
11682           else
11683             retval = FALSE;
11684         }
11685       else if (json_object_has_member (object, "y-axis"))
11686         {
11687           member = json_object_get_member (object, "y-axis");
11688
11689           info->axis = CLUTTER_Y_AXIS;
11690
11691           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11692             {
11693               info->angle = json_node_get_double (member);
11694               retval = TRUE;
11695             }
11696           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11697             retval = parse_rotation_array (actor,
11698                                            json_node_get_array (member),
11699                                            info);
11700           else
11701             retval = FALSE;
11702         }
11703       else if (json_object_has_member (object, "z-axis"))
11704         {
11705           member = json_object_get_member (object, "z-axis");
11706
11707           info->axis = CLUTTER_Z_AXIS;
11708
11709           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11710             {
11711               info->angle = json_node_get_double (member);
11712               retval = TRUE;
11713             }
11714           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11715             retval = parse_rotation_array (actor,
11716                                            json_node_get_array (member),
11717                                            info);
11718           else
11719             retval = FALSE;
11720         }
11721     }
11722
11723   return retval;
11724 }
11725
11726 static GSList *
11727 parse_actor_metas (ClutterScript *script,
11728                    ClutterActor  *actor,
11729                    JsonNode      *node)
11730 {
11731   GList *elements, *l;
11732   GSList *retval = NULL;
11733
11734   if (!JSON_NODE_HOLDS_ARRAY (node))
11735     return NULL;
11736
11737   elements = json_array_get_elements (json_node_get_array (node));
11738
11739   for (l = elements; l != NULL; l = l->next)
11740     {
11741       JsonNode *element = l->data;
11742       const gchar *id_ = _clutter_script_get_id_from_node (element);
11743       GObject *meta;
11744
11745       if (id_ == NULL || *id_ == '\0')
11746         continue;
11747
11748       meta = clutter_script_get_object (script, id_);
11749       if (meta == NULL)
11750         continue;
11751
11752       retval = g_slist_prepend (retval, meta);
11753     }
11754
11755   g_list_free (elements);
11756
11757   return g_slist_reverse (retval);
11758 }
11759
11760 static GSList *
11761 parse_behaviours (ClutterScript *script,
11762                   ClutterActor  *actor,
11763                   JsonNode      *node)
11764 {
11765   GList *elements, *l;
11766   GSList *retval = NULL;
11767
11768   if (!JSON_NODE_HOLDS_ARRAY (node))
11769     return NULL;
11770
11771   elements = json_array_get_elements (json_node_get_array (node));
11772
11773   for (l = elements; l != NULL; l = l->next)
11774     {
11775       JsonNode *element = l->data;
11776       const gchar *id_ = _clutter_script_get_id_from_node (element);
11777       GObject *behaviour;
11778
11779       if (id_ == NULL || *id_ == '\0')
11780         continue;
11781
11782       behaviour = clutter_script_get_object (script, id_);
11783       if (behaviour == NULL)
11784         continue;
11785
11786       retval = g_slist_prepend (retval, behaviour);
11787     }
11788
11789   g_list_free (elements);
11790
11791   return g_slist_reverse (retval);
11792 }
11793
11794 static gboolean
11795 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
11796                                  ClutterScript     *script,
11797                                  GValue            *value,
11798                                  const gchar       *name,
11799                                  JsonNode          *node)
11800 {
11801   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11802   gboolean retval = FALSE;
11803
11804   if ((name[0] == 'x' && name[1] == '\0') ||
11805       (name[0] == 'y' && name[1] == '\0') ||
11806       (strcmp (name, "width") == 0) ||
11807       (strcmp (name, "height") == 0) ||
11808       (strcmp (name, "anchor_x") == 0) ||
11809       (strcmp (name, "anchor_y") == 0))
11810     {
11811       ParseDimension dimension;
11812       gfloat units;
11813
11814       if (name[0] == 'x')
11815         dimension = PARSE_X;
11816       else if (name[0] == 'y')
11817         dimension = PARSE_Y;
11818       else if (name[0] == 'w')
11819         dimension = PARSE_WIDTH;
11820       else if (name[0] == 'h')
11821         dimension = PARSE_HEIGHT;
11822       else if (name[0] == 'a' && name[7] == 'x')
11823         dimension = PARSE_ANCHOR_X;
11824       else if (name[0] == 'a' && name[7] == 'y')
11825         dimension = PARSE_ANCHOR_Y;
11826       else
11827         return FALSE;
11828
11829       units = parse_units (actor, dimension, node);
11830
11831       /* convert back to pixels: all properties are pixel-based */
11832       g_value_init (value, G_TYPE_FLOAT);
11833       g_value_set_float (value, units);
11834
11835       retval = TRUE;
11836     }
11837   else if (strcmp (name, "rotation") == 0)
11838     {
11839       RotationInfo *info;
11840
11841       info = g_slice_new0 (RotationInfo);
11842       retval = parse_rotation (actor, node, info);
11843
11844       if (retval)
11845         {
11846           g_value_init (value, G_TYPE_POINTER);
11847           g_value_set_pointer (value, info);
11848         }
11849       else
11850         g_slice_free (RotationInfo, info);
11851     }
11852   else if (strcmp (name, "behaviours") == 0)
11853     {
11854       GSList *l;
11855
11856 #ifdef CLUTTER_ENABLE_DEBUG
11857       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
11858         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
11859                                      "and it should not be used in newly "
11860                                      "written ClutterScript definitions.");
11861 #endif
11862
11863       l = parse_behaviours (script, actor, node);
11864
11865       g_value_init (value, G_TYPE_POINTER);
11866       g_value_set_pointer (value, l);
11867
11868       retval = TRUE;
11869     }
11870   else if (strcmp (name, "actions") == 0 ||
11871            strcmp (name, "constraints") == 0 ||
11872            strcmp (name, "effects") == 0)
11873     {
11874       GSList *l;
11875
11876       l = parse_actor_metas (script, actor, node);
11877
11878       g_value_init (value, G_TYPE_POINTER);
11879       g_value_set_pointer (value, l);
11880
11881       retval = TRUE;
11882     }
11883
11884   return retval;
11885 }
11886
11887 static void
11888 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
11889                                    ClutterScript     *script,
11890                                    const gchar       *name,
11891                                    const GValue      *value)
11892 {
11893   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11894
11895 #ifdef CLUTTER_ENABLE_DEBUG
11896   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
11897     {
11898       gchar *tmp = g_strdup_value_contents (value);
11899
11900       CLUTTER_NOTE (SCRIPT,
11901                     "in ClutterActor::set_custom_property('%s') = %s",
11902                     name,
11903                     tmp);
11904
11905       g_free (tmp);
11906     }
11907 #endif /* CLUTTER_ENABLE_DEBUG */
11908
11909   if (strcmp (name, "rotation") == 0)
11910     {
11911       RotationInfo *info;
11912
11913       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11914         return;
11915
11916       info = g_value_get_pointer (value);
11917
11918       clutter_actor_set_rotation (actor,
11919                                   info->axis, info->angle,
11920                                   info->center_x,
11921                                   info->center_y,
11922                                   info->center_z);
11923
11924       g_slice_free (RotationInfo, info);
11925
11926       return;
11927     }
11928
11929   if (strcmp (name, "behaviours") == 0)
11930     {
11931       GSList *behaviours, *l;
11932
11933       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11934         return;
11935
11936       behaviours = g_value_get_pointer (value);
11937       for (l = behaviours; l != NULL; l = l->next)
11938         {
11939           ClutterBehaviour *behaviour = l->data;
11940
11941           clutter_behaviour_apply (behaviour, actor);
11942         }
11943
11944       g_slist_free (behaviours);
11945
11946       return;
11947     }
11948
11949   if (strcmp (name, "actions") == 0 ||
11950       strcmp (name, "constraints") == 0 ||
11951       strcmp (name, "effects") == 0)
11952     {
11953       GSList *metas, *l;
11954
11955       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11956         return;
11957
11958       metas = g_value_get_pointer (value);
11959       for (l = metas; l != NULL; l = l->next)
11960         {
11961           if (name[0] == 'a')
11962             clutter_actor_add_action (actor, l->data);
11963
11964           if (name[0] == 'c')
11965             clutter_actor_add_constraint (actor, l->data);
11966
11967           if (name[0] == 'e')
11968             clutter_actor_add_effect (actor, l->data);
11969         }
11970
11971       g_slist_free (metas);
11972
11973       return;
11974     }
11975
11976   g_object_set_property (G_OBJECT (scriptable), name, value);
11977 }
11978
11979 static void
11980 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
11981 {
11982   iface->parse_custom_node = clutter_actor_parse_custom_node;
11983   iface->set_custom_property = clutter_actor_set_custom_property;
11984 }
11985
11986 static ClutterActorMeta *
11987 get_meta_from_animation_property (ClutterActor  *actor,
11988                                   const gchar   *name,
11989                                   gchar        **name_p)
11990 {
11991   ClutterActorPrivate *priv = actor->priv;
11992   ClutterActorMeta *meta = NULL;
11993   gchar **tokens;
11994
11995   /* if this is not a special property, fall through */
11996   if (name[0] != '@')
11997     return NULL;
11998
11999   /* detect the properties named using the following spec:
12000    *
12001    *   @<section>.<meta-name>.<property-name>
12002    *
12003    * where <section> can be one of the following:
12004    *
12005    *   - actions
12006    *   - constraints
12007    *   - effects
12008    *
12009    * and <meta-name> is the name set on a specific ActorMeta
12010    */
12011
12012   tokens = g_strsplit (name + 1, ".", -1);
12013   if (tokens == NULL || g_strv_length (tokens) != 3)
12014     {
12015       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12016                     name + 1);
12017       g_strfreev (tokens);
12018       return NULL;
12019     }
12020
12021   if (strcmp (tokens[0], "actions") == 0)
12022     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12023
12024   if (strcmp (tokens[0], "constraints") == 0)
12025     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12026
12027   if (strcmp (tokens[0], "effects") == 0)
12028     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12029
12030   if (name_p != NULL)
12031     *name_p = g_strdup (tokens[2]);
12032
12033   CLUTTER_NOTE (ANIMATION,
12034                 "Looking for property '%s' of object '%s' in section '%s'",
12035                 tokens[2],
12036                 tokens[1],
12037                 tokens[0]);
12038
12039   g_strfreev (tokens);
12040
12041   return meta;
12042 }
12043
12044 static GParamSpec *
12045 clutter_actor_find_property (ClutterAnimatable *animatable,
12046                              const gchar       *property_name)
12047 {
12048   ClutterActorMeta *meta = NULL;
12049   GObjectClass *klass = NULL;
12050   GParamSpec *pspec = NULL;
12051   gchar *p_name = NULL;
12052
12053   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12054                                            property_name,
12055                                            &p_name);
12056
12057   if (meta != NULL)
12058     {
12059       klass = G_OBJECT_GET_CLASS (meta);
12060
12061       pspec = g_object_class_find_property (klass, p_name);
12062     }
12063   else
12064     {
12065       klass = G_OBJECT_GET_CLASS (animatable);
12066
12067       pspec = g_object_class_find_property (klass, property_name);
12068     }
12069
12070   g_free (p_name);
12071
12072   return pspec;
12073 }
12074
12075 static void
12076 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12077                                  const gchar       *property_name,
12078                                  GValue            *initial)
12079 {
12080   ClutterActorMeta *meta = NULL;
12081   gchar *p_name = NULL;
12082
12083   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12084                                            property_name,
12085                                            &p_name);
12086
12087   if (meta != NULL)
12088     g_object_get_property (G_OBJECT (meta), p_name, initial);
12089   else
12090     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12091
12092   g_free (p_name);
12093 }
12094
12095 static void
12096 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12097                                const gchar       *property_name,
12098                                const GValue      *final)
12099 {
12100   ClutterActorMeta *meta = NULL;
12101   gchar *p_name = NULL;
12102
12103   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12104                                            property_name,
12105                                            &p_name);
12106   if (meta != NULL)
12107     g_object_set_property (G_OBJECT (meta), p_name, final);
12108   else
12109     g_object_set_property (G_OBJECT (animatable), property_name, final);
12110
12111   g_free (p_name);
12112 }
12113
12114 static void
12115 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12116 {
12117   iface->find_property = clutter_actor_find_property;
12118   iface->get_initial_state = clutter_actor_get_initial_state;
12119   iface->set_final_state = clutter_actor_set_final_state;
12120 }
12121
12122 /**
12123  * clutter_actor_transform_stage_point:
12124  * @self: A #ClutterActor
12125  * @x: (in): x screen coordinate of the point to unproject
12126  * @y: (in): y screen coordinate of the point to unproject
12127  * @x_out: (out): return location for the unprojected x coordinance
12128  * @y_out: (out): return location for the unprojected y coordinance
12129  *
12130  * This function translates screen coordinates (@x, @y) to
12131  * coordinates relative to the actor. For example, it can be used to translate
12132  * screen events from global screen coordinates into actor-local coordinates.
12133  *
12134  * The conversion can fail, notably if the transform stack results in the
12135  * actor being projected on the screen as a mere line.
12136  *
12137  * The conversion should not be expected to be pixel-perfect due to the
12138  * nature of the operation. In general the error grows when the skewing
12139  * of the actor rectangle on screen increases.
12140  *
12141  * <note><para>This function can be computationally intensive.</para></note>
12142  *
12143  * <note><para>This function only works when the allocation is up-to-date,
12144  * i.e. inside of paint().</para></note>
12145  *
12146  * Return value: %TRUE if conversion was successful.
12147  *
12148  * Since: 0.6
12149  */
12150 gboolean
12151 clutter_actor_transform_stage_point (ClutterActor *self,
12152                                      gfloat        x,
12153                                      gfloat        y,
12154                                      gfloat       *x_out,
12155                                      gfloat       *y_out)
12156 {
12157   ClutterVertex v[4];
12158   float ST[3][3];
12159   float RQ[3][3];
12160   int du, dv, xi, yi;
12161   float px, py;
12162   float xf, yf, wf, det;
12163   ClutterActorPrivate *priv;
12164
12165   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12166
12167   priv = self->priv;
12168
12169   /* This implementation is based on the quad -> quad projection algorithm
12170    * described by Paul Heckbert in:
12171    *
12172    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12173    *
12174    * and the sample implementation at:
12175    *
12176    *   http://www.cs.cmu.edu/~ph/src/texfund/
12177    *
12178    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12179    * quad to rectangle only, which significantly simplifies things; the
12180    * function calls have been unrolled, and most of the math is done in fixed
12181    * point.
12182    */
12183
12184   clutter_actor_get_abs_allocation_vertices (self, v);
12185
12186   /* Keeping these as ints simplifies the multiplication (no significant
12187    * loss of precision here).
12188    */
12189   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12190   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12191
12192   if (!du || !dv)
12193     return FALSE;
12194
12195 #define UX2FP(x)        (x)
12196 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12197
12198   /* First, find mapping from unit uv square to xy quadrilateral; this
12199    * equivalent to the pmap_square_quad() functions in the sample
12200    * implementation, which we can simplify, since our target is always
12201    * a rectangle.
12202    */
12203   px = v[0].x - v[1].x + v[3].x - v[2].x;
12204   py = v[0].y - v[1].y + v[3].y - v[2].y;
12205
12206   if (!px && !py)
12207     {
12208       /* affine transform */
12209       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12210       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12211       RQ[2][0] = UX2FP (v[0].x);
12212       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12213       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12214       RQ[2][1] = UX2FP (v[0].y);
12215       RQ[0][2] = 0;
12216       RQ[1][2] = 0;
12217       RQ[2][2] = 1.0;
12218     }
12219   else
12220     {
12221       /* projective transform */
12222       double dx1, dx2, dy1, dy2, del;
12223
12224       dx1 = UX2FP (v[1].x - v[3].x);
12225       dx2 = UX2FP (v[2].x - v[3].x);
12226       dy1 = UX2FP (v[1].y - v[3].y);
12227       dy2 = UX2FP (v[2].y - v[3].y);
12228
12229       del = DET2FP (dx1, dx2, dy1, dy2);
12230       if (!del)
12231         return FALSE;
12232
12233       /*
12234        * The division here needs to be done in floating point for
12235        * precisions reasons.
12236        */
12237       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12238       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12239       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12240       RQ[2][2] = 1.0;
12241       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12242       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12243       RQ[2][0] = UX2FP (v[0].x);
12244       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12245       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12246       RQ[2][1] = UX2FP (v[0].y);
12247     }
12248
12249   /*
12250    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12251    * square. Since our rectangle is based at 0,0 we only need to scale.
12252    */
12253   RQ[0][0] /= du;
12254   RQ[1][0] /= dv;
12255   RQ[0][1] /= du;
12256   RQ[1][1] /= dv;
12257   RQ[0][2] /= du;
12258   RQ[1][2] /= dv;
12259
12260   /*
12261    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12262    * inverse of that.
12263    */
12264   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12265   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12266   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12267   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12268   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12269   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12270   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12271   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12272   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12273
12274   /*
12275    * Check the resulting matrix is OK.
12276    */
12277   det = (RQ[0][0] * ST[0][0])
12278       + (RQ[0][1] * ST[0][1])
12279       + (RQ[0][2] * ST[0][2]);
12280   if (!det)
12281     return FALSE;
12282
12283   /*
12284    * Now transform our point with the ST matrix; the notional w
12285    * coordinate is 1, hence the last part is simply added.
12286    */
12287   xi = (int) x;
12288   yi = (int) y;
12289
12290   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12291   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12292   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12293
12294   if (x_out)
12295     *x_out = xf / wf;
12296
12297   if (y_out)
12298     *y_out = yf / wf;
12299
12300 #undef UX2FP
12301 #undef DET2FP
12302
12303   return TRUE;
12304 }
12305
12306 /*
12307  * ClutterGeometry
12308  */
12309
12310 static ClutterGeometry*
12311 clutter_geometry_copy (const ClutterGeometry *geometry)
12312 {
12313   return g_slice_dup (ClutterGeometry, geometry);
12314 }
12315
12316 static void
12317 clutter_geometry_free (ClutterGeometry *geometry)
12318 {
12319   if (G_LIKELY (geometry != NULL))
12320     g_slice_free (ClutterGeometry, geometry);
12321 }
12322
12323 /**
12324  * clutter_geometry_union:
12325  * @geometry_a: a #ClutterGeometry
12326  * @geometry_b: another #ClutterGeometry
12327  * @result: (out): location to store the result
12328  *
12329  * Find the union of two rectangles represented as #ClutterGeometry.
12330  *
12331  * Since: 1.4
12332  */
12333 void
12334 clutter_geometry_union (const ClutterGeometry *geometry_a,
12335                         const ClutterGeometry *geometry_b,
12336                         ClutterGeometry       *result)
12337 {
12338   /* We don't try to handle rectangles that can't be represented
12339    * as a signed integer box */
12340   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12341   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12342   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12343                   geometry_b->x + (gint)geometry_b->width);
12344   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12345                   geometry_b->y + (gint)geometry_b->height);
12346   result->x = x_1;
12347   result->y = y_1;
12348   result->width = x_2 - x_1;
12349   result->height = y_2 - y_1;
12350 }
12351
12352 /**
12353  * clutter_geometry_intersects:
12354  * @geometry0: The first geometry to test
12355  * @geometry1: The second geometry to test
12356  *
12357  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12358  * they do else %FALSE.
12359  *
12360  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12361  * %FALSE.
12362  *
12363  * Since: 1.4
12364  */
12365 gboolean
12366 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12367                              const ClutterGeometry *geometry1)
12368 {
12369   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12370       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12371       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12372       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12373     return FALSE;
12374   else
12375     return TRUE;
12376 }
12377
12378 static gboolean
12379 clutter_geometry_progress (const GValue *a,
12380                            const GValue *b,
12381                            gdouble       progress,
12382                            GValue       *retval)
12383 {
12384   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12385   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12386   ClutterGeometry res = { 0, };
12387   gint a_width = a_geom->width;
12388   gint b_width = b_geom->width;
12389   gint a_height = a_geom->height;
12390   gint b_height = b_geom->height;
12391
12392   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12393   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12394
12395   res.width = a_width + (b_width - a_width) * progress;
12396   res.height = a_height + (b_height - a_height) * progress;
12397
12398   g_value_set_boxed (retval, &res);
12399
12400   return TRUE;
12401 }
12402
12403 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12404                                clutter_geometry_copy,
12405                                clutter_geometry_free,
12406                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12407
12408 /*
12409  * ClutterVertices
12410  */
12411
12412 /**
12413  * clutter_vertex_new:
12414  * @x: X coordinate
12415  * @y: Y coordinate
12416  * @z: Z coordinate
12417  *
12418  * Creates a new #ClutterVertex for the point in 3D space
12419  * identified by the 3 coordinates @x, @y, @z
12420  *
12421  * Return value: the newly allocate #ClutterVertex. Use
12422  *   clutter_vertex_free() to free the resources
12423  *
12424  * Since: 1.0
12425  */
12426 ClutterVertex *
12427 clutter_vertex_new (gfloat x,
12428                     gfloat y,
12429                     gfloat z)
12430 {
12431   ClutterVertex *vertex;
12432
12433   vertex = g_slice_new (ClutterVertex);
12434   vertex->x = x;
12435   vertex->y = y;
12436   vertex->z = z;
12437
12438   return vertex;
12439 }
12440
12441 /**
12442  * clutter_vertex_copy:
12443  * @vertex: a #ClutterVertex
12444  *
12445  * Copies @vertex
12446  *
12447  * Return value: a newly allocated copy of #ClutterVertex. Use
12448  *   clutter_vertex_free() to free the allocated resources
12449  *
12450  * Since: 1.0
12451  */
12452 ClutterVertex *
12453 clutter_vertex_copy (const ClutterVertex *vertex)
12454 {
12455   if (G_LIKELY (vertex != NULL))
12456     return g_slice_dup (ClutterVertex, vertex);
12457
12458   return NULL;
12459 }
12460
12461 /**
12462  * clutter_vertex_free:
12463  * @vertex: a #ClutterVertex
12464  *
12465  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
12466  *
12467  * Since: 1.0
12468  */
12469 void
12470 clutter_vertex_free (ClutterVertex *vertex)
12471 {
12472   if (G_UNLIKELY (vertex != NULL))
12473     g_slice_free (ClutterVertex, vertex);
12474 }
12475
12476 /**
12477  * clutter_vertex_equal:
12478  * @vertex_a: a #ClutterVertex
12479  * @vertex_b: a #ClutterVertex
12480  *
12481  * Compares @vertex_a and @vertex_b for equality
12482  *
12483  * Return value: %TRUE if the passed #ClutterVertex are equal
12484  *
12485  * Since: 1.0
12486  */
12487 gboolean
12488 clutter_vertex_equal (const ClutterVertex *vertex_a,
12489                       const ClutterVertex *vertex_b)
12490 {
12491   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
12492
12493   if (vertex_a == vertex_b)
12494     return TRUE;
12495
12496   return vertex_a->x == vertex_b->x &&
12497          vertex_a->y == vertex_b->y &&
12498          vertex_a->z == vertex_b->z;
12499 }
12500
12501 static gboolean
12502 clutter_vertex_progress (const GValue *a,
12503                          const GValue *b,
12504                          gdouble       progress,
12505                          GValue       *retval)
12506 {
12507   const ClutterVertex *av = g_value_get_boxed (a);
12508   const ClutterVertex *bv = g_value_get_boxed (b);
12509   ClutterVertex res = { 0, };
12510
12511   res.x = av->x + (bv->x - av->x) * progress;
12512   res.y = av->y + (bv->y - av->y) * progress;
12513   res.z = av->z + (bv->z - av->z) * progress;
12514
12515   g_value_set_boxed (retval, &res);
12516
12517   return TRUE;
12518 }
12519
12520 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
12521                                clutter_vertex_copy,
12522                                clutter_vertex_free,
12523                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
12524
12525 /**
12526  * clutter_actor_is_rotated:
12527  * @self: a #ClutterActor
12528  *
12529  * Checks whether any rotation is applied to the actor.
12530  *
12531  * Return value: %TRUE if the actor is rotated.
12532  *
12533  * Since: 0.6
12534  */
12535 gboolean
12536 clutter_actor_is_rotated (ClutterActor *self)
12537 {
12538   const ClutterTransformInfo *info;
12539
12540   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12541
12542   info = _clutter_actor_get_transform_info_or_defaults (self);
12543
12544   if (info->rx_angle || info->ry_angle || info->rz_angle)
12545     return TRUE;
12546
12547   return FALSE;
12548 }
12549
12550 /**
12551  * clutter_actor_is_scaled:
12552  * @self: a #ClutterActor
12553  *
12554  * Checks whether the actor is scaled in either dimension.
12555  *
12556  * Return value: %TRUE if the actor is scaled.
12557  *
12558  * Since: 0.6
12559  */
12560 gboolean
12561 clutter_actor_is_scaled (ClutterActor *self)
12562 {
12563   const ClutterTransformInfo *info;
12564
12565   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12566
12567   info = _clutter_actor_get_transform_info_or_defaults (self);
12568
12569   if (info->scale_x != 1.0 || info->scale_y != 1.0)
12570     return TRUE;
12571
12572   return FALSE;
12573 }
12574
12575 ClutterActor *
12576 _clutter_actor_get_stage_internal (ClutterActor *actor)
12577 {
12578   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
12579     actor = actor->priv->parent;
12580
12581   return actor;
12582 }
12583
12584 /**
12585  * clutter_actor_get_stage:
12586  * @actor: a #ClutterActor
12587  *
12588  * Retrieves the #ClutterStage where @actor is contained.
12589  *
12590  * Return value: (transfer none) (type Clutter.Stage): the stage
12591  *   containing the actor, or %NULL
12592  *
12593  * Since: 0.8
12594  */
12595 ClutterActor *
12596 clutter_actor_get_stage (ClutterActor *actor)
12597 {
12598   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
12599
12600   return _clutter_actor_get_stage_internal (actor);
12601 }
12602
12603 /**
12604  * clutter_actor_allocate_available_size:
12605  * @self: a #ClutterActor
12606  * @x: the actor's X coordinate
12607  * @y: the actor's Y coordinate
12608  * @available_width: the maximum available width, or -1 to use the
12609  *   actor's natural width
12610  * @available_height: the maximum available height, or -1 to use the
12611  *   actor's natural height
12612  * @flags: flags controlling the allocation
12613  *
12614  * Allocates @self taking into account the #ClutterActor<!-- -->'s
12615  * preferred size, but limiting it to the maximum available width
12616  * and height provided.
12617  *
12618  * This function will do the right thing when dealing with the
12619  * actor's request mode.
12620  *
12621  * The implementation of this function is equivalent to:
12622  *
12623  * |[
12624  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12625  *     {
12626  *       clutter_actor_get_preferred_width (self, available_height,
12627  *                                          &amp;min_width,
12628  *                                          &amp;natural_width);
12629  *       width = CLAMP (natural_width, min_width, available_width);
12630  *
12631  *       clutter_actor_get_preferred_height (self, width,
12632  *                                           &amp;min_height,
12633  *                                           &amp;natural_height);
12634  *       height = CLAMP (natural_height, min_height, available_height);
12635  *     }
12636  *   else
12637  *     {
12638  *       clutter_actor_get_preferred_height (self, available_width,
12639  *                                           &amp;min_height,
12640  *                                           &amp;natural_height);
12641  *       height = CLAMP (natural_height, min_height, available_height);
12642  *
12643  *       clutter_actor_get_preferred_width (self, height,
12644  *                                          &amp;min_width,
12645  *                                          &amp;natural_width);
12646  *       width = CLAMP (natural_width, min_width, available_width);
12647  *     }
12648  *
12649  *   box.x1 = x; box.y1 = y;
12650  *   box.x2 = box.x1 + available_width;
12651  *   box.y2 = box.y1 + available_height;
12652  *   clutter_actor_allocate (self, &amp;box, flags);
12653  * ]|
12654  *
12655  * This function can be used by fluid layout managers to allocate
12656  * an actor's preferred size without making it bigger than the area
12657  * available for the container.
12658  *
12659  * Since: 1.0
12660  */
12661 void
12662 clutter_actor_allocate_available_size (ClutterActor           *self,
12663                                        gfloat                  x,
12664                                        gfloat                  y,
12665                                        gfloat                  available_width,
12666                                        gfloat                  available_height,
12667                                        ClutterAllocationFlags  flags)
12668 {
12669   ClutterActorPrivate *priv;
12670   gfloat width, height;
12671   gfloat min_width, min_height;
12672   gfloat natural_width, natural_height;
12673   ClutterActorBox box;
12674
12675   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12676
12677   priv = self->priv;
12678
12679   width = height = 0.0;
12680
12681   switch (priv->request_mode)
12682     {
12683     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
12684       clutter_actor_get_preferred_width (self, available_height,
12685                                          &min_width,
12686                                          &natural_width);
12687       width  = CLAMP (natural_width, min_width, available_width);
12688
12689       clutter_actor_get_preferred_height (self, width,
12690                                           &min_height,
12691                                           &natural_height);
12692       height = CLAMP (natural_height, min_height, available_height);
12693       break;
12694
12695     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
12696       clutter_actor_get_preferred_height (self, available_width,
12697                                           &min_height,
12698                                           &natural_height);
12699       height = CLAMP (natural_height, min_height, available_height);
12700
12701       clutter_actor_get_preferred_width (self, height,
12702                                          &min_width,
12703                                          &natural_width);
12704       width  = CLAMP (natural_width, min_width, available_width);
12705       break;
12706     }
12707
12708
12709   box.x1 = x;
12710   box.y1 = y;
12711   box.x2 = box.x1 + width;
12712   box.y2 = box.y1 + height;
12713   clutter_actor_allocate (self, &box, flags);
12714 }
12715
12716 /**
12717  * clutter_actor_allocate_preferred_size:
12718  * @self: a #ClutterActor
12719  * @flags: flags controlling the allocation
12720  *
12721  * Allocates the natural size of @self.
12722  *
12723  * This function is a utility call for #ClutterActor implementations
12724  * that allocates the actor's preferred natural size. It can be used
12725  * by fixed layout managers (like #ClutterGroup or so called
12726  * 'composite actors') inside the ClutterActor::allocate
12727  * implementation to give each child exactly how much space it
12728  * requires.
12729  *
12730  * This function is not meant to be used by applications. It is also
12731  * not meant to be used outside the implementation of the
12732  * ClutterActor::allocate virtual function.
12733  *
12734  * Since: 0.8
12735  */
12736 void
12737 clutter_actor_allocate_preferred_size (ClutterActor           *self,
12738                                        ClutterAllocationFlags  flags)
12739 {
12740   gfloat actor_x, actor_y;
12741   gfloat natural_width, natural_height;
12742   ClutterActorBox actor_box;
12743
12744   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12745
12746   actor_x = clutter_actor_get_x (self);
12747   actor_y = clutter_actor_get_y (self);
12748
12749   clutter_actor_get_preferred_size (self,
12750                                     NULL, NULL,
12751                                     &natural_width,
12752                                     &natural_height);
12753
12754   actor_box.x1 = actor_x;
12755   actor_box.y1 = actor_y;
12756   actor_box.x2 = actor_box.x1 + natural_width;
12757   actor_box.y2 = actor_box.y1 + natural_height;
12758
12759   clutter_actor_allocate (self, &actor_box, flags);
12760 }
12761
12762 /**
12763  * clutter_actor_allocate_align_fill:
12764  * @self: a #ClutterActor
12765  * @box: a #ClutterActorBox, containing the available width and height
12766  * @x_align: the horizontal alignment, between 0 and 1
12767  * @y_align: the vertical alignment, between 0 and 1
12768  * @x_fill: whether the actor should fill horizontally
12769  * @y_fill: whether the actor should fill vertically
12770  * @flags: allocation flags to be passed to clutter_actor_allocate()
12771  *
12772  * Allocates @self by taking into consideration the available allocation
12773  * area; an alignment factor on either axis; and whether the actor should
12774  * fill the allocation on either axis.
12775  *
12776  * The @box should contain the available allocation width and height;
12777  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
12778  * allocation will be offset by their value.
12779  *
12780  * This function takes into consideration the geometry request specified by
12781  * the #ClutterActor:request-mode property, and the text direction.
12782  *
12783  * This function is useful for fluid layout managers, like #ClutterBinLayout
12784  * or #ClutterTableLayout
12785  *
12786  * Since: 1.4
12787  */
12788 void
12789 clutter_actor_allocate_align_fill (ClutterActor           *self,
12790                                    const ClutterActorBox  *box,
12791                                    gdouble                 x_align,
12792                                    gdouble                 y_align,
12793                                    gboolean                x_fill,
12794                                    gboolean                y_fill,
12795                                    ClutterAllocationFlags  flags)
12796 {
12797   ClutterActorPrivate *priv;
12798   ClutterActorBox allocation = { 0, };
12799   gfloat x_offset, y_offset;
12800   gfloat available_width, available_height;
12801   gfloat child_width, child_height;
12802
12803   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12804   g_return_if_fail (box != NULL);
12805   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
12806   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
12807
12808   priv = self->priv;
12809
12810   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
12811   clutter_actor_box_get_size (box, &available_width, &available_height);
12812
12813   if (available_width < 0)
12814     available_width = 0;
12815
12816   if (available_height < 0)
12817     available_height = 0;
12818
12819   if (x_fill)
12820     {
12821       allocation.x1 = x_offset;
12822       allocation.x2 = allocation.x1 + available_width;
12823     }
12824
12825   if (y_fill)
12826     {
12827       allocation.y1 = y_offset;
12828       allocation.y2 = allocation.y1 + available_height;
12829     }
12830
12831   /* if we are filling horizontally and vertically then we're done */
12832   if (x_fill && y_fill)
12833     goto out;
12834
12835   child_width = child_height = 0.0f;
12836
12837   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12838     {
12839       gfloat min_width, natural_width;
12840       gfloat min_height, natural_height;
12841
12842       clutter_actor_get_preferred_width (self, available_height,
12843                                          &min_width,
12844                                          &natural_width);
12845
12846       child_width = CLAMP (natural_width, min_width, available_width);
12847
12848       if (!y_fill)
12849         {
12850           clutter_actor_get_preferred_height (self, child_width,
12851                                               &min_height,
12852                                               &natural_height);
12853
12854           child_height = CLAMP (natural_height, min_height, available_height);
12855         }
12856     }
12857   else
12858     {
12859       gfloat min_width, natural_width;
12860       gfloat min_height, natural_height;
12861
12862       clutter_actor_get_preferred_height (self, available_width,
12863                                           &min_height,
12864                                           &natural_height);
12865
12866       child_height = CLAMP (natural_height, min_height, available_height);
12867
12868       if (!x_fill)
12869         {
12870           clutter_actor_get_preferred_width (self, child_height,
12871                                              &min_width,
12872                                              &natural_width);
12873
12874           child_width = CLAMP (natural_width, min_width, available_width);
12875         }
12876     }
12877
12878   /* invert the horizontal alignment for RTL languages */
12879   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
12880     x_align = 1.0 - x_align;
12881
12882   if (!x_fill)
12883     {
12884       allocation.x1 = x_offset
12885                     + ((available_width - child_width) * x_align);
12886       allocation.x2 = allocation.x1 + child_width;
12887     }
12888
12889   if (!y_fill)
12890     {
12891       allocation.y1 = y_offset
12892                     + ((available_height - child_height) * y_align);
12893       allocation.y2 = allocation.y1 + child_height;
12894     }
12895
12896 out:
12897   clutter_actor_box_clamp_to_pixel (&allocation);
12898   clutter_actor_allocate (self, &allocation, flags);
12899 }
12900
12901 /**
12902  * clutter_actor_grab_key_focus:
12903  * @self: a #ClutterActor
12904  *
12905  * Sets the key focus of the #ClutterStage including @self
12906  * to this #ClutterActor.
12907  *
12908  * Since: 1.0
12909  */
12910 void
12911 clutter_actor_grab_key_focus (ClutterActor *self)
12912 {
12913   ClutterActor *stage;
12914
12915   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12916
12917   stage = _clutter_actor_get_stage_internal (self);
12918   if (stage != NULL)
12919     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
12920 }
12921
12922 /**
12923  * clutter_actor_get_pango_context:
12924  * @self: a #ClutterActor
12925  *
12926  * Retrieves the #PangoContext for @self. The actor's #PangoContext
12927  * is already configured using the appropriate font map, resolution
12928  * and font options.
12929  *
12930  * Unlike clutter_actor_create_pango_context(), this context is owend
12931  * by the #ClutterActor and it will be updated each time the options
12932  * stored by the #ClutterBackend change.
12933  *
12934  * You can use the returned #PangoContext to create a #PangoLayout
12935  * and render text using cogl_pango_render_layout() to reuse the
12936  * glyphs cache also used by Clutter.
12937  *
12938  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
12939  *   The returned #PangoContext is owned by the actor and should not be
12940  *   unreferenced by the application code
12941  *
12942  * Since: 1.0
12943  */
12944 PangoContext *
12945 clutter_actor_get_pango_context (ClutterActor *self)
12946 {
12947   ClutterActorPrivate *priv;
12948
12949   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12950
12951   priv = self->priv;
12952
12953   if (priv->pango_context != NULL)
12954     return priv->pango_context;
12955
12956   priv->pango_context = _clutter_context_get_pango_context ();
12957   g_object_ref (priv->pango_context);
12958
12959   return priv->pango_context;
12960 }
12961
12962 /**
12963  * clutter_actor_create_pango_context:
12964  * @self: a #ClutterActor
12965  *
12966  * Creates a #PangoContext for the given actor. The #PangoContext
12967  * is already configured using the appropriate font map, resolution
12968  * and font options.
12969  *
12970  * See also clutter_actor_get_pango_context().
12971  *
12972  * Return value: (transfer full): the newly created #PangoContext.
12973  *   Use g_object_unref() on the returned value to deallocate its
12974  *   resources
12975  *
12976  * Since: 1.0
12977  */
12978 PangoContext *
12979 clutter_actor_create_pango_context (ClutterActor *self)
12980 {
12981   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12982
12983   return _clutter_context_create_pango_context ();
12984 }
12985
12986 /**
12987  * clutter_actor_create_pango_layout:
12988  * @self: a #ClutterActor
12989  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
12990  *
12991  * Creates a new #PangoLayout from the same #PangoContext used
12992  * by the #ClutterActor. The #PangoLayout is already configured
12993  * with the font map, resolution and font options, and the
12994  * given @text.
12995  *
12996  * If you want to keep around a #PangoLayout created by this
12997  * function you will have to connect to the #ClutterBackend::font-changed
12998  * and #ClutterBackend::resolution-changed signals, and call
12999  * pango_layout_context_changed() in response to them.
13000  *
13001  * Return value: (transfer full): the newly created #PangoLayout.
13002  *   Use g_object_unref() when done
13003  *
13004  * Since: 1.0
13005  */
13006 PangoLayout *
13007 clutter_actor_create_pango_layout (ClutterActor *self,
13008                                    const gchar  *text)
13009 {
13010   PangoContext *context;
13011   PangoLayout *layout;
13012
13013   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13014
13015   context = clutter_actor_get_pango_context (self);
13016   layout = pango_layout_new (context);
13017
13018   if (text)
13019     pango_layout_set_text (layout, text, -1);
13020
13021   return layout;
13022 }
13023
13024 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13025  * ClutterOffscreenEffect.
13026  */
13027 void
13028 _clutter_actor_set_opacity_override (ClutterActor *self,
13029                                      gint          opacity)
13030 {
13031   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13032
13033   self->priv->opacity_override = opacity;
13034 }
13035
13036 gint
13037 _clutter_actor_get_opacity_override (ClutterActor *self)
13038 {
13039   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13040
13041   return self->priv->opacity_override;
13042 }
13043
13044 /* Allows you to disable applying the actors model view transform during
13045  * a paint. Used by ClutterClone. */
13046 void
13047 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13048                                                 gboolean      enable)
13049 {
13050   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13051
13052   self->priv->enable_model_view_transform = enable;
13053 }
13054
13055 void
13056 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13057                                           gboolean      enable)
13058 {
13059   ClutterActorPrivate *priv;
13060
13061   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13062
13063   priv = self->priv;
13064
13065   priv->enable_paint_unmapped = enable;
13066
13067   if (priv->enable_paint_unmapped)
13068     {
13069       /* Make sure that the parents of the widget are realized first;
13070        * otherwise checks in clutter_actor_update_map_state() will
13071        * fail.
13072        */
13073       clutter_actor_realize (self);
13074
13075       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13076     }
13077   else
13078     {
13079       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13080     }
13081 }
13082
13083 static void
13084 clutter_anchor_coord_get_units (ClutterActor      *self,
13085                                 const AnchorCoord *coord,
13086                                 gfloat            *x,
13087                                 gfloat            *y,
13088                                 gfloat            *z)
13089 {
13090   if (coord->is_fractional)
13091     {
13092       gfloat actor_width, actor_height;
13093
13094       clutter_actor_get_size (self, &actor_width, &actor_height);
13095
13096       if (x)
13097         *x = actor_width * coord->v.fraction.x;
13098
13099       if (y)
13100         *y = actor_height * coord->v.fraction.y;
13101
13102       if (z)
13103         *z = 0;
13104     }
13105   else
13106     {
13107       if (x)
13108         *x = coord->v.units.x;
13109
13110       if (y)
13111         *y = coord->v.units.y;
13112
13113       if (z)
13114         *z = coord->v.units.z;
13115     }
13116 }
13117
13118 static void
13119 clutter_anchor_coord_set_units (AnchorCoord *coord,
13120                                 gfloat       x,
13121                                 gfloat       y,
13122                                 gfloat       z)
13123 {
13124   coord->is_fractional = FALSE;
13125   coord->v.units.x = x;
13126   coord->v.units.y = y;
13127   coord->v.units.z = z;
13128 }
13129
13130 static ClutterGravity
13131 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13132 {
13133   if (coord->is_fractional)
13134     {
13135       if (coord->v.fraction.x == 0.0)
13136         {
13137           if (coord->v.fraction.y == 0.0)
13138             return CLUTTER_GRAVITY_NORTH_WEST;
13139           else if (coord->v.fraction.y == 0.5)
13140             return CLUTTER_GRAVITY_WEST;
13141           else if (coord->v.fraction.y == 1.0)
13142             return CLUTTER_GRAVITY_SOUTH_WEST;
13143           else
13144             return CLUTTER_GRAVITY_NONE;
13145         }
13146       else if (coord->v.fraction.x == 0.5)
13147         {
13148           if (coord->v.fraction.y == 0.0)
13149             return CLUTTER_GRAVITY_NORTH;
13150           else if (coord->v.fraction.y == 0.5)
13151             return CLUTTER_GRAVITY_CENTER;
13152           else if (coord->v.fraction.y == 1.0)
13153             return CLUTTER_GRAVITY_SOUTH;
13154           else
13155             return CLUTTER_GRAVITY_NONE;
13156         }
13157       else if (coord->v.fraction.x == 1.0)
13158         {
13159           if (coord->v.fraction.y == 0.0)
13160             return CLUTTER_GRAVITY_NORTH_EAST;
13161           else if (coord->v.fraction.y == 0.5)
13162             return CLUTTER_GRAVITY_EAST;
13163           else if (coord->v.fraction.y == 1.0)
13164             return CLUTTER_GRAVITY_SOUTH_EAST;
13165           else
13166             return CLUTTER_GRAVITY_NONE;
13167         }
13168       else
13169         return CLUTTER_GRAVITY_NONE;
13170     }
13171   else
13172     return CLUTTER_GRAVITY_NONE;
13173 }
13174
13175 static void
13176 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13177                                   ClutterGravity  gravity)
13178 {
13179   switch (gravity)
13180     {
13181     case CLUTTER_GRAVITY_NORTH:
13182       coord->v.fraction.x = 0.5;
13183       coord->v.fraction.y = 0.0;
13184       break;
13185
13186     case CLUTTER_GRAVITY_NORTH_EAST:
13187       coord->v.fraction.x = 1.0;
13188       coord->v.fraction.y = 0.0;
13189       break;
13190
13191     case CLUTTER_GRAVITY_EAST:
13192       coord->v.fraction.x = 1.0;
13193       coord->v.fraction.y = 0.5;
13194       break;
13195
13196     case CLUTTER_GRAVITY_SOUTH_EAST:
13197       coord->v.fraction.x = 1.0;
13198       coord->v.fraction.y = 1.0;
13199       break;
13200
13201     case CLUTTER_GRAVITY_SOUTH:
13202       coord->v.fraction.x = 0.5;
13203       coord->v.fraction.y = 1.0;
13204       break;
13205
13206     case CLUTTER_GRAVITY_SOUTH_WEST:
13207       coord->v.fraction.x = 0.0;
13208       coord->v.fraction.y = 1.0;
13209       break;
13210
13211     case CLUTTER_GRAVITY_WEST:
13212       coord->v.fraction.x = 0.0;
13213       coord->v.fraction.y = 0.5;
13214       break;
13215
13216     case CLUTTER_GRAVITY_NORTH_WEST:
13217       coord->v.fraction.x = 0.0;
13218       coord->v.fraction.y = 0.0;
13219       break;
13220
13221     case CLUTTER_GRAVITY_CENTER:
13222       coord->v.fraction.x = 0.5;
13223       coord->v.fraction.y = 0.5;
13224       break;
13225
13226     default:
13227       coord->v.fraction.x = 0.0;
13228       coord->v.fraction.y = 0.0;
13229       break;
13230     }
13231
13232   coord->is_fractional = TRUE;
13233 }
13234
13235 static gboolean
13236 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13237 {
13238   if (coord->is_fractional)
13239     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13240   else
13241     return (coord->v.units.x == 0.0
13242             && coord->v.units.y == 0.0
13243             && coord->v.units.z == 0.0);
13244 }
13245
13246 /**
13247  * clutter_actor_get_flags:
13248  * @self: a #ClutterActor
13249  *
13250  * Retrieves the flags set on @self
13251  *
13252  * Return value: a bitwise or of #ClutterActorFlags or 0
13253  *
13254  * Since: 1.0
13255  */
13256 ClutterActorFlags
13257 clutter_actor_get_flags (ClutterActor *self)
13258 {
13259   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13260
13261   return self->flags;
13262 }
13263
13264 /**
13265  * clutter_actor_set_flags:
13266  * @self: a #ClutterActor
13267  * @flags: the flags to set
13268  *
13269  * Sets @flags on @self
13270  *
13271  * This function will emit notifications for the changed properties
13272  *
13273  * Since: 1.0
13274  */
13275 void
13276 clutter_actor_set_flags (ClutterActor      *self,
13277                          ClutterActorFlags  flags)
13278 {
13279   ClutterActorFlags old_flags;
13280   GObject *obj;
13281   gboolean was_reactive_set, reactive_set;
13282   gboolean was_realized_set, realized_set;
13283   gboolean was_mapped_set, mapped_set;
13284   gboolean was_visible_set, visible_set;
13285
13286   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13287
13288   if (self->flags == flags)
13289     return;
13290
13291   obj = G_OBJECT (self);
13292   g_object_ref (obj);
13293   g_object_freeze_notify (obj);
13294
13295   old_flags = self->flags;
13296
13297   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13298   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13299   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13300   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13301
13302   self->flags |= flags;
13303
13304   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13305   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13306   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13307   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13308
13309   if (reactive_set != was_reactive_set)
13310     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13311
13312   if (realized_set != was_realized_set)
13313     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13314
13315   if (mapped_set != was_mapped_set)
13316     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13317
13318   if (visible_set != was_visible_set)
13319     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13320
13321   g_object_thaw_notify (obj);
13322   g_object_unref (obj);
13323 }
13324
13325 /**
13326  * clutter_actor_unset_flags:
13327  * @self: a #ClutterActor
13328  * @flags: the flags to unset
13329  *
13330  * Unsets @flags on @self
13331  *
13332  * This function will emit notifications for the changed properties
13333  *
13334  * Since: 1.0
13335  */
13336 void
13337 clutter_actor_unset_flags (ClutterActor      *self,
13338                            ClutterActorFlags  flags)
13339 {
13340   ClutterActorFlags old_flags;
13341   GObject *obj;
13342   gboolean was_reactive_set, reactive_set;
13343   gboolean was_realized_set, realized_set;
13344   gboolean was_mapped_set, mapped_set;
13345   gboolean was_visible_set, visible_set;
13346
13347   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13348
13349   obj = G_OBJECT (self);
13350   g_object_freeze_notify (obj);
13351
13352   old_flags = self->flags;
13353
13354   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13355   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13356   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13357   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13358
13359   self->flags &= ~flags;
13360
13361   if (self->flags == old_flags)
13362     return;
13363
13364   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13365   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13366   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13367   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13368
13369   if (reactive_set != was_reactive_set)
13370     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13371
13372   if (realized_set != was_realized_set)
13373     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13374
13375   if (mapped_set != was_mapped_set)
13376     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13377
13378   if (visible_set != was_visible_set)
13379     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13380
13381   g_object_thaw_notify (obj);
13382 }
13383
13384 /**
13385  * clutter_actor_get_transformation_matrix:
13386  * @self: a #ClutterActor
13387  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13388  *
13389  * Retrieves the transformations applied to @self relative to its
13390  * parent.
13391  *
13392  * Since: 1.0
13393  */
13394 void
13395 clutter_actor_get_transformation_matrix (ClutterActor *self,
13396                                          CoglMatrix   *matrix)
13397 {
13398   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13399
13400   cogl_matrix_init_identity (matrix);
13401
13402   _clutter_actor_apply_modelview_transform (self, matrix);
13403 }
13404
13405 void
13406 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13407                                    gboolean      is_in_clone_paint)
13408 {
13409   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13410   self->priv->in_clone_paint = is_in_clone_paint;
13411 }
13412
13413 /**
13414  * clutter_actor_is_in_clone_paint:
13415  * @self: a #ClutterActor
13416  *
13417  * Checks whether @self is being currently painted by a #ClutterClone
13418  *
13419  * This function is useful only inside the ::paint virtual function
13420  * implementations or within handlers for the #ClutterActor::paint
13421  * signal
13422  *
13423  * This function should not be used by applications
13424  *
13425  * Return value: %TRUE if the #ClutterActor is currently being painted
13426  *   by a #ClutterClone, and %FALSE otherwise
13427  *
13428  * Since: 1.0
13429  */
13430 gboolean
13431 clutter_actor_is_in_clone_paint (ClutterActor *self)
13432 {
13433   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13434
13435   return self->priv->in_clone_paint;
13436 }
13437
13438 static gboolean
13439 set_direction_recursive (ClutterActor *actor,
13440                          gpointer      user_data)
13441 {
13442   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
13443
13444   clutter_actor_set_text_direction (actor, text_dir);
13445
13446   return TRUE;
13447 }
13448
13449 /**
13450  * clutter_actor_set_text_direction:
13451  * @self: a #ClutterActor
13452  * @text_dir: the text direction for @self
13453  *
13454  * Sets the #ClutterTextDirection for an actor
13455  *
13456  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
13457  *
13458  * If @self implements #ClutterContainer then this function will recurse
13459  * inside all the children of @self (including the internal ones).
13460  *
13461  * Composite actors not implementing #ClutterContainer, or actors requiring
13462  * special handling when the text direction changes, should connect to
13463  * the #GObject::notify signal for the #ClutterActor:text-direction property
13464  *
13465  * Since: 1.2
13466  */
13467 void
13468 clutter_actor_set_text_direction (ClutterActor         *self,
13469                                   ClutterTextDirection  text_dir)
13470 {
13471   ClutterActorPrivate *priv;
13472
13473   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13474   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
13475
13476   priv = self->priv;
13477
13478   if (priv->text_direction != text_dir)
13479     {
13480       priv->text_direction = text_dir;
13481
13482       /* we need to emit the notify::text-direction first, so that
13483        * the sub-classes can catch that and do specific handling of
13484        * the text direction; see clutter_text_direction_changed_cb()
13485        * inside clutter-text.c
13486        */
13487       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
13488
13489       _clutter_actor_foreach_child (self, set_direction_recursive,
13490                                     GINT_TO_POINTER (text_dir));
13491
13492       clutter_actor_queue_relayout (self);
13493     }
13494 }
13495
13496 void
13497 _clutter_actor_set_has_pointer (ClutterActor *self,
13498                                 gboolean      has_pointer)
13499 {
13500   ClutterActorPrivate *priv = self->priv;
13501
13502   if (priv->has_pointer != has_pointer)
13503     {
13504       priv->has_pointer = has_pointer;
13505
13506       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
13507     }
13508 }
13509
13510 /**
13511  * clutter_actor_get_text_direction:
13512  * @self: a #ClutterActor
13513  *
13514  * Retrieves the value set using clutter_actor_set_text_direction()
13515  *
13516  * If no text direction has been previously set, the default text
13517  * direction, as returned by clutter_get_default_text_direction(), will
13518  * be returned instead
13519  *
13520  * Return value: the #ClutterTextDirection for the actor
13521  *
13522  * Since: 1.2
13523  */
13524 ClutterTextDirection
13525 clutter_actor_get_text_direction (ClutterActor *self)
13526 {
13527   ClutterActorPrivate *priv;
13528
13529   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
13530                         CLUTTER_TEXT_DIRECTION_LTR);
13531
13532   priv = self->priv;
13533
13534   /* if no direction has been set yet use the default */
13535   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
13536     priv->text_direction = clutter_get_default_text_direction ();
13537
13538   return priv->text_direction;
13539 }
13540
13541 /**
13542  * clutter_actor_push_internal:
13543  * @self: a #ClutterActor
13544  *
13545  * Should be used by actors implementing the #ClutterContainer and with
13546  * internal children added through clutter_actor_set_parent(), for instance:
13547  *
13548  * |[
13549  *   static void
13550  *   my_actor_init (MyActor *self)
13551  *   {
13552  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
13553  *
13554  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
13555  *
13556  *     /&ast; calling clutter_actor_set_parent() now will result in
13557  *      &ast; the internal flag being set on a child of MyActor
13558  *      &ast;/
13559  *
13560  *     /&ast; internal child - a background texture &ast;/
13561  *     self->priv->background_tex = clutter_texture_new ();
13562  *     clutter_actor_set_parent (self->priv->background_tex,
13563  *                               CLUTTER_ACTOR (self));
13564  *
13565  *     /&ast; internal child - a label &ast;/
13566  *     self->priv->label = clutter_text_new ();
13567  *     clutter_actor_set_parent (self->priv->label,
13568  *                               CLUTTER_ACTOR (self));
13569  *
13570  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
13571  *
13572  *     /&ast; calling clutter_actor_set_parent() now will not result in
13573  *      &ast; the internal flag being set on a child of MyActor
13574  *      &ast;/
13575  *   }
13576  * ]|
13577  *
13578  * This function will be used by Clutter to toggle an "internal child"
13579  * flag whenever clutter_actor_set_parent() is called; internal children
13580  * are handled differently by Clutter, specifically when destroying their
13581  * parent.
13582  *
13583  * Call clutter_actor_pop_internal() when you finished adding internal
13584  * children.
13585  *
13586  * Nested calls to clutter_actor_push_internal() are allowed, but each
13587  * one must by followed by a clutter_actor_pop_internal() call.
13588  *
13589  * Since: 1.2
13590  *
13591  * Deprecated: 1.10: All children of an actor are accessible through
13592  *   the #ClutterActor API, and #ClutterActor implements the
13593  *   #ClutterContainer interface, so this function is only useful
13594  *   for legacy containers overriding the default implementation.
13595  */
13596 void
13597 clutter_actor_push_internal (ClutterActor *self)
13598 {
13599   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13600
13601   self->priv->internal_child += 1;
13602 }
13603
13604 /**
13605  * clutter_actor_pop_internal:
13606  * @self: a #ClutterActor
13607  *
13608  * Disables the effects of clutter_actor_push_internal().
13609  *
13610  * Since: 1.2
13611  *
13612  * Deprecated: 1.10: All children of an actor are accessible through
13613  *   the #ClutterActor API. This function is only useful for legacy
13614  *   containers overriding the default implementation of the
13615  *   #ClutterContainer interface.
13616  */
13617 void
13618 clutter_actor_pop_internal (ClutterActor *self)
13619 {
13620   ClutterActorPrivate *priv;
13621
13622   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13623
13624   priv = self->priv;
13625
13626   if (priv->internal_child == 0)
13627     {
13628       g_warning ("Mismatched %s: you need to call "
13629                  "clutter_actor_push_composite() at least once before "
13630                  "calling this function", G_STRFUNC);
13631       return;
13632     }
13633
13634   priv->internal_child -= 1;
13635 }
13636
13637 /**
13638  * clutter_actor_has_pointer:
13639  * @self: a #ClutterActor
13640  *
13641  * Checks whether an actor contains the pointer of a
13642  * #ClutterInputDevice
13643  *
13644  * Return value: %TRUE if the actor contains the pointer, and
13645  *   %FALSE otherwise
13646  *
13647  * Since: 1.2
13648  */
13649 gboolean
13650 clutter_actor_has_pointer (ClutterActor *self)
13651 {
13652   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13653
13654   return self->priv->has_pointer;
13655 }
13656
13657 /* XXX: This is a workaround for not being able to break the ABI of
13658  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
13659  * clutter_actor_queue_clipped_redraw() for details.
13660  */
13661 ClutterPaintVolume *
13662 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
13663 {
13664   return g_object_get_data (G_OBJECT (self),
13665                             "-clutter-actor-queue-redraw-clip");
13666 }
13667
13668 void
13669 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
13670                                       ClutterPaintVolume *clip)
13671 {
13672   g_object_set_data (G_OBJECT (self),
13673                      "-clutter-actor-queue-redraw-clip",
13674                      clip);
13675 }
13676
13677 /**
13678  * clutter_actor_has_allocation:
13679  * @self: a #ClutterActor
13680  *
13681  * Checks if the actor has an up-to-date allocation assigned to
13682  * it. This means that the actor should have an allocation: it's
13683  * visible and has a parent. It also means that there is no
13684  * outstanding relayout request in progress for the actor or its
13685  * children (There might be other outstanding layout requests in
13686  * progress that will cause the actor to get a new allocation
13687  * when the stage is laid out, however).
13688  *
13689  * If this function returns %FALSE, then the actor will normally
13690  * be allocated before it is next drawn on the screen.
13691  *
13692  * Return value: %TRUE if the actor has an up-to-date allocation
13693  *
13694  * Since: 1.4
13695  */
13696 gboolean
13697 clutter_actor_has_allocation (ClutterActor *self)
13698 {
13699   ClutterActorPrivate *priv;
13700
13701   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13702
13703   priv = self->priv;
13704
13705   return priv->parent != NULL &&
13706          CLUTTER_ACTOR_IS_VISIBLE (self) &&
13707          !priv->needs_allocation;
13708 }
13709
13710 /**
13711  * clutter_actor_add_action:
13712  * @self: a #ClutterActor
13713  * @action: a #ClutterAction
13714  *
13715  * Adds @action to the list of actions applied to @self
13716  *
13717  * A #ClutterAction can only belong to one actor at a time
13718  *
13719  * The #ClutterActor will hold a reference on @action until either
13720  * clutter_actor_remove_action() or clutter_actor_clear_actions()
13721  * is called
13722  *
13723  * Since: 1.4
13724  */
13725 void
13726 clutter_actor_add_action (ClutterActor  *self,
13727                           ClutterAction *action)
13728 {
13729   ClutterActorPrivate *priv;
13730
13731   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13732   g_return_if_fail (CLUTTER_IS_ACTION (action));
13733
13734   priv = self->priv;
13735
13736   if (priv->actions == NULL)
13737     {
13738       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13739       priv->actions->actor = self;
13740     }
13741
13742   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
13743
13744   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13745 }
13746
13747 /**
13748  * clutter_actor_add_action_with_name:
13749  * @self: a #ClutterActor
13750  * @name: the name to set on the action
13751  * @action: a #ClutterAction
13752  *
13753  * A convenience function for setting the name of a #ClutterAction
13754  * while adding it to the list of actions applied to @self
13755  *
13756  * This function is the logical equivalent of:
13757  *
13758  * |[
13759  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13760  *   clutter_actor_add_action (self, action);
13761  * ]|
13762  *
13763  * Since: 1.4
13764  */
13765 void
13766 clutter_actor_add_action_with_name (ClutterActor  *self,
13767                                     const gchar   *name,
13768                                     ClutterAction *action)
13769 {
13770   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13771   g_return_if_fail (name != NULL);
13772   g_return_if_fail (CLUTTER_IS_ACTION (action));
13773
13774   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13775   clutter_actor_add_action (self, action);
13776 }
13777
13778 /**
13779  * clutter_actor_remove_action:
13780  * @self: a #ClutterActor
13781  * @action: a #ClutterAction
13782  *
13783  * Removes @action from the list of actions applied to @self
13784  *
13785  * The reference held by @self on the #ClutterAction will be released
13786  *
13787  * Since: 1.4
13788  */
13789 void
13790 clutter_actor_remove_action (ClutterActor  *self,
13791                              ClutterAction *action)
13792 {
13793   ClutterActorPrivate *priv;
13794
13795   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13796   g_return_if_fail (CLUTTER_IS_ACTION (action));
13797
13798   priv = self->priv;
13799
13800   if (priv->actions == NULL)
13801     return;
13802
13803   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
13804
13805   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13806 }
13807
13808 /**
13809  * clutter_actor_remove_action_by_name:
13810  * @self: a #ClutterActor
13811  * @name: the name of the action to remove
13812  *
13813  * Removes the #ClutterAction with the given name from the list
13814  * of actions applied to @self
13815  *
13816  * Since: 1.4
13817  */
13818 void
13819 clutter_actor_remove_action_by_name (ClutterActor *self,
13820                                      const gchar  *name)
13821 {
13822   ClutterActorPrivate *priv;
13823   ClutterActorMeta *meta;
13824
13825   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13826   g_return_if_fail (name != NULL);
13827
13828   priv = self->priv;
13829
13830   if (priv->actions == NULL)
13831     return;
13832
13833   meta = _clutter_meta_group_get_meta (priv->actions, name);
13834   if (meta == NULL)
13835     return;
13836
13837   _clutter_meta_group_remove_meta (priv->actions, meta);
13838
13839   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13840 }
13841
13842 /**
13843  * clutter_actor_get_actions:
13844  * @self: a #ClutterActor
13845  *
13846  * Retrieves the list of actions applied to @self
13847  *
13848  * Return value: (transfer container) (element-type Clutter.Action): a copy
13849  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
13850  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13851  *   allocated by the returned #GList
13852  *
13853  * Since: 1.4
13854  */
13855 GList *
13856 clutter_actor_get_actions (ClutterActor *self)
13857 {
13858   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13859
13860   if (self->priv->actions == NULL)
13861     return NULL;
13862
13863   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
13864 }
13865
13866 /**
13867  * clutter_actor_get_action:
13868  * @self: a #ClutterActor
13869  * @name: the name of the action to retrieve
13870  *
13871  * Retrieves the #ClutterAction with the given name in the list
13872  * of actions applied to @self
13873  *
13874  * Return value: (transfer none): a #ClutterAction for the given
13875  *   name, or %NULL. The returned #ClutterAction is owned by the
13876  *   actor and it should not be unreferenced directly
13877  *
13878  * Since: 1.4
13879  */
13880 ClutterAction *
13881 clutter_actor_get_action (ClutterActor *self,
13882                           const gchar  *name)
13883 {
13884   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13885   g_return_val_if_fail (name != NULL, NULL);
13886
13887   if (self->priv->actions == NULL)
13888     return NULL;
13889
13890   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
13891 }
13892
13893 /**
13894  * clutter_actor_clear_actions:
13895  * @self: a #ClutterActor
13896  *
13897  * Clears the list of actions applied to @self
13898  *
13899  * Since: 1.4
13900  */
13901 void
13902 clutter_actor_clear_actions (ClutterActor *self)
13903 {
13904   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13905
13906   if (self->priv->actions == NULL)
13907     return;
13908
13909   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
13910 }
13911
13912 /**
13913  * clutter_actor_add_constraint:
13914  * @self: a #ClutterActor
13915  * @constraint: a #ClutterConstraint
13916  *
13917  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
13918  * to @self
13919  *
13920  * The #ClutterActor will hold a reference on the @constraint until
13921  * either clutter_actor_remove_constraint() or
13922  * clutter_actor_clear_constraints() is called.
13923  *
13924  * Since: 1.4
13925  */
13926 void
13927 clutter_actor_add_constraint (ClutterActor      *self,
13928                               ClutterConstraint *constraint)
13929 {
13930   ClutterActorPrivate *priv;
13931
13932   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13933   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13934
13935   priv = self->priv;
13936
13937   if (priv->constraints == NULL)
13938     {
13939       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13940       priv->constraints->actor = self;
13941     }
13942
13943   _clutter_meta_group_add_meta (priv->constraints,
13944                                 CLUTTER_ACTOR_META (constraint));
13945   clutter_actor_queue_relayout (self);
13946
13947   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13948 }
13949
13950 /**
13951  * clutter_actor_add_constraint_with_name:
13952  * @self: a #ClutterActor
13953  * @name: the name to set on the constraint
13954  * @constraint: a #ClutterConstraint
13955  *
13956  * A convenience function for setting the name of a #ClutterConstraint
13957  * while adding it to the list of constraints applied to @self
13958  *
13959  * This function is the logical equivalent of:
13960  *
13961  * |[
13962  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13963  *   clutter_actor_add_constraint (self, constraint);
13964  * ]|
13965  *
13966  * Since: 1.4
13967  */
13968 void
13969 clutter_actor_add_constraint_with_name (ClutterActor      *self,
13970                                         const gchar       *name,
13971                                         ClutterConstraint *constraint)
13972 {
13973   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13974   g_return_if_fail (name != NULL);
13975   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13976
13977   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13978   clutter_actor_add_constraint (self, constraint);
13979 }
13980
13981 /**
13982  * clutter_actor_remove_constraint:
13983  * @self: a #ClutterActor
13984  * @constraint: a #ClutterConstraint
13985  *
13986  * Removes @constraint from the list of constraints applied to @self
13987  *
13988  * The reference held by @self on the #ClutterConstraint will be released
13989  *
13990  * Since: 1.4
13991  */
13992 void
13993 clutter_actor_remove_constraint (ClutterActor      *self,
13994                                  ClutterConstraint *constraint)
13995 {
13996   ClutterActorPrivate *priv;
13997
13998   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13999   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14000
14001   priv = self->priv;
14002
14003   if (priv->constraints == NULL)
14004     return;
14005
14006   _clutter_meta_group_remove_meta (priv->constraints,
14007                                    CLUTTER_ACTOR_META (constraint));
14008   clutter_actor_queue_relayout (self);
14009
14010   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14011 }
14012
14013 /**
14014  * clutter_actor_remove_constraint_by_name:
14015  * @self: a #ClutterActor
14016  * @name: the name of the constraint to remove
14017  *
14018  * Removes the #ClutterConstraint with the given name from the list
14019  * of constraints applied to @self
14020  *
14021  * Since: 1.4
14022  */
14023 void
14024 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14025                                          const gchar  *name)
14026 {
14027   ClutterActorPrivate *priv;
14028   ClutterActorMeta *meta;
14029
14030   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14031   g_return_if_fail (name != NULL);
14032
14033   priv = self->priv;
14034
14035   if (priv->constraints == NULL)
14036     return;
14037
14038   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14039   if (meta == NULL)
14040     return;
14041
14042   _clutter_meta_group_remove_meta (priv->constraints, meta);
14043   clutter_actor_queue_relayout (self);
14044 }
14045
14046 /**
14047  * clutter_actor_get_constraints:
14048  * @self: a #ClutterActor
14049  *
14050  * Retrieves the list of constraints applied to @self
14051  *
14052  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14053  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14054  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14055  *   allocated by the returned #GList
14056  *
14057  * Since: 1.4
14058  */
14059 GList *
14060 clutter_actor_get_constraints (ClutterActor *self)
14061 {
14062   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14063
14064   if (self->priv->constraints == NULL)
14065     return NULL;
14066
14067   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14068 }
14069
14070 /**
14071  * clutter_actor_get_constraint:
14072  * @self: a #ClutterActor
14073  * @name: the name of the constraint to retrieve
14074  *
14075  * Retrieves the #ClutterConstraint with the given name in the list
14076  * of constraints applied to @self
14077  *
14078  * Return value: (transfer none): a #ClutterConstraint for the given
14079  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14080  *   actor and it should not be unreferenced directly
14081  *
14082  * Since: 1.4
14083  */
14084 ClutterConstraint *
14085 clutter_actor_get_constraint (ClutterActor *self,
14086                               const gchar  *name)
14087 {
14088   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14089   g_return_val_if_fail (name != NULL, NULL);
14090
14091   if (self->priv->constraints == NULL)
14092     return NULL;
14093
14094   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14095 }
14096
14097 /**
14098  * clutter_actor_clear_constraints:
14099  * @self: a #ClutterActor
14100  *
14101  * Clears the list of constraints applied to @self
14102  *
14103  * Since: 1.4
14104  */
14105 void
14106 clutter_actor_clear_constraints (ClutterActor *self)
14107 {
14108   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14109
14110   if (self->priv->constraints == NULL)
14111     return;
14112
14113   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14114
14115   clutter_actor_queue_relayout (self);
14116 }
14117
14118 /**
14119  * clutter_actor_set_clip_to_allocation:
14120  * @self: a #ClutterActor
14121  * @clip_set: %TRUE to apply a clip tracking the allocation
14122  *
14123  * Sets whether @self should be clipped to the same size as its
14124  * allocation
14125  *
14126  * Since: 1.4
14127  */
14128 void
14129 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14130                                       gboolean      clip_set)
14131 {
14132   ClutterActorPrivate *priv;
14133
14134   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14135
14136   clip_set = !!clip_set;
14137
14138   priv = self->priv;
14139
14140   if (priv->clip_to_allocation != clip_set)
14141     {
14142       priv->clip_to_allocation = clip_set;
14143
14144       clutter_actor_queue_redraw (self);
14145
14146       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14147     }
14148 }
14149
14150 /**
14151  * clutter_actor_get_clip_to_allocation:
14152  * @self: a #ClutterActor
14153  *
14154  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14155  *
14156  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14157  *
14158  * Since: 1.4
14159  */
14160 gboolean
14161 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14162 {
14163   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14164
14165   return self->priv->clip_to_allocation;
14166 }
14167
14168 /**
14169  * clutter_actor_add_effect:
14170  * @self: a #ClutterActor
14171  * @effect: a #ClutterEffect
14172  *
14173  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14174  *
14175  * The #ClutterActor will hold a reference on the @effect until either
14176  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14177  * called.
14178  *
14179  * Since: 1.4
14180  */
14181 void
14182 clutter_actor_add_effect (ClutterActor  *self,
14183                           ClutterEffect *effect)
14184 {
14185   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14186   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14187
14188   _clutter_actor_add_effect_internal (self, effect);
14189
14190   clutter_actor_queue_redraw (self);
14191
14192   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14193 }
14194
14195 /**
14196  * clutter_actor_add_effect_with_name:
14197  * @self: a #ClutterActor
14198  * @name: the name to set on the effect
14199  * @effect: a #ClutterEffect
14200  *
14201  * A convenience function for setting the name of a #ClutterEffect
14202  * while adding it to the list of effectss applied to @self
14203  *
14204  * This function is the logical equivalent of:
14205  *
14206  * |[
14207  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14208  *   clutter_actor_add_effect (self, effect);
14209  * ]|
14210  *
14211  * Since: 1.4
14212  */
14213 void
14214 clutter_actor_add_effect_with_name (ClutterActor  *self,
14215                                     const gchar   *name,
14216                                     ClutterEffect *effect)
14217 {
14218   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14219   g_return_if_fail (name != NULL);
14220   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14221
14222   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14223   clutter_actor_add_effect (self, effect);
14224 }
14225
14226 /**
14227  * clutter_actor_remove_effect:
14228  * @self: a #ClutterActor
14229  * @effect: a #ClutterEffect
14230  *
14231  * Removes @effect from the list of effects applied to @self
14232  *
14233  * The reference held by @self on the #ClutterEffect will be released
14234  *
14235  * Since: 1.4
14236  */
14237 void
14238 clutter_actor_remove_effect (ClutterActor  *self,
14239                              ClutterEffect *effect)
14240 {
14241   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14242   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14243
14244   _clutter_actor_remove_effect_internal (self, effect);
14245
14246   clutter_actor_queue_redraw (self);
14247
14248   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14249 }
14250
14251 /**
14252  * clutter_actor_remove_effect_by_name:
14253  * @self: a #ClutterActor
14254  * @name: the name of the effect to remove
14255  *
14256  * Removes the #ClutterEffect with the given name from the list
14257  * of effects applied to @self
14258  *
14259  * Since: 1.4
14260  */
14261 void
14262 clutter_actor_remove_effect_by_name (ClutterActor *self,
14263                                      const gchar  *name)
14264 {
14265   ClutterActorPrivate *priv;
14266   ClutterActorMeta *meta;
14267
14268   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14269   g_return_if_fail (name != NULL);
14270
14271   priv = self->priv;
14272
14273   if (priv->effects == NULL)
14274     return;
14275
14276   meta = _clutter_meta_group_get_meta (priv->effects, name);
14277   if (meta == NULL)
14278     return;
14279
14280   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14281 }
14282
14283 /**
14284  * clutter_actor_get_effects:
14285  * @self: a #ClutterActor
14286  *
14287  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14288  *
14289  * Return value: (transfer container) (element-type Clutter.Effect): a list
14290  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14291  *   list are owned by Clutter and they should not be freed. You should
14292  *   free the returned list using g_list_free() when done
14293  *
14294  * Since: 1.4
14295  */
14296 GList *
14297 clutter_actor_get_effects (ClutterActor *self)
14298 {
14299   ClutterActorPrivate *priv;
14300
14301   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14302
14303   priv = self->priv;
14304
14305   if (priv->effects == NULL)
14306     return NULL;
14307
14308   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14309 }
14310
14311 /**
14312  * clutter_actor_get_effect:
14313  * @self: a #ClutterActor
14314  * @name: the name of the effect to retrieve
14315  *
14316  * Retrieves the #ClutterEffect with the given name in the list
14317  * of effects applied to @self
14318  *
14319  * Return value: (transfer none): a #ClutterEffect for the given
14320  *   name, or %NULL. The returned #ClutterEffect is owned by the
14321  *   actor and it should not be unreferenced directly
14322  *
14323  * Since: 1.4
14324  */
14325 ClutterEffect *
14326 clutter_actor_get_effect (ClutterActor *self,
14327                           const gchar  *name)
14328 {
14329   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14330   g_return_val_if_fail (name != NULL, NULL);
14331
14332   if (self->priv->effects == NULL)
14333     return NULL;
14334
14335   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14336 }
14337
14338 /**
14339  * clutter_actor_clear_effects:
14340  * @self: a #ClutterActor
14341  *
14342  * Clears the list of effects applied to @self
14343  *
14344  * Since: 1.4
14345  */
14346 void
14347 clutter_actor_clear_effects (ClutterActor *self)
14348 {
14349   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14350
14351   if (self->priv->effects == NULL)
14352     return;
14353
14354   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14355
14356   clutter_actor_queue_redraw (self);
14357 }
14358
14359 /**
14360  * clutter_actor_has_key_focus:
14361  * @self: a #ClutterActor
14362  *
14363  * Checks whether @self is the #ClutterActor that has key focus
14364  *
14365  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14366  *
14367  * Since: 1.4
14368  */
14369 gboolean
14370 clutter_actor_has_key_focus (ClutterActor *self)
14371 {
14372   ClutterActor *stage;
14373
14374   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14375
14376   stage = _clutter_actor_get_stage_internal (self);
14377   if (stage == NULL)
14378     return FALSE;
14379
14380   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14381 }
14382
14383 static gboolean
14384 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14385                                       ClutterPaintVolume *pv)
14386 {
14387   ClutterActorPrivate *priv = self->priv;
14388
14389   /* Actors are only expected to report a valid paint volume
14390    * while they have a valid allocation. */
14391   if (G_UNLIKELY (priv->needs_allocation))
14392     {
14393       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14394                     "Actor needs allocation",
14395                     _clutter_actor_get_debug_name (self));
14396       return FALSE;
14397     }
14398
14399   /* Check if there are any handlers connected to the paint
14400    * signal. If there are then all bets are off for what the paint
14401    * volume for this actor might possibly be!
14402    *
14403    * XXX: It's expected that this is going to end up being quite a
14404    * costly check to have to do here, but we haven't come up with
14405    * another solution that can reliably catch paint signal handlers at
14406    * the right time to either avoid artefacts due to invalid stage
14407    * clipping or due to incorrect culling.
14408    *
14409    * Previously we checked in clutter_actor_paint(), but at that time
14410    * we may already be using a stage clip that could be derived from
14411    * an invalid paint-volume. We used to try and handle that by
14412    * queuing a follow up, unclipped, redraw but still the previous
14413    * checking wasn't enough to catch invalid volumes involved in
14414    * culling (considering that containers may derive their volume from
14415    * children that haven't yet been painted)
14416    *
14417    * Longer term, improved solutions could be:
14418    * - Disallow painting in the paint signal, only allow using it
14419    *   for tracking when paints happen. We can add another API that
14420    *   allows monkey patching the paint of arbitrary actors but in a
14421    *   more controlled way and that also supports modifying the
14422    *   paint-volume.
14423    * - If we could be notified somehow when signal handlers are
14424    *   connected we wouldn't have to poll for handlers like this.
14425    */
14426   if (g_signal_has_handler_pending (self,
14427                                     actor_signals[PAINT],
14428                                     0,
14429                                     TRUE))
14430     {
14431       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14432                     "Actor has \"paint\" signal handlers",
14433                     _clutter_actor_get_debug_name (self));
14434       return FALSE;
14435     }
14436
14437   _clutter_paint_volume_init_static (pv, self);
14438
14439   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
14440     {
14441       clutter_paint_volume_free (pv);
14442       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14443                     "Actor failed to report a volume",
14444                     _clutter_actor_get_debug_name (self));
14445       return FALSE;
14446     }
14447
14448   /* since effects can modify the paint volume, we allow them to actually
14449    * do this by making get_paint_volume() "context sensitive"
14450    */
14451   if (priv->effects != NULL)
14452     {
14453       if (priv->current_effect != NULL)
14454         {
14455           const GList *effects, *l;
14456
14457           /* if we are being called from within the paint sequence of
14458            * an actor, get the paint volume up to the current effect
14459            */
14460           effects = _clutter_meta_group_peek_metas (priv->effects);
14461           for (l = effects;
14462                l != NULL || (l != NULL && l->data != priv->current_effect);
14463                l = l->next)
14464             {
14465               if (!_clutter_effect_get_paint_volume (l->data, pv))
14466                 {
14467                   clutter_paint_volume_free (pv);
14468                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14469                                 "Effect (%s) failed to report a volume",
14470                                 _clutter_actor_get_debug_name (self),
14471                                 _clutter_actor_meta_get_debug_name (l->data));
14472                   return FALSE;
14473                 }
14474             }
14475         }
14476       else
14477         {
14478           const GList *effects, *l;
14479
14480           /* otherwise, get the cumulative volume */
14481           effects = _clutter_meta_group_peek_metas (priv->effects);
14482           for (l = effects; l != NULL; l = l->next)
14483             if (!_clutter_effect_get_paint_volume (l->data, pv))
14484               {
14485                 clutter_paint_volume_free (pv);
14486                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14487                               "Effect (%s) failed to report a volume",
14488                               _clutter_actor_get_debug_name (self),
14489                               _clutter_actor_meta_get_debug_name (l->data));
14490                 return FALSE;
14491               }
14492         }
14493     }
14494
14495   return TRUE;
14496 }
14497
14498 /* The public clutter_actor_get_paint_volume API returns a const
14499  * pointer since we return a pointer directly to the cached
14500  * PaintVolume associated with the actor and don't want the user to
14501  * inadvertently modify it, but for internal uses we sometimes need
14502  * access to the same PaintVolume but need to apply some book-keeping
14503  * modifications to it so we don't want a const pointer.
14504  */
14505 static ClutterPaintVolume *
14506 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
14507 {
14508   ClutterActorPrivate *priv;
14509
14510   priv = self->priv;
14511
14512   if (priv->paint_volume_valid)
14513     clutter_paint_volume_free (&priv->paint_volume);
14514
14515   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
14516     {
14517       priv->paint_volume_valid = TRUE;
14518       return &priv->paint_volume;
14519     }
14520   else
14521     {
14522       priv->paint_volume_valid = FALSE;
14523       return NULL;
14524     }
14525 }
14526
14527 /**
14528  * clutter_actor_get_paint_volume:
14529  * @self: a #ClutterActor
14530  *
14531  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
14532  * when a paint volume can't be determined.
14533  *
14534  * The paint volume is defined as the 3D space occupied by an actor
14535  * when being painted.
14536  *
14537  * This function will call the <function>get_paint_volume()</function>
14538  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
14539  * should not usually care about overriding the default implementation,
14540  * unless they are, for instance: painting outside their allocation, or
14541  * actors with a depth factor (not in terms of #ClutterActor:depth but real
14542  * 3D depth).
14543  *
14544  * <note>2D actors overriding <function>get_paint_volume()</function>
14545  * ensure their volume has a depth of 0. (This will be true so long as
14546  * you don't call clutter_paint_volume_set_depth().)</note>
14547  *
14548  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
14549  *   or %NULL if no volume could be determined. The returned pointer
14550  *   is not guaranteed to be valid across multiple frames; if you want
14551  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
14552  *
14553  * Since: 1.6
14554  */
14555 const ClutterPaintVolume *
14556 clutter_actor_get_paint_volume (ClutterActor *self)
14557 {
14558   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14559
14560   return _clutter_actor_get_paint_volume_mutable (self);
14561 }
14562
14563 /**
14564  * clutter_actor_get_transformed_paint_volume:
14565  * @self: a #ClutterActor
14566  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
14567  *    (or %NULL for the stage)
14568  *
14569  * Retrieves the 3D paint volume of an actor like
14570  * clutter_actor_get_paint_volume() does (Please refer to the
14571  * documentation of clutter_actor_get_paint_volume() for more
14572  * details.) and it additionally transforms the paint volume into the
14573  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
14574  * is passed for @relative_to_ancestor)
14575  *
14576  * This can be used by containers that base their paint volume on
14577  * the volume of their children. Such containers can query the
14578  * transformed paint volume of all of its children and union them
14579  * together using clutter_paint_volume_union().
14580  *
14581  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
14582  *   or %NULL if no volume could be determined. The returned pointer is
14583  *   not guaranteed to be valid across multiple frames; if you wish to
14584  *   keep it, you will have to copy it using clutter_paint_volume_copy().
14585  *
14586  * Since: 1.6
14587  */
14588 const ClutterPaintVolume *
14589 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
14590                                             ClutterActor *relative_to_ancestor)
14591 {
14592   const ClutterPaintVolume *volume;
14593   ClutterActor *stage;
14594   ClutterPaintVolume *transformed_volume;
14595
14596   stage = _clutter_actor_get_stage_internal (self);
14597   if (G_UNLIKELY (stage == NULL))
14598     return NULL;
14599
14600   if (relative_to_ancestor == NULL)
14601     relative_to_ancestor = stage;
14602
14603   volume = clutter_actor_get_paint_volume (self);
14604   if (volume == NULL)
14605     return NULL;
14606
14607   transformed_volume =
14608     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
14609
14610   _clutter_paint_volume_copy_static (volume, transformed_volume);
14611
14612   _clutter_paint_volume_transform_relative (transformed_volume,
14613                                             relative_to_ancestor);
14614
14615   return transformed_volume;
14616 }
14617
14618 /**
14619  * clutter_actor_get_paint_box:
14620  * @self: a #ClutterActor
14621  * @box: (out): return location for a #ClutterActorBox
14622  *
14623  * Retrieves the paint volume of the passed #ClutterActor, and
14624  * transforms it into a 2D bounding box in stage coordinates.
14625  *
14626  * This function is useful to determine the on screen area occupied by
14627  * the actor. The box is only an approximation and may often be
14628  * considerably larger due to the optimizations used to calculate the
14629  * box. The box is never smaller though, so it can reliably be used
14630  * for culling.
14631  *
14632  * There are times when a 2D paint box can't be determined, e.g.
14633  * because the actor isn't yet parented under a stage or because
14634  * the actor is unable to determine a paint volume.
14635  *
14636  * Return value: %TRUE if a 2D paint box could be determined, else
14637  * %FALSE.
14638  *
14639  * Since: 1.6
14640  */
14641 gboolean
14642 clutter_actor_get_paint_box (ClutterActor    *self,
14643                              ClutterActorBox *box)
14644 {
14645   ClutterActor *stage;
14646   ClutterPaintVolume *pv;
14647
14648   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14649   g_return_val_if_fail (box != NULL, FALSE);
14650
14651   stage = _clutter_actor_get_stage_internal (self);
14652   if (G_UNLIKELY (!stage))
14653     return FALSE;
14654
14655   pv = _clutter_actor_get_paint_volume_mutable (self);
14656   if (G_UNLIKELY (!pv))
14657     return FALSE;
14658
14659   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
14660
14661   return TRUE;
14662 }
14663
14664 /**
14665  * clutter_actor_has_overlaps:
14666  * @self: A #ClutterActor
14667  *
14668  * Asks the actor's implementation whether it may contain overlapping
14669  * primitives.
14670  *
14671  * For example; Clutter may use this to determine whether the painting
14672  * should be redirected to an offscreen buffer to correctly implement
14673  * the opacity property.
14674  *
14675  * Custom actors can override the default response by implementing the
14676  * #ClutterActor <function>has_overlaps</function> virtual function. See
14677  * clutter_actor_set_offscreen_redirect() for more information.
14678  *
14679  * Return value: %TRUE if the actor may have overlapping primitives, and
14680  *   %FALSE otherwise
14681  *
14682  * Since: 1.8
14683  */
14684 gboolean
14685 clutter_actor_has_overlaps (ClutterActor *self)
14686 {
14687   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14688
14689   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
14690 }
14691
14692 /**
14693  * clutter_actor_has_effects:
14694  * @self: A #ClutterActor
14695  *
14696  * Returns whether the actor has any effects applied.
14697  *
14698  * Return value: %TRUE if the actor has any effects,
14699  *   %FALSE otherwise
14700  *
14701  * Since: 1.10
14702  */
14703 gboolean
14704 clutter_actor_has_effects (ClutterActor *self)
14705 {
14706   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14707
14708   if (self->priv->effects == NULL)
14709     return FALSE;
14710
14711   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
14712 }
14713
14714 /**
14715  * clutter_actor_has_constraints:
14716  * @self: A #ClutterActor
14717  *
14718  * Returns whether the actor has any constraints applied.
14719  *
14720  * Return value: %TRUE if the actor has any constraints,
14721  *   %FALSE otherwise
14722  *
14723  * Since: 1.10
14724  */
14725 gboolean
14726 clutter_actor_has_constraints (ClutterActor *self)
14727 {
14728   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14729
14730   return self->priv->constraints != NULL;
14731 }
14732
14733 /**
14734  * clutter_actor_has_actions:
14735  * @self: A #ClutterActor
14736  *
14737  * Returns whether the actor has any actions applied.
14738  *
14739  * Return value: %TRUE if the actor has any actions,
14740  *   %FALSE otherwise
14741  *
14742  * Since: 1.10
14743  */
14744 gboolean
14745 clutter_actor_has_actions (ClutterActor *self)
14746 {
14747   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14748
14749   return self->priv->actions != NULL;
14750 }
14751
14752 /**
14753  * clutter_actor_get_n_children:
14754  * @self: a #ClutterActor
14755  *
14756  * Retrieves the number of children of @self.
14757  *
14758  * Return value: the number of children of an actor
14759  *
14760  * Since: 1.10
14761  */
14762 gint
14763 clutter_actor_get_n_children (ClutterActor *self)
14764 {
14765   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14766
14767   return self->priv->n_children;
14768 }
14769
14770 /**
14771  * clutter_actor_get_child_at_index:
14772  * @self: a #ClutterActor
14773  * @index_: the position in the list of children
14774  *
14775  * Retrieves the actor at the given @index_ inside the list of
14776  * children of @self.
14777  *
14778  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
14779  *
14780  * Since: 1.10
14781  */
14782 ClutterActor *
14783 clutter_actor_get_child_at_index (ClutterActor *self,
14784                                   gint          index_)
14785 {
14786   ClutterActor *iter;
14787   int i;
14788
14789   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14790   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
14791
14792   for (iter = self->priv->first_child, i = 0;
14793        iter != NULL && i < index_;
14794        iter = iter->priv->next_sibling, i += 1)
14795     ;
14796
14797   return iter;
14798 }
14799
14800 /*< private >
14801  * _clutter_actor_foreach_child:
14802  * @actor: The actor whos children you want to iterate
14803  * @callback: The function to call for each child
14804  * @user_data: Private data to pass to @callback
14805  *
14806  * Calls a given @callback once for each child of the specified @actor and
14807  * passing the @user_data pointer each time.
14808  *
14809  * Return value: returns %TRUE if all children were iterated, else
14810  *    %FALSE if a callback broke out of iteration early.
14811  */
14812 gboolean
14813 _clutter_actor_foreach_child (ClutterActor           *self,
14814                               ClutterForeachCallback  callback,
14815                               gpointer                user_data)
14816 {
14817   ClutterActorPrivate *priv = self->priv;
14818   ClutterActor *iter;
14819   gboolean cont;
14820
14821   for (cont = TRUE, iter = priv->first_child;
14822        cont && iter != NULL;
14823        iter = iter->priv->next_sibling)
14824     {
14825       cont = callback (iter, user_data);
14826     }
14827
14828   return cont;
14829 }
14830
14831 /* For debugging purposes this gives us a simple way to print out
14832  * the scenegraph e.g in gdb using:
14833  * [|
14834  *   _clutter_actor_traverse (stage,
14835  *                            0,
14836  *                            _clutter_debug_print_actor_cb,
14837  *                            NULL,
14838  *                            NULL);
14839  * |]
14840  */
14841 ClutterActorTraverseVisitFlags
14842 _clutter_debug_print_actor_cb (ClutterActor *actor,
14843                                int depth,
14844                                void *user_data)
14845 {
14846   g_print ("%*s%s:%p\n",
14847            depth * 2, "",
14848            _clutter_actor_get_debug_name (actor),
14849            actor);
14850
14851   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14852 }
14853
14854 static void
14855 _clutter_actor_traverse_breadth (ClutterActor           *actor,
14856                                  ClutterTraverseCallback callback,
14857                                  gpointer                user_data)
14858 {
14859   GQueue *queue = g_queue_new ();
14860   ClutterActor dummy;
14861   int current_depth = 0;
14862
14863   g_queue_push_tail (queue, actor);
14864   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
14865
14866   while ((actor = g_queue_pop_head (queue)))
14867     {
14868       ClutterActorTraverseVisitFlags flags;
14869
14870       if (actor == &dummy)
14871         {
14872           current_depth++;
14873           g_queue_push_tail (queue, &dummy);
14874           continue;
14875         }
14876
14877       flags = callback (actor, current_depth, user_data);
14878       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14879         break;
14880       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14881         {
14882           ClutterActor *iter;
14883
14884           for (iter = actor->priv->first_child;
14885                iter != NULL;
14886                iter = iter->priv->next_sibling)
14887             {
14888               g_queue_push_tail (queue, iter);
14889             }
14890         }
14891     }
14892
14893   g_queue_free (queue);
14894 }
14895
14896 static ClutterActorTraverseVisitFlags
14897 _clutter_actor_traverse_depth (ClutterActor           *actor,
14898                                ClutterTraverseCallback before_children_callback,
14899                                ClutterTraverseCallback after_children_callback,
14900                                int                     current_depth,
14901                                gpointer                user_data)
14902 {
14903   ClutterActorTraverseVisitFlags flags;
14904
14905   flags = before_children_callback (actor, current_depth, user_data);
14906   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14907     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14908
14909   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14910     {
14911       ClutterActor *iter;
14912
14913       for (iter = actor->priv->first_child;
14914            iter != NULL;
14915            iter = iter->priv->next_sibling)
14916         {
14917           flags = _clutter_actor_traverse_depth (iter,
14918                                                  before_children_callback,
14919                                                  after_children_callback,
14920                                                  current_depth + 1,
14921                                                  user_data);
14922
14923           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14924             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14925         }
14926     }
14927
14928   if (after_children_callback)
14929     return after_children_callback (actor, current_depth, user_data);
14930   else
14931     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14932 }
14933
14934 /* _clutter_actor_traverse:
14935  * @actor: The actor to start traversing the graph from
14936  * @flags: These flags may affect how the traversal is done
14937  * @before_children_callback: A function to call before visiting the
14938  *   children of the current actor.
14939  * @after_children_callback: A function to call after visiting the
14940  *   children of the current actor. (Ignored if
14941  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
14942  * @user_data: The private data to pass to the callbacks
14943  *
14944  * Traverses the scenegraph starting at the specified @actor and
14945  * descending through all its children and its children's children.
14946  * For each actor traversed @before_children_callback and
14947  * @after_children_callback are called with the specified
14948  * @user_data, before and after visiting that actor's children.
14949  *
14950  * The callbacks can return flags that affect the ongoing traversal
14951  * such as by skipping over an actors children or bailing out of
14952  * any further traversing.
14953  */
14954 void
14955 _clutter_actor_traverse (ClutterActor              *actor,
14956                          ClutterActorTraverseFlags  flags,
14957                          ClutterTraverseCallback    before_children_callback,
14958                          ClutterTraverseCallback    after_children_callback,
14959                          gpointer                   user_data)
14960 {
14961   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
14962     _clutter_actor_traverse_breadth (actor,
14963                                      before_children_callback,
14964                                      user_data);
14965   else /* DEPTH_FIRST */
14966     _clutter_actor_traverse_depth (actor,
14967                                    before_children_callback,
14968                                    after_children_callback,
14969                                    0, /* start depth */
14970                                    user_data);
14971 }
14972
14973 static void
14974 on_layout_manager_changed (ClutterLayoutManager *manager,
14975                            ClutterActor         *self)
14976 {
14977   clutter_actor_queue_relayout (self);
14978 }
14979
14980 /**
14981  * clutter_actor_set_layout_manager:
14982  * @self: a #ClutterActor
14983  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
14984  *
14985  * Sets the #ClutterLayoutManager delegate object that will be used to
14986  * lay out the children of @self.
14987  *
14988  * The #ClutterActor will take a reference on the passed @manager which
14989  * will be released either when the layout manager is removed, or when
14990  * the actor is destroyed.
14991  *
14992  * Since: 1.10
14993  */
14994 void
14995 clutter_actor_set_layout_manager (ClutterActor         *self,
14996                                   ClutterLayoutManager *manager)
14997 {
14998   ClutterActorPrivate *priv;
14999
15000   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15001   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15002
15003   priv = self->priv;
15004
15005   if (priv->layout_manager != NULL)
15006     {
15007       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15008                                             G_CALLBACK (on_layout_manager_changed),
15009                                             self);
15010       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15011       g_object_unref (priv->layout_manager);
15012     }
15013
15014   priv->layout_manager = manager;
15015
15016   if (priv->layout_manager != NULL)
15017     {
15018       g_object_ref_sink (priv->layout_manager);
15019       clutter_layout_manager_set_container (priv->layout_manager,
15020                                             CLUTTER_CONTAINER (self));
15021       g_signal_connect (priv->layout_manager, "layout-changed",
15022                         G_CALLBACK (on_layout_manager_changed),
15023                         self);
15024     }
15025
15026   clutter_actor_queue_relayout (self);
15027
15028   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15029 }
15030
15031 /**
15032  * clutter_actor_get_layout_manager:
15033  * @self: a #ClutterActor
15034  *
15035  * Retrieves the #ClutterLayoutManager used by @self.
15036  *
15037  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15038  *   or %NULL
15039  *
15040  * Since: 1.10
15041  */
15042 ClutterLayoutManager *
15043 clutter_actor_get_layout_manager (ClutterActor *self)
15044 {
15045   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15046
15047   return self->priv->layout_manager;
15048 }
15049
15050 static const ClutterLayoutInfo default_layout_info = {
15051   0.f,                          /* fixed-x */
15052   0.f,                          /* fixed-y */
15053   { 0, 0, 0, 0 },               /* margin */
15054   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15055   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15056   0.f, 0.f,                     /* min_width, natural_width */
15057   0.f, 0.f,                     /* natual_width, natural_height */
15058 };
15059
15060 static void
15061 layout_info_free (gpointer data)
15062 {
15063   if (G_LIKELY (data != NULL))
15064     g_slice_free (ClutterLayoutInfo, data);
15065 }
15066
15067 /*< private >
15068  * _clutter_actor_get_layout_info:
15069  * @self: a #ClutterActor
15070  *
15071  * Retrieves a pointer to the ClutterLayoutInfo structure.
15072  *
15073  * If the actor does not have a ClutterLayoutInfo associated to it, one
15074  * will be created and initialized to the default values.
15075  *
15076  * This function should be used for setters.
15077  *
15078  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15079  * instead.
15080  *
15081  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15082  */
15083 ClutterLayoutInfo *
15084 _clutter_actor_get_layout_info (ClutterActor *self)
15085 {
15086   ClutterLayoutInfo *retval;
15087
15088   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15089   if (retval == NULL)
15090     {
15091       retval = g_slice_new (ClutterLayoutInfo);
15092
15093       *retval = default_layout_info;
15094
15095       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15096                                retval,
15097                                layout_info_free);
15098     }
15099
15100   return retval;
15101 }
15102
15103 /*< private >
15104  * _clutter_actor_get_layout_info_or_defaults:
15105  * @self: a #ClutterActor
15106  *
15107  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15108  *
15109  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15110  * then the default structure will be returned.
15111  *
15112  * This function should only be used for getters.
15113  *
15114  * Return value: a const pointer to the ClutterLayoutInfo structure
15115  */
15116 const ClutterLayoutInfo *
15117 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15118 {
15119   const ClutterLayoutInfo *info;
15120
15121   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15122   if (info == NULL)
15123     return &default_layout_info;
15124
15125   return info;
15126 }
15127
15128 /**
15129  * clutter_actor_set_x_align:
15130  * @self: a #ClutterActor
15131  * @x_align: the horizontal alignment policy
15132  *
15133  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15134  * actor received extra horizontal space.
15135  *
15136  * See also the #ClutterActor:x-align property.
15137  *
15138  * Since: 1.10
15139  */
15140 void
15141 clutter_actor_set_x_align (ClutterActor      *self,
15142                            ClutterActorAlign  x_align)
15143 {
15144   ClutterLayoutInfo *info;
15145
15146   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15147
15148   info = _clutter_actor_get_layout_info (self);
15149
15150   if (info->x_align != x_align)
15151     {
15152       info->x_align = x_align;
15153
15154       clutter_actor_queue_relayout (self);
15155
15156       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15157     }
15158 }
15159
15160 /**
15161  * clutter_actor_get_x_align:
15162  * @self: a #ClutterActor
15163  *
15164  * Retrieves the horizontal alignment policy set using
15165  * clutter_actor_set_x_align().
15166  *
15167  * Return value: the horizontal alignment policy.
15168  *
15169  * Since: 1.10
15170  */
15171 ClutterActorAlign
15172 clutter_actor_get_x_align (ClutterActor *self)
15173 {
15174   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15175
15176   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15177 }
15178
15179 /**
15180  * clutter_actor_set_y_align:
15181  * @self: a #ClutterActor
15182  * @y_align: the vertical alignment policy
15183  *
15184  * Sets the vertical alignment policy of a #ClutterActor, in case the
15185  * actor received extra vertical space.
15186  *
15187  * See also the #ClutterActor:y-align property.
15188  *
15189  * Since: 1.10
15190  */
15191 void
15192 clutter_actor_set_y_align (ClutterActor      *self,
15193                            ClutterActorAlign  y_align)
15194 {
15195   ClutterLayoutInfo *info;
15196
15197   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15198
15199   info = _clutter_actor_get_layout_info (self);
15200
15201   if (info->y_align != y_align)
15202     {
15203       info->y_align = y_align;
15204
15205       clutter_actor_queue_relayout (self);
15206
15207       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15208     }
15209 }
15210
15211 /**
15212  * clutter_actor_get_y_align:
15213  * @self: a #ClutterActor
15214  *
15215  * Retrieves the vertical alignment policy set using
15216  * clutter_actor_set_y_align().
15217  *
15218  * Return value: the vertical alignment policy.
15219  *
15220  * Since: 1.10
15221  */
15222 ClutterActorAlign
15223 clutter_actor_get_y_align (ClutterActor *self)
15224 {
15225   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15226
15227   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15228 }
15229
15230
15231 /**
15232  * clutter_margin_new:
15233  *
15234  * Creates a new #ClutterMargin.
15235  *
15236  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15237  *   clutter_margin_free() to free the resources associated with it when
15238  *   done.
15239  *
15240  * Since: 1.10
15241  */
15242 ClutterMargin *
15243 clutter_margin_new (void)
15244 {
15245   return g_slice_new0 (ClutterMargin);
15246 }
15247
15248 /**
15249  * clutter_margin_copy:
15250  * @margin_: a #ClutterMargin
15251  *
15252  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15253  * the newly created structure.
15254  *
15255  * Return value: (transfer full): a copy of the #ClutterMargin.
15256  *
15257  * Since: 1.10
15258  */
15259 ClutterMargin *
15260 clutter_margin_copy (const ClutterMargin *margin_)
15261 {
15262   if (G_LIKELY (margin_ != NULL))
15263     return g_slice_dup (ClutterMargin, margin_);
15264
15265   return NULL;
15266 }
15267
15268 /**
15269  * clutter_margin_free:
15270  * @margin_: a #ClutterMargin
15271  *
15272  * Frees the resources allocated by clutter_margin_new() and
15273  * clutter_margin_copy().
15274  *
15275  * Since: 1.10
15276  */
15277 void
15278 clutter_margin_free (ClutterMargin *margin_)
15279 {
15280   if (G_LIKELY (margin_ != NULL))
15281     g_slice_free (ClutterMargin, margin_);
15282 }
15283
15284 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15285                      clutter_margin_copy,
15286                      clutter_margin_free)
15287
15288 /**
15289  * clutter_actor_set_margin:
15290  * @self: a #ClutterActor
15291  * @margin: a #ClutterMargin
15292  *
15293  * Sets all the components of the margin of a #ClutterActor.
15294  *
15295  * Since: 1.10
15296  */
15297 void
15298 clutter_actor_set_margin (ClutterActor        *self,
15299                           const ClutterMargin *margin)
15300 {
15301   ClutterLayoutInfo *info;
15302   gboolean changed;
15303   GObject *obj;
15304
15305   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15306   g_return_if_fail (margin != NULL);
15307
15308   obj = G_OBJECT (self);
15309   changed = FALSE;
15310
15311   g_object_freeze_notify (obj);
15312
15313   info = _clutter_actor_get_layout_info (self);
15314
15315   if (info->margin.top != margin->top)
15316     {
15317       info->margin.top = margin->top;
15318       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15319       changed = TRUE;
15320     }
15321
15322   if (info->margin.right != margin->right)
15323     {
15324       info->margin.right = margin->right;
15325       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15326       changed = TRUE;
15327     }
15328
15329   if (info->margin.bottom != margin->bottom)
15330     {
15331       info->margin.bottom = margin->bottom;
15332       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15333       changed = TRUE;
15334     }
15335
15336   if (info->margin.left != margin->left)
15337     {
15338       info->margin.left = margin->left;
15339       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15340       changed = TRUE;
15341     }
15342
15343   if (changed)
15344     clutter_actor_queue_relayout (self);
15345
15346   g_object_thaw_notify (obj);
15347 }
15348
15349 /**
15350  * clutter_actor_get_margin:
15351  * @self: a #ClutterActor
15352  * @margin: (out caller-allocates): return location for a #ClutterMargin
15353  *
15354  * Retrieves all the components of the margin of a #ClutterActor.
15355  *
15356  * Since: 1.10
15357  */
15358 void
15359 clutter_actor_get_margin (ClutterActor  *self,
15360                           ClutterMargin *margin)
15361 {
15362   const ClutterLayoutInfo *info;
15363
15364   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15365   g_return_if_fail (margin != NULL);
15366
15367   info = _clutter_actor_get_layout_info_or_defaults (self);
15368
15369   *margin = info->margin;
15370 }
15371
15372 /**
15373  * clutter_actor_set_margin_top:
15374  * @self: a #ClutterActor
15375  * @margin: the top margin
15376  *
15377  * Sets the margin from the top of a #ClutterActor.
15378  *
15379  * Since: 1.10
15380  */
15381 void
15382 clutter_actor_set_margin_top (ClutterActor *self,
15383                               gfloat        margin)
15384 {
15385   ClutterLayoutInfo *info;
15386
15387   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15388   g_return_if_fail (margin >= 0.f);
15389
15390   info = _clutter_actor_get_layout_info (self);
15391
15392   if (info->margin.top == margin)
15393     return;
15394
15395   info->margin.top = margin;
15396
15397   clutter_actor_queue_relayout (self);
15398
15399   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15400 }
15401
15402 /**
15403  * clutter_actor_get_margin_top:
15404  * @self: a #ClutterActor
15405  *
15406  * Retrieves the top margin of a #ClutterActor.
15407  *
15408  * Return value: the top margin
15409  *
15410  * Since: 1.10
15411  */
15412 gfloat
15413 clutter_actor_get_margin_top (ClutterActor *self)
15414 {
15415   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15416
15417   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15418 }
15419
15420 /**
15421  * clutter_actor_set_margin_bottom:
15422  * @self: a #ClutterActor
15423  * @margin: the bottom margin
15424  *
15425  * Sets the margin from the bottom of a #ClutterActor.
15426  *
15427  * Since: 1.10
15428  */
15429 void
15430 clutter_actor_set_margin_bottom (ClutterActor *self,
15431                                  gfloat        margin)
15432 {
15433   ClutterLayoutInfo *info;
15434
15435   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15436   g_return_if_fail (margin >= 0.f);
15437
15438   info = _clutter_actor_get_layout_info (self);
15439
15440   if (info->margin.bottom == margin)
15441     return;
15442
15443   info->margin.bottom = margin;
15444
15445   clutter_actor_queue_relayout (self);
15446
15447   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
15448 }
15449
15450 /**
15451  * clutter_actor_get_margin_bottom:
15452  * @self: a #ClutterActor
15453  *
15454  * Retrieves the bottom margin of a #ClutterActor.
15455  *
15456  * Return value: the bottom margin
15457  *
15458  * Since: 1.10
15459  */
15460 gfloat
15461 clutter_actor_get_margin_bottom (ClutterActor *self)
15462 {
15463   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15464
15465   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
15466 }
15467
15468 /**
15469  * clutter_actor_set_margin_left:
15470  * @self: a #ClutterActor
15471  * @margin: the left margin
15472  *
15473  * Sets the margin from the left of a #ClutterActor.
15474  *
15475  * Since: 1.10
15476  */
15477 void
15478 clutter_actor_set_margin_left (ClutterActor *self,
15479                                gfloat        margin)
15480 {
15481   ClutterLayoutInfo *info;
15482
15483   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15484   g_return_if_fail (margin >= 0.f);
15485
15486   info = _clutter_actor_get_layout_info (self);
15487
15488   if (info->margin.left == margin)
15489     return;
15490
15491   info->margin.left = margin;
15492
15493   clutter_actor_queue_relayout (self);
15494
15495   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
15496 }
15497
15498 /**
15499  * clutter_actor_get_margin_left:
15500  * @self: a #ClutterActor
15501  *
15502  * Retrieves the left margin of a #ClutterActor.
15503  *
15504  * Return value: the left margin
15505  *
15506  * Since: 1.10
15507  */
15508 gfloat
15509 clutter_actor_get_margin_left (ClutterActor *self)
15510 {
15511   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15512
15513   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
15514 }
15515
15516 /**
15517  * clutter_actor_set_margin_right:
15518  * @self: a #ClutterActor
15519  * @margin: the right margin
15520  *
15521  * Sets the margin from the right of a #ClutterActor.
15522  *
15523  * Since: 1.10
15524  */
15525 void
15526 clutter_actor_set_margin_right (ClutterActor *self,
15527                                 gfloat        margin)
15528 {
15529   ClutterLayoutInfo *info;
15530
15531   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15532   g_return_if_fail (margin >= 0.f);
15533
15534   info = _clutter_actor_get_layout_info (self);
15535
15536   if (info->margin.right == margin)
15537     return;
15538
15539   info->margin.right = margin;
15540
15541   clutter_actor_queue_relayout (self);
15542
15543   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
15544 }
15545
15546 /**
15547  * clutter_actor_get_margin_right:
15548  * @self: a #ClutterActor
15549  *
15550  * Retrieves the right margin of a #ClutterActor.
15551  *
15552  * Return value: the right margin
15553  *
15554  * Since: 1.10
15555  */
15556 gfloat
15557 clutter_actor_get_margin_right (ClutterActor *self)
15558 {
15559   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15560
15561   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
15562 }
15563
15564 /**
15565  * clutter_actor_set_background_color:
15566  * @self: a #ClutterActor
15567  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
15568  *  set color
15569  *
15570  * Sets the background color of a #ClutterActor.
15571  *
15572  * The background color will be used to cover the whole allocation of the
15573  * actor. The default background color of an actor is transparent.
15574  *
15575  * To check whether an actor has a background color, you can use the
15576  * #ClutterActor:background-color-set actor property.
15577  *
15578  * Since: 1.10
15579  */
15580 void
15581 clutter_actor_set_background_color (ClutterActor       *self,
15582                                     const ClutterColor *color)
15583 {
15584   ClutterActorPrivate *priv;
15585
15586   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15587
15588   priv = self->priv;
15589
15590   if (color == NULL)
15591     {
15592       priv->bg_color_set = FALSE;
15593       g_object_notify_by_pspec (G_OBJECT (self),
15594                                 obj_props[PROP_BACKGROUND_COLOR_SET]);
15595       return;
15596     }
15597
15598   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
15599     return;
15600
15601   priv->bg_color = *color;
15602   priv->bg_color_set = TRUE;
15603
15604   clutter_actor_queue_redraw (self);
15605
15606   g_object_notify_by_pspec (G_OBJECT (self),
15607                             obj_props[PROP_BACKGROUND_COLOR_SET]);
15608   g_object_notify_by_pspec (G_OBJECT (self),
15609                             obj_props[PROP_BACKGROUND_COLOR]);
15610 }
15611
15612 /**
15613  * clutter_actor_get_background_color:
15614  * @self: a #ClutterActor
15615  * @color: (out caller-allocates): return location for a #ClutterColor
15616  *
15617  * Retrieves the color set using clutter_actor_set_background_color().
15618  *
15619  * Since: 1.10
15620  */
15621 void
15622 clutter_actor_get_background_color (ClutterActor *self,
15623                                     ClutterColor *color)
15624 {
15625   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15626   g_return_if_fail (color != NULL);
15627
15628   *color = self->priv->bg_color;
15629 }
15630
15631 /**
15632  * clutter_actor_get_previous_sibling:
15633  * @self: a #ClutterActor
15634  *
15635  * Retrieves the sibling of @self that comes before it in the list
15636  * of children of @self's parent.
15637  *
15638  * The returned pointer is only valid until the scene graph changes; it
15639  * is not safe to modify the list of children of @self while iterating
15640  * it.
15641  *
15642  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15643  *
15644  * Since: 1.10
15645  */
15646 ClutterActor *
15647 clutter_actor_get_previous_sibling (ClutterActor *self)
15648 {
15649   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15650
15651   return self->priv->prev_sibling;
15652 }
15653
15654 /**
15655  * clutter_actor_get_next_sibling:
15656  * @self: a #ClutterActor
15657  *
15658  * Retrieves the sibling of @self that comes after it in the list
15659  * of children of @self's parent.
15660  *
15661  * The returned pointer is only valid until the scene graph changes; it
15662  * is not safe to modify the list of children of @self while iterating
15663  * it.
15664  *
15665  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15666  *
15667  * Since: 1.10
15668  */
15669 ClutterActor *
15670 clutter_actor_get_next_sibling (ClutterActor *self)
15671 {
15672   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15673
15674   return self->priv->next_sibling;
15675 }
15676
15677 /**
15678  * clutter_actor_get_first_child:
15679  * @self: a #ClutterActor
15680  *
15681  * Retrieves the first child of @self.
15682  *
15683  * The returned pointer is only valid until the scene graph changes; it
15684  * is not safe to modify the list of children of @self while iterating
15685  * it.
15686  *
15687  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15688  *
15689  * Since: 1.10
15690  */
15691 ClutterActor *
15692 clutter_actor_get_first_child (ClutterActor *self)
15693 {
15694   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15695
15696   return self->priv->first_child;
15697 }
15698
15699 /**
15700  * clutter_actor_get_last_child:
15701  * @self: a #ClutterActor
15702  *
15703  * Retrieves the last child of @self.
15704  *
15705  * The returned pointer is only valid until the scene graph changes; it
15706  * is not safe to modify the list of children of @self while iterating
15707  * it.
15708  *
15709  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15710  *
15711  * Since: 1.10
15712  */
15713 ClutterActor *
15714 clutter_actor_get_last_child (ClutterActor *self)
15715 {
15716   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15717
15718   return self->priv->last_child;
15719 }
15720
15721 /* easy way to have properly named fields instead of the dummy ones
15722  * we use in the public structure
15723  */
15724 typedef struct _RealActorIter
15725 {
15726   ClutterActor *root;           /* dummy1 */
15727   ClutterActor *current;        /* dummy2 */
15728   gpointer padding_1;           /* dummy3 */
15729   gint age;                     /* dummy4 */
15730   gpointer padding_2;           /* dummy5 */
15731 } RealActorIter;
15732
15733 /**
15734  * clutter_actor_iter_init:
15735  * @iter: a #ClutterActorIter
15736  * @root: a #ClutterActor
15737  *
15738  * Initializes a #ClutterActorIter, which can then be used to iterate
15739  * efficiently over a section of the scene graph, and associates it
15740  * with @root.
15741  *
15742  * Modifying the scene graph section that contains @root will invalidate
15743  * the iterator.
15744  *
15745  * |[
15746  *   ClutterActorIter iter;
15747  *   ClutterActor *child;
15748  *
15749  *   clutter_actor_iter_init (&iter, container);
15750  *   while (clutter_actor_iter_next (&iter, &child))
15751  *     {
15752  *       /&ast; do something with child &ast;/
15753  *     }
15754  * ]|
15755  *
15756  * Since: 1.10
15757  */
15758 void
15759 clutter_actor_iter_init (ClutterActorIter *iter,
15760                          ClutterActor     *root)
15761 {
15762   RealActorIter *ri = (RealActorIter *) iter;
15763
15764   g_return_if_fail (iter != NULL);
15765   g_return_if_fail (CLUTTER_IS_ACTOR (root));
15766
15767   ri->root = root;
15768   ri->current = NULL;
15769   ri->age = root->priv->age;
15770 }
15771
15772 /**
15773  * clutter_actor_iter_next:
15774  * @iter: a #ClutterActorIter
15775  * @child: (out): return location for a #ClutterActor
15776  *
15777  * Advances the @iter and retrieves the next child of the root #ClutterActor
15778  * that was used to initialize the #ClutterActorIterator.
15779  *
15780  * If the iterator can advance, this function returns %TRUE and sets the
15781  * @child argument.
15782  *
15783  * If the iterator cannot advance, this function returns %FALSE, and
15784  * the contents of @child are undefined.
15785  *
15786  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15787  *
15788  * Since: 1.10
15789  */
15790 gboolean
15791 clutter_actor_iter_next (ClutterActorIter  *iter,
15792                          ClutterActor     **child)
15793 {
15794   RealActorIter *ri = (RealActorIter *) iter;
15795
15796   g_return_val_if_fail (iter != NULL, FALSE);
15797   g_return_val_if_fail (ri->root != NULL, FALSE);
15798 #ifndef G_DISABLE_ASSERT
15799   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15800 #endif
15801
15802   if (ri->current == NULL)
15803     ri->current = ri->root->priv->first_child;
15804   else
15805     ri->current = ri->current->priv->next_sibling;
15806
15807   if (child != NULL)
15808     *child = ri->current;
15809
15810   return ri->current != NULL;
15811 }
15812
15813 /**
15814  * clutter_actor_iter_prev:
15815  * @iter: a #ClutterActorIter
15816  * @child: (out): return location for a #ClutterActor
15817  *
15818  * Advances the @iter and retrieves the previous child of the root
15819  * #ClutterActor that was used to initialize the #ClutterActorIterator.
15820  *
15821  * If the iterator can advance, this function returns %TRUE and sets the
15822  * @child argument.
15823  *
15824  * If the iterator cannot advance, this function returns %FALSE, and
15825  * the contents of @child are undefined.
15826  *
15827  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15828  *
15829  * Since: 1.10
15830  */
15831 gboolean
15832 clutter_actor_iter_prev (ClutterActorIter  *iter,
15833                          ClutterActor     **child)
15834 {
15835   RealActorIter *ri = (RealActorIter *) iter;
15836
15837   g_return_val_if_fail (iter != NULL, FALSE);
15838   g_return_val_if_fail (ri->root != NULL, FALSE);
15839 #ifndef G_DISABLE_ASSERT
15840   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15841 #endif
15842
15843   if (ri->current == NULL)
15844     ri->current = ri->root->priv->last_child;
15845   else
15846     ri->current = ri->current->priv->prev_sibling;
15847
15848   if (child != NULL)
15849     *child = ri->current;
15850
15851   return ri->current != NULL;
15852 }
15853
15854 /**
15855  * clutter_actor_iter_remove:
15856  * @iter: a #ClutterActorIter
15857  *
15858  * Safely removes the #ClutterActor currently pointer to by the iterator
15859  * from its parent.
15860  *
15861  * This function can only be called after clutter_actor_iter_next() or
15862  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15863  * than once for the same actor.
15864  *
15865  * This function will call clutter_actor_remove_child() internally.
15866  *
15867  * Since: 1.10
15868  */
15869 void
15870 clutter_actor_iter_remove (ClutterActorIter *iter)
15871 {
15872   RealActorIter *ri = (RealActorIter *) iter;
15873   ClutterActor *cur;
15874
15875   g_return_if_fail (iter != NULL);
15876   g_return_if_fail (ri->root != NULL);
15877 #ifndef G_DISABLE_ASSERT
15878   g_return_if_fail (ri->age == ri->root->priv->age);
15879 #endif
15880   g_return_if_fail (ri->current != NULL);
15881
15882   cur = ri->current;
15883
15884   if (cur != NULL)
15885     {
15886       ri->current = cur->priv->prev_sibling;
15887
15888       clutter_actor_remove_child_internal (ri->root, cur,
15889                                            REMOVE_CHILD_DEFAULT_FLAGS);
15890
15891       ri->age += 1;
15892     }
15893 }
15894
15895 /**
15896  * clutter_actor_iter_destroy:
15897  * @iter: a #ClutterActorIter
15898  *
15899  * Safely destroys the #ClutterActor currently pointer to by the iterator
15900  * from its parent.
15901  *
15902  * This function can only be called after clutter_actor_iter_next() or
15903  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15904  * than once for the same actor.
15905  *
15906  * This function will call clutter_actor_destroy() internally.
15907  *
15908  * Since: 1.10
15909  */
15910 void
15911 clutter_actor_iter_destroy (ClutterActorIter *iter)
15912 {
15913   RealActorIter *ri = (RealActorIter *) iter;
15914   ClutterActor *cur;
15915
15916   g_return_if_fail (iter != NULL);
15917   g_return_if_fail (ri->root != NULL);
15918 #ifndef G_DISABLE_ASSERT
15919   g_return_if_fail (ri->age == ri->root->priv->age);
15920 #endif
15921   g_return_if_fail (ri->current != NULL);
15922
15923   cur = ri->current;
15924
15925   if (cur != NULL)
15926     {
15927       ri->current = cur->priv->prev_sibling;
15928
15929       clutter_actor_destroy (cur);
15930
15931       ri->age += 1;
15932     }
15933 }