ClutterActor: clear redraw entry before emitting signals
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: Base abstract class for all visual stage actors.
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-events">
119  *   <title>Handling events on an actor</title>
120  *   <para>A #ClutterActor can receive and handle input device events, for
121  *   instance pointer events and key events, as long as its
122  *   #ClutterActor:reactive property is set to %TRUE.</para>
123  *   <para>Once an actor has been determined to be the source of an event,
124  *   Clutter will traverse the scene graph from the top-level actor towards the
125  *   event source, emitting the #ClutterActor::captured-event signal on each
126  *   ancestor until it reaches the source; this phase is also called
127  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
128  *   stopped, the graph is walked backwards, from the source actor to the
129  *   top-level, and the #ClutterActor::event signal, along with other event
130  *   signals if needed, is emitted; this phase is also called <emphasis>the
131  *   bubble phase</emphasis>. At any point of the signal emission, signal
132  *   handlers can stop the propagation through the scene graph by returning
133  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
134  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
135  * </refsect2>
136  *
137  * <refsect2 id="ClutterActor-subclassing">
138  *   <title>Implementing an actor</title>
139  *   <para>Careful consideration should be given when deciding to implement
140  *   a #ClutterActor sub-class. It is generally recommended to implement a
141  *   sub-class of #ClutterActor only for actors that should be used as leaf
142  *   nodes of a scene graph.</para>
143  *   <para>If your actor should be painted in a custom way, you should
144  *   override the #ClutterActor::paint signal class handler. You can either
145  *   opt to chain up to the parent class implementation or decide to fully
146  *   override the default paint implementation; Clutter will set up the
147  *   transformations and clip regions prior to emitting the #ClutterActor::paint
148  *   signal.</para>
149  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
150  *   #ClutterActorClass.get_preferred_height() virtual functions it is
151  *   possible to change or provide the preferred size of an actor; similarly,
152  *   by overriding the #ClutterActorClass.allocate() virtual function it is
153  *   possible to control the layout of the children of an actor. Make sure to
154  *   always chain up to the parent implementation of the
155  *   #ClutterActorClass.allocate() virtual function.</para>
156  *   <para>In general, it is strongly encouraged to use delegation and
157  *   composition instead of direct subclassing.</para>
158  * </refsect2>
159  *
160  * <refsect2 id="ClutterActor-script">
161  *   <title>ClutterActor custom properties for #ClutterScript</title>
162  *   <para>#ClutterActor defines a custom "rotation" property which
163  *   allows a short-hand description of the rotations to be applied
164  *   to an actor.</para>
165  *   <para>The syntax of the "rotation" property is the following:</para>
166  *   <informalexample>
167  *     <programlisting>
168  * "rotation" : [
169  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
170  * ]
171  *     </programlisting>
172  *   </informalexample>
173  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
174  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
175  *   floating point value representing the rotation angle on the given axis,
176  *   in degrees.</para>
177  *   <para>The <emphasis>center</emphasis> array is optional, and if present
178  *   it must contain the center of rotation as described by two coordinates:
179  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
180  *   "z-axis".</para>
181  *   <para>#ClutterActor will also parse every positional and dimensional
182  *   property defined as a string through clutter_units_from_string(); you
183  *   should read the documentation for the #ClutterUnits parser format for
184  *   the valid units and syntax.</para>
185  * </refsect2>
186  *
187  * <refsect2 id="ClutterActor-animating">
188  *   <title>Custom animatable properties</title>
189  *   <para>#ClutterActor allows accessing properties of #ClutterAction
190  *   and #ClutterConstraint instances associated to an actor instance
191  *   for animation purposes.</para>
192  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
193  *   property it is necessary to set the #ClutterActorMeta:name property on the
194  *   given action or constraint.</para>
195  *   <para>The property can be accessed using the following syntax:</para>
196  *   <informalexample>
197  *     <programlisting>
198  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
199  *     </programlisting>
200  *   </informalexample>
201  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
202  *   <para>The <emphasis>section</emphasis> fragment can be one between
203  *   "actions", "constraints" and "effects".</para>
204  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
205  *   action or constraint, as specified by the #ClutterActorMeta:name
206  *   property.</para>
207  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
208  *   action or constraint property to be animated.</para>
209  *   <para>The example below animates a #ClutterBindConstraint applied to an
210  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
211  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
212  *   its initial state is fully transparent and overlapping the actor to
213  *   which is bound to. </para>
214  *   <informalexample><programlisting>
215  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
216  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
217  * clutter_actor_add_constraint (rect, constraint);
218  *
219  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
220  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
221  * clutter_actor_add_constraint (rect, constraint);
222  *
223  * clutter_actor_set_reactive (rect, TRUE);
224  * clutter_actor_set_opacity (rect, 0);
225  *
226  * g_signal_connect (rect, "button-press-event",
227  *                   G_CALLBACK (on_button_press),
228  *                   NULL);
229  *   </programlisting></informalexample>
230  *   <para>On button press, the rectangle "slides" from behind the actor to
231  *   which is bound to, using the #ClutterBindConstraint:offset property and
232  *   the #ClutterActor:opacity property.</para>
233  *   <informalexample><programlisting>
234  * float new_offset = clutter_actor_get_width (origin) + h_padding;
235  *
236  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
237  *                        "opacity", 255,
238  *                        "@constraints.bind-x.offset", new_offset,
239  *                        NULL);
240  *   </programlisting></informalexample>
241  * </refsect2>
242  */
243
244 /**
245  * CLUTTER_ACTOR_IS_MAPPED:
246  * @a: a #ClutterActor
247  *
248  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
249  *
250  * The mapped state is set when the actor is visible and all its parents up
251  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
252  *
253  * This check can be used to see if an actor is going to be painted, as only
254  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
255  *
256  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
257  * not be checked directly; instead, the recommended usage is to connect a
258  * handler on the #GObject::notify signal for the #ClutterActor:mapped
259  * property of #ClutterActor, and check the presence of
260  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
261  *
262  * It is also important to note that Clutter may delay the changes of
263  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
264  * limitations, or during the reparenting of an actor, to optimize
265  * unnecessary (and potentially expensive) state changes.
266  *
267  * Since: 0.2
268  */
269
270 /**
271  * CLUTTER_ACTOR_IS_REALIZED:
272  * @a: a #ClutterActor
273  *
274  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
275  *
276  * The realized state has an actor-dependant interpretation. If an
277  * actor wants to delay allocating resources until it is attached to a
278  * stage, it may use the realize state to do so. However it is
279  * perfectly acceptable for an actor to allocate Cogl resources before
280  * being realized because there is only one drawing context used by Clutter
281  * so any resources will work on any stage.  If an actor is mapped it
282  * must also be realized, but an actor can be realized and unmapped
283  * (this is so hiding an actor temporarily doesn't do an expensive
284  * unrealize/realize).
285  *
286  * To be realized an actor must be inside a stage, and all its parents
287  * must be realized.
288  *
289  * Since: 0.2
290  */
291
292 /**
293  * CLUTTER_ACTOR_IS_VISIBLE:
294  * @a: a #ClutterActor
295  *
296  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
297  * Equivalent to the ClutterActor::visible object property.
298  *
299  * Note that an actor is only painted onscreen if it's mapped, which
300  * means it's visible, and all its parents are visible, and one of the
301  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
302  *
303  * Since: 0.2
304  */
305
306 /**
307  * CLUTTER_ACTOR_IS_REACTIVE:
308  * @a: a #ClutterActor
309  *
310  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
311  *
312  * Only reactive actors will receive event-related signals.
313  *
314  * Since: 0.6
315  */
316
317 #ifdef HAVE_CONFIG_H
318 #include "config.h"
319 #endif
320
321 #include <math.h>
322
323 #include "cogl/cogl.h"
324
325 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
326 #define CLUTTER_ENABLE_EXPERIMENTAL_API
327
328 #include "clutter-actor-private.h"
329
330 #include "clutter-action.h"
331 #include "clutter-actor-meta-private.h"
332 #include "clutter-animatable.h"
333 #include "clutter-color-static.h"
334 #include "clutter-color.h"
335 #include "clutter-constraint.h"
336 #include "clutter-container.h"
337 #include "clutter-debug.h"
338 #include "clutter-effect-private.h"
339 #include "clutter-enum-types.h"
340 #include "clutter-fixed-layout.h"
341 #include "clutter-flatten-effect.h"
342 #include "clutter-interval.h"
343 #include "clutter-main.h"
344 #include "clutter-marshal.h"
345 #include "clutter-paint-volume-private.h"
346 #include "clutter-private.h"
347 #include "clutter-profile.h"
348 #include "clutter-scriptable.h"
349 #include "clutter-script-private.h"
350 #include "clutter-stage-private.h"
351 #include "clutter-units.h"
352
353 #include "deprecated/clutter-behaviour.h"
354 #include "deprecated/clutter-container.h"
355
356 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
357 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
358
359 /* Internal enum used to control mapped state update.  This is a hint
360  * which indicates when to do something other than just enforce
361  * invariants.
362  */
363 typedef enum {
364   MAP_STATE_CHECK,           /* just enforce invariants. */
365   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
366                               * used when about to unparent.
367                               */
368   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
369                               * used to set mapped on toplevels.
370                               */
371   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
372                               * used just before unmapping parent.
373                               */
374 } MapStateChange;
375
376 /* 3 entries should be a good compromise, few layout managers
377  * will ask for 3 different preferred size in each allocation cycle */
378 #define N_CACHED_SIZE_REQUESTS 3
379
380 struct _ClutterActorPrivate
381 {
382   /* request mode */
383   ClutterRequestMode request_mode;
384
385   /* our cached size requests for different width / height */
386   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
387   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
388
389   /* An age of 0 means the entry is not set */
390   guint cached_height_age;
391   guint cached_width_age;
392
393   /* the bounding box of the actor, relative to the parent's
394    * allocation
395    */
396   ClutterActorBox allocation;
397   ClutterAllocationFlags allocation_flags;
398
399   /* depth */
400   gfloat z;
401
402   /* clip, in actor coordinates */
403   cairo_rectangle_t clip;
404
405   /* the cached transformation matrix; see apply_transform() */
406   CoglMatrix transform;
407
408   guint8 opacity;
409   gint opacity_override;
410
411   ClutterOffscreenRedirect offscreen_redirect;
412
413   /* This is an internal effect used to implement the
414      offscreen-redirect property */
415   ClutterEffect *flatten_effect;
416
417   /* scene graph */
418   ClutterActor *parent;
419   ClutterActor *prev_sibling;
420   ClutterActor *next_sibling;
421   ClutterActor *first_child;
422   ClutterActor *last_child;
423
424   gint n_children;
425
426   /* tracks whenever the children of an actor are changed; the
427    * age is incremented by 1 whenever an actor is added or
428    * removed. the age is not incremented when the first or the
429    * last child pointers are changed, or when grandchildren of
430    * an actor are changed.
431    */
432   gint age;
433
434   gchar *name; /* a non-unique name, used for debugging */
435   guint32 id; /* unique id, used for backward compatibility */
436
437   gint32 pick_id; /* per-stage unique id, used for picking */
438
439   /* a back-pointer to the Pango context that we can use
440    * to create pre-configured PangoLayout
441    */
442   PangoContext *pango_context;
443
444   /* the text direction configured for this child - either by
445    * application code, or by the actor's parent
446    */
447   ClutterTextDirection text_direction;
448
449   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
450   gint internal_child;
451
452   /* meta classes */
453   ClutterMetaGroup *actions;
454   ClutterMetaGroup *constraints;
455   ClutterMetaGroup *effects;
456
457   /* delegate object used to allocate the children of this actor */
458   ClutterLayoutManager *layout_manager;
459
460   /* used when painting, to update the paint volume */
461   ClutterEffect *current_effect;
462
463   /* This is used to store an effect which needs to be redrawn. A
464      redraw can be queued to start from a particular effect. This is
465      used by parametrised effects that can cache an image of the
466      actor. If a parameter of the effect changes then it only needs to
467      redraw the cached image, not the actual actor. The pointer is
468      only valid if is_dirty == TRUE. If the pointer is NULL then the
469      whole actor is dirty. */
470   ClutterEffect *effect_to_redraw;
471
472   /* This is used when painting effects to implement the
473      clutter_actor_continue_paint() function. It points to the node in
474      the list of effects that is next in the chain */
475   const GList *next_effect_to_paint;
476
477   ClutterPaintVolume paint_volume;
478
479   /* NB: This volume isn't relative to this actor, it is in eye
480    * coordinates so that it can remain valid after the actor changes.
481    */
482   ClutterPaintVolume last_paint_volume;
483
484   ClutterStageQueueRedrawEntry *queue_redraw_entry;
485
486   ClutterColor bg_color;
487
488   /* bitfields */
489
490   /* fixed position and sizes */
491   guint position_set                : 1;
492   guint min_width_set               : 1;
493   guint min_height_set              : 1;
494   guint natural_width_set           : 1;
495   guint natural_height_set          : 1;
496   /* cached request is invalid (implies allocation is too) */
497   guint needs_width_request         : 1;
498   /* cached request is invalid (implies allocation is too) */
499   guint needs_height_request        : 1;
500   /* cached allocation is invalid (request has changed, probably) */
501   guint needs_allocation            : 1;
502   guint show_on_set_parent          : 1;
503   guint has_clip                    : 1;
504   guint clip_to_allocation          : 1;
505   guint enable_model_view_transform : 1;
506   guint enable_paint_unmapped       : 1;
507   guint has_pointer                 : 1;
508   guint propagated_one_redraw       : 1;
509   guint paint_volume_valid          : 1;
510   guint last_paint_volume_valid     : 1;
511   guint in_clone_paint              : 1;
512   guint transform_valid             : 1;
513   /* This is TRUE if anything has queued a redraw since we were last
514      painted. In this case effect_to_redraw will point to an effect
515      the redraw was queued from or it will be NULL if the redraw was
516      queued without an effect. */
517   guint is_dirty                    : 1;
518   guint bg_color_set                : 1;
519 };
520
521 enum
522 {
523   PROP_0,
524
525   PROP_NAME,
526
527   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
528    * when set they force a size request, when gotten they
529    * get the allocation if the allocation is valid, and the
530    * request otherwise
531    */
532   PROP_X,
533   PROP_Y,
534   PROP_WIDTH,
535   PROP_HEIGHT,
536
537   /* Then the rest of these size-related properties are the "actual"
538    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
539    */
540   PROP_FIXED_X,
541   PROP_FIXED_Y,
542
543   PROP_FIXED_POSITION_SET,
544
545   PROP_MIN_WIDTH,
546   PROP_MIN_WIDTH_SET,
547
548   PROP_MIN_HEIGHT,
549   PROP_MIN_HEIGHT_SET,
550
551   PROP_NATURAL_WIDTH,
552   PROP_NATURAL_WIDTH_SET,
553
554   PROP_NATURAL_HEIGHT,
555   PROP_NATURAL_HEIGHT_SET,
556
557   PROP_REQUEST_MODE,
558
559   /* Allocation properties are read-only */
560   PROP_ALLOCATION,
561
562   PROP_DEPTH,
563
564   PROP_CLIP,
565   PROP_HAS_CLIP,
566   PROP_CLIP_TO_ALLOCATION,
567
568   PROP_OPACITY,
569
570   PROP_OFFSCREEN_REDIRECT,
571
572   PROP_VISIBLE,
573   PROP_MAPPED,
574   PROP_REALIZED,
575   PROP_REACTIVE,
576
577   PROP_SCALE_X,
578   PROP_SCALE_Y,
579   PROP_SCALE_CENTER_X,
580   PROP_SCALE_CENTER_Y,
581   PROP_SCALE_GRAVITY,
582
583   PROP_ROTATION_ANGLE_X,
584   PROP_ROTATION_ANGLE_Y,
585   PROP_ROTATION_ANGLE_Z,
586   PROP_ROTATION_CENTER_X,
587   PROP_ROTATION_CENTER_Y,
588   PROP_ROTATION_CENTER_Z,
589   /* This property only makes sense for the z rotation because the
590      others would depend on the actor having a size along the
591      z-axis */
592   PROP_ROTATION_CENTER_Z_GRAVITY,
593
594   PROP_ANCHOR_X,
595   PROP_ANCHOR_Y,
596   PROP_ANCHOR_GRAVITY,
597
598   PROP_SHOW_ON_SET_PARENT,
599
600   PROP_TEXT_DIRECTION,
601   PROP_HAS_POINTER,
602
603   PROP_ACTIONS,
604   PROP_CONSTRAINTS,
605   PROP_EFFECT,
606
607   PROP_LAYOUT_MANAGER,
608
609   PROP_X_ALIGN,
610   PROP_Y_ALIGN,
611   PROP_MARGIN_TOP,
612   PROP_MARGIN_BOTTOM,
613   PROP_MARGIN_LEFT,
614   PROP_MARGIN_RIGHT,
615
616   PROP_BACKGROUND_COLOR,
617   PROP_BACKGROUND_COLOR_SET,
618
619   PROP_FIRST_CHILD,
620   PROP_LAST_CHILD,
621
622   PROP_LAST
623 };
624
625 static GParamSpec *obj_props[PROP_LAST];
626
627 enum
628 {
629   SHOW,
630   HIDE,
631   DESTROY,
632   PARENT_SET,
633   KEY_FOCUS_IN,
634   KEY_FOCUS_OUT,
635   PAINT,
636   PICK,
637   REALIZE,
638   UNREALIZE,
639   QUEUE_REDRAW,
640   QUEUE_RELAYOUT,
641   EVENT,
642   CAPTURED_EVENT,
643   BUTTON_PRESS_EVENT,
644   BUTTON_RELEASE_EVENT,
645   SCROLL_EVENT,
646   KEY_PRESS_EVENT,
647   KEY_RELEASE_EVENT,
648   MOTION_EVENT,
649   ENTER_EVENT,
650   LEAVE_EVENT,
651   ALLOCATION_CHANGED,
652
653   LAST_SIGNAL
654 };
655
656 static guint actor_signals[LAST_SIGNAL] = { 0, };
657
658 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
659 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
660 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
661 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
662
663 /* These setters are all static for now, maybe they should be in the
664  * public API, but they are perhaps obscure enough to leave only as
665  * properties
666  */
667 static void clutter_actor_set_min_width          (ClutterActor *self,
668                                                   gfloat        min_width);
669 static void clutter_actor_set_min_height         (ClutterActor *self,
670                                                   gfloat        min_height);
671 static void clutter_actor_set_natural_width      (ClutterActor *self,
672                                                   gfloat        natural_width);
673 static void clutter_actor_set_natural_height     (ClutterActor *self,
674                                                   gfloat        natural_height);
675 static void clutter_actor_set_min_width_set      (ClutterActor *self,
676                                                   gboolean      use_min_width);
677 static void clutter_actor_set_min_height_set     (ClutterActor *self,
678                                                   gboolean      use_min_height);
679 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
680                                                   gboolean  use_natural_width);
681 static void clutter_actor_set_natural_height_set (ClutterActor *self,
682                                                   gboolean  use_natural_height);
683 static void clutter_actor_update_map_state       (ClutterActor  *self,
684                                                   MapStateChange change);
685 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
686
687 /* Helper routines for managing anchor coords */
688 static void clutter_anchor_coord_get_units (ClutterActor      *self,
689                                             const AnchorCoord *coord,
690                                             gfloat            *x,
691                                             gfloat            *y,
692                                             gfloat            *z);
693 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
694                                             gfloat             x,
695                                             gfloat             y,
696                                             gfloat             z);
697
698 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
699 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
700                                                         ClutterGravity     gravity);
701
702 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
703
704 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
705
706 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
707                                                                ClutterActor *ancestor,
708                                                                CoglMatrix *matrix);
709
710 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
711
712 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
713
714 static void on_layout_manager_changed (ClutterLayoutManager *manager,
715                                        ClutterActor         *self);
716
717 /* Helper macro which translates by the anchor coord, applies the
718    given transformation and then translates back */
719 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
720   gfloat _tx, _ty, _tz;                                                \
721   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
722   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
723   { _transform; }                                                      \
724   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
725
726 static GQuark quark_shader_data = 0;
727 static GQuark quark_actor_layout_info = 0;
728 static GQuark quark_actor_transform_info = 0;
729
730 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
731                          clutter_actor,
732                          G_TYPE_INITIALLY_UNOWNED,
733                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
734                                                 clutter_container_iface_init)
735                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
736                                                 clutter_scriptable_iface_init)
737                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
738                                                 clutter_animatable_iface_init)
739                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
740                                                 atk_implementor_iface_init));
741
742 /*< private >
743  * clutter_actor_get_debug_name:
744  * @actor: a #ClutterActor
745  *
746  * Retrieves a printable name of @actor for debugging messages
747  *
748  * Return value: a string with a printable name
749  */
750 const gchar *
751 _clutter_actor_get_debug_name (ClutterActor *actor)
752 {
753   return actor->priv->name != NULL ? actor->priv->name
754                                    : G_OBJECT_TYPE_NAME (actor);
755 }
756
757 #ifdef CLUTTER_ENABLE_DEBUG
758 /* XXX - this is for debugging only, remove once working (or leave
759  * in only in some debug mode). Should leave it for a little while
760  * until we're confident in the new map/realize/visible handling.
761  */
762 static inline void
763 clutter_actor_verify_map_state (ClutterActor *self)
764 {
765   ClutterActorPrivate *priv = self->priv;
766
767   if (CLUTTER_ACTOR_IS_REALIZED (self))
768     {
769       /* all bets are off during reparent when we're potentially realized,
770        * but should not be according to invariants
771        */
772       if (!CLUTTER_ACTOR_IN_REPARENT (self))
773         {
774           if (priv->parent == NULL)
775             {
776               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
777                 {
778                 }
779               else
780                 g_warning ("Realized non-toplevel actor '%s' should "
781                            "have a parent",
782                            _clutter_actor_get_debug_name (self));
783             }
784           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
785             {
786               g_warning ("Realized actor %s has an unrealized parent %s",
787                          _clutter_actor_get_debug_name (self),
788                          _clutter_actor_get_debug_name (priv->parent));
789             }
790         }
791     }
792
793   if (CLUTTER_ACTOR_IS_MAPPED (self))
794     {
795       if (!CLUTTER_ACTOR_IS_REALIZED (self))
796         g_warning ("Actor '%s' is mapped but not realized",
797                    _clutter_actor_get_debug_name (self));
798
799       /* remaining bets are off during reparent when we're potentially
800        * mapped, but should not be according to invariants
801        */
802       if (!CLUTTER_ACTOR_IN_REPARENT (self))
803         {
804           if (priv->parent == NULL)
805             {
806               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
807                 {
808                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
809                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
810                     {
811                       g_warning ("Toplevel actor '%s' is mapped "
812                                  "but not visible",
813                                  _clutter_actor_get_debug_name (self));
814                     }
815                 }
816               else
817                 {
818                   g_warning ("Mapped actor '%s' should have a parent",
819                              _clutter_actor_get_debug_name (self));
820                 }
821             }
822           else
823             {
824               ClutterActor *iter = self;
825
826               /* check for the enable_paint_unmapped flag on the actor
827                * and parents; if the flag is enabled at any point of this
828                * branch of the scene graph then all the later checks
829                * become pointless
830                */
831               while (iter != NULL)
832                 {
833                   if (iter->priv->enable_paint_unmapped)
834                     return;
835
836                   iter = iter->priv->parent;
837                 }
838
839               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
840                 {
841                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
842                              "is not visible",
843                              _clutter_actor_get_debug_name (self),
844                              _clutter_actor_get_debug_name (priv->parent));
845                 }
846
847               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
848                 {
849                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
850                              "is not realized",
851                              _clutter_actor_get_debug_name (self),
852                              _clutter_actor_get_debug_name (priv->parent));
853                 }
854
855               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
856                 {
857                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
858                     g_warning ("Actor '%s' is mapped but its non-toplevel "
859                                "parent '%s' is not mapped",
860                                _clutter_actor_get_debug_name (self),
861                                _clutter_actor_get_debug_name (priv->parent));
862                 }
863             }
864         }
865     }
866 }
867
868 #endif /* CLUTTER_ENABLE_DEBUG */
869
870 static void
871 clutter_actor_set_mapped (ClutterActor *self,
872                           gboolean      mapped)
873 {
874   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
875     return;
876
877   if (mapped)
878     {
879       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
880       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
881     }
882   else
883     {
884       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
885       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
886     }
887 }
888
889 /* this function updates the mapped and realized states according to
890  * invariants, in the appropriate order.
891  */
892 static void
893 clutter_actor_update_map_state (ClutterActor  *self,
894                                 MapStateChange change)
895 {
896   gboolean was_mapped;
897
898   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
899
900   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
901     {
902       /* the mapped flag on top-level actors must be set by the
903        * per-backend implementation because it might be asynchronous.
904        *
905        * That is, the MAPPED flag on toplevels currently tracks the X
906        * server mapped-ness of the window, while the expected behavior
907        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
908        * This creates some weird complexity by breaking the invariant
909        * that if we're visible and all ancestors shown then we are
910        * also mapped - instead, we are mapped if all ancestors
911        * _possibly excepting_ the stage are mapped. The stage
912        * will map/unmap for example when it is minimized or
913        * moved to another workspace.
914        *
915        * So, the only invariant on the stage is that if visible it
916        * should be realized, and that it has to be visible to be
917        * mapped.
918        */
919       if (CLUTTER_ACTOR_IS_VISIBLE (self))
920         clutter_actor_realize (self);
921
922       switch (change)
923         {
924         case MAP_STATE_CHECK:
925           break;
926
927         case MAP_STATE_MAKE_MAPPED:
928           g_assert (!was_mapped);
929           clutter_actor_set_mapped (self, TRUE);
930           break;
931
932         case MAP_STATE_MAKE_UNMAPPED:
933           g_assert (was_mapped);
934           clutter_actor_set_mapped (self, FALSE);
935           break;
936
937         case MAP_STATE_MAKE_UNREALIZED:
938           /* we only use MAKE_UNREALIZED in unparent,
939            * and unparenting a stage isn't possible.
940            * If someone wants to just unrealize a stage
941            * then clutter_actor_unrealize() doesn't
942            * go through this codepath.
943            */
944           g_warning ("Trying to force unrealize stage is not allowed");
945           break;
946         }
947
948       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
949           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
950           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
951         {
952           g_warning ("Clutter toplevel of type '%s' is not visible, but "
953                      "it is somehow still mapped",
954                      _clutter_actor_get_debug_name (self));
955         }
956     }
957   else
958     {
959       ClutterActorPrivate *priv = self->priv;
960       ClutterActor *parent = priv->parent;
961       gboolean should_be_mapped;
962       gboolean may_be_realized;
963       gboolean must_be_realized;
964
965       should_be_mapped = FALSE;
966       may_be_realized = TRUE;
967       must_be_realized = FALSE;
968
969       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
970         {
971           may_be_realized = FALSE;
972         }
973       else
974         {
975           /* Maintain invariant that if parent is mapped, and we are
976            * visible, then we are mapped ...  unless parent is a
977            * stage, in which case we map regardless of parent's map
978            * state but do require stage to be visible and realized.
979            *
980            * If parent is realized, that does not force us to be
981            * realized; but if parent is unrealized, that does force
982            * us to be unrealized.
983            *
984            * The reason we don't force children to realize with
985            * parents is _clutter_actor_rerealize(); if we require that
986            * a realized parent means children are realized, then to
987            * unrealize an actor we would have to unrealize its
988            * parents, which would end up meaning unrealizing and
989            * hiding the entire stage. So we allow unrealizing a
990            * child (as long as that child is not mapped) while that
991            * child still has a realized parent.
992            *
993            * Also, if we unrealize from leaf nodes to root, and
994            * realize from root to leaf, the invariants are never
995            * violated if we allow children to be unrealized
996            * while parents are realized.
997            *
998            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
999            * to force us to unmap, even though parent is still
1000            * mapped. This is because we're unmapping from leaf nodes
1001            * up to root nodes.
1002            */
1003           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1004               change != MAP_STATE_MAKE_UNMAPPED)
1005             {
1006               gboolean parent_is_visible_realized_toplevel;
1007
1008               parent_is_visible_realized_toplevel =
1009                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1010                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1011                  CLUTTER_ACTOR_IS_REALIZED (parent));
1012
1013               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1014                   parent_is_visible_realized_toplevel)
1015                 {
1016                   must_be_realized = TRUE;
1017                   should_be_mapped = TRUE;
1018                 }
1019             }
1020
1021           /* if the actor has been set to be painted even if unmapped
1022            * then we should map it and check for realization as well;
1023            * this is an override for the branch of the scene graph
1024            * which begins with this node
1025            */
1026           if (priv->enable_paint_unmapped)
1027             {
1028               if (priv->parent == NULL)
1029                 g_warning ("Attempting to map an unparented actor '%s'",
1030                            _clutter_actor_get_debug_name (self));
1031
1032               should_be_mapped = TRUE;
1033               must_be_realized = TRUE;
1034             }
1035
1036           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1037             may_be_realized = FALSE;
1038         }
1039
1040       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1041         {
1042           if (parent == NULL)
1043             g_warning ("Attempting to map a child that does not "
1044                        "meet the necessary invariants: the actor '%s' "
1045                        "has no parent",
1046                        _clutter_actor_get_debug_name (self));
1047           else
1048             g_warning ("Attempting to map a child that does not "
1049                        "meet the necessary invariants: the actor '%s' "
1050                        "is parented to an unmapped actor '%s'",
1051                        _clutter_actor_get_debug_name (self),
1052                        _clutter_actor_get_debug_name (priv->parent));
1053         }
1054
1055       /* If in reparent, we temporarily suspend unmap and unrealize.
1056        *
1057        * We want to go in the order "realize, map" and "unmap, unrealize"
1058        */
1059
1060       /* Unmap */
1061       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1062         clutter_actor_set_mapped (self, FALSE);
1063
1064       /* Realize */
1065       if (must_be_realized)
1066         clutter_actor_realize (self);
1067
1068       /* if we must be realized then we may be, presumably */
1069       g_assert (!(must_be_realized && !may_be_realized));
1070
1071       /* Unrealize */
1072       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1073         clutter_actor_unrealize_not_hiding (self);
1074
1075       /* Map */
1076       if (should_be_mapped)
1077         {
1078           if (!must_be_realized)
1079             g_warning ("Somehow we think actor '%s' should be mapped but "
1080                        "not realized, which isn't allowed",
1081                        _clutter_actor_get_debug_name (self));
1082
1083           /* realization is allowed to fail (though I don't know what
1084            * an app is supposed to do about that - shouldn't it just
1085            * be a g_error? anyway, we have to avoid mapping if this
1086            * happens)
1087            */
1088           if (CLUTTER_ACTOR_IS_REALIZED (self))
1089             clutter_actor_set_mapped (self, TRUE);
1090         }
1091     }
1092
1093 #ifdef CLUTTER_ENABLE_DEBUG
1094   /* check all invariants were kept */
1095   clutter_actor_verify_map_state (self);
1096 #endif
1097 }
1098
1099 static void
1100 clutter_actor_real_map (ClutterActor *self)
1101 {
1102   ClutterActorPrivate *priv = self->priv;
1103   ClutterActor *stage, *iter;
1104
1105   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1106
1107   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1108                 _clutter_actor_get_debug_name (self));
1109
1110   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1111
1112   stage = _clutter_actor_get_stage_internal (self);
1113   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1114
1115   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1116                 priv->pick_id,
1117                 _clutter_actor_get_debug_name (self));
1118
1119   /* notify on parent mapped before potentially mapping
1120    * children, so apps see a top-down notification.
1121    */
1122   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1123
1124   for (iter = self->priv->first_child;
1125        iter != NULL;
1126        iter = iter->priv->next_sibling)
1127     {
1128       clutter_actor_map (iter);
1129     }
1130 }
1131
1132 /**
1133  * clutter_actor_map:
1134  * @self: A #ClutterActor
1135  *
1136  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1137  * and realizes its children if they are visible. Does nothing if the
1138  * actor is not visible.
1139  *
1140  * Calling this function is strongly disencouraged: the default
1141  * implementation of #ClutterActorClass.map() will map all the children
1142  * of an actor when mapping its parent.
1143  *
1144  * When overriding map, it is mandatory to chain up to the parent
1145  * implementation.
1146  *
1147  * Since: 1.0
1148  */
1149 void
1150 clutter_actor_map (ClutterActor *self)
1151 {
1152   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1153
1154   if (CLUTTER_ACTOR_IS_MAPPED (self))
1155     return;
1156
1157   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1158     return;
1159
1160   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1161 }
1162
1163 static void
1164 clutter_actor_real_unmap (ClutterActor *self)
1165 {
1166   ClutterActorPrivate *priv = self->priv;
1167   ClutterActor *iter;
1168
1169   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1170
1171   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1172                 _clutter_actor_get_debug_name (self));
1173
1174   for (iter = self->priv->first_child;
1175        iter != NULL;
1176        iter = iter->priv->next_sibling)
1177     {
1178       clutter_actor_unmap (iter);
1179     }
1180
1181   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1182
1183   /* clear the contents of the last paint volume, so that hiding + moving +
1184    * showing will not result in the wrong area being repainted
1185    */
1186   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1187   priv->last_paint_volume_valid = TRUE;
1188
1189   /* notify on parent mapped after potentially unmapping
1190    * children, so apps see a bottom-up notification.
1191    */
1192   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1193
1194   /* relinquish keyboard focus if we were unmapped while owning it */
1195   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1196     {
1197       ClutterStage *stage;
1198
1199       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1200
1201       if (stage != NULL)
1202         _clutter_stage_release_pick_id (stage, priv->pick_id);
1203
1204       priv->pick_id = -1;
1205
1206       if (stage != NULL &&
1207           clutter_stage_get_key_focus (stage) == self)
1208         {
1209           clutter_stage_set_key_focus (stage, NULL);
1210         }
1211     }
1212 }
1213
1214 /**
1215  * clutter_actor_unmap:
1216  * @self: A #ClutterActor
1217  *
1218  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1219  * unmaps its children if they were mapped.
1220  *
1221  * Calling this function is not encouraged: the default #ClutterActor
1222  * implementation of #ClutterActorClass.unmap() will also unmap any
1223  * eventual children by default when their parent is unmapped.
1224  *
1225  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1226  * chain up to the parent implementation.
1227  *
1228  * <note>It is important to note that the implementation of the
1229  * #ClutterActorClass.unmap() virtual function may be called after
1230  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1231  * implementation, but it is guaranteed to be called before the
1232  * #GObjectClass.finalize() implementation.</note>
1233  *
1234  * Since: 1.0
1235  */
1236 void
1237 clutter_actor_unmap (ClutterActor *self)
1238 {
1239   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1240
1241   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1242     return;
1243
1244   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1245 }
1246
1247 static void
1248 clutter_actor_real_show (ClutterActor *self)
1249 {
1250   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1251     {
1252       ClutterActorPrivate *priv = self->priv;
1253
1254       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1255
1256       /* we notify on the "visible" flag in the clutter_actor_show()
1257        * wrapper so the entire show signal emission completes first
1258        * (?)
1259        */
1260       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1261
1262       /* we queue a relayout unless the actor is inside a
1263        * container that explicitly told us not to
1264        */
1265       if (priv->parent != NULL &&
1266           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1267         {
1268           /* While an actor is hidden the parent may not have
1269            * allocated/requested so we need to start from scratch
1270            * and avoid the short-circuiting in
1271            * clutter_actor_queue_relayout().
1272            */
1273           priv->needs_width_request  = FALSE;
1274           priv->needs_height_request = FALSE;
1275           priv->needs_allocation     = FALSE;
1276           clutter_actor_queue_relayout (self);
1277         }
1278     }
1279 }
1280
1281 static inline void
1282 set_show_on_set_parent (ClutterActor *self,
1283                         gboolean      set_show)
1284 {
1285   ClutterActorPrivate *priv = self->priv;
1286
1287   set_show = !!set_show;
1288
1289   if (priv->show_on_set_parent == set_show)
1290     return;
1291
1292   if (priv->parent == NULL)
1293     {
1294       priv->show_on_set_parent = set_show;
1295       g_object_notify_by_pspec (G_OBJECT (self),
1296                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1297     }
1298 }
1299
1300 /**
1301  * clutter_actor_show:
1302  * @self: A #ClutterActor
1303  *
1304  * Flags an actor to be displayed. An actor that isn't shown will not
1305  * be rendered on the stage.
1306  *
1307  * Actors are visible by default.
1308  *
1309  * If this function is called on an actor without a parent, the
1310  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1311  * effect.
1312  */
1313 void
1314 clutter_actor_show (ClutterActor *self)
1315 {
1316   ClutterActorPrivate *priv;
1317
1318   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1319
1320   /* simple optimization */
1321   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1322     {
1323       /* we still need to set the :show-on-set-parent property, in
1324        * case show() is called on an unparented actor
1325        */
1326       set_show_on_set_parent (self, TRUE);
1327       return;
1328     }
1329
1330 #ifdef CLUTTER_ENABLE_DEBUG
1331   clutter_actor_verify_map_state (self);
1332 #endif
1333
1334   priv = self->priv;
1335
1336   g_object_freeze_notify (G_OBJECT (self));
1337
1338   set_show_on_set_parent (self, TRUE);
1339
1340   g_signal_emit (self, actor_signals[SHOW], 0);
1341   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1342
1343   if (priv->parent != NULL)
1344     clutter_actor_queue_redraw (priv->parent);
1345
1346   g_object_thaw_notify (G_OBJECT (self));
1347 }
1348
1349 /**
1350  * clutter_actor_show_all:
1351  * @self: a #ClutterActor
1352  *
1353  * Calls clutter_actor_show() on all children of an actor (if any).
1354  *
1355  * Since: 0.2
1356  *
1357  * Deprecated: 1.10: Actors are visible by default
1358  */
1359 void
1360 clutter_actor_show_all (ClutterActor *self)
1361 {
1362   ClutterActorClass *klass;
1363
1364   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1365
1366   klass = CLUTTER_ACTOR_GET_CLASS (self);
1367   if (klass->show_all)
1368     klass->show_all (self);
1369 }
1370
1371 static void
1372 clutter_actor_real_hide (ClutterActor *self)
1373 {
1374   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1375     {
1376       ClutterActorPrivate *priv = self->priv;
1377
1378       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1379
1380       /* we notify on the "visible" flag in the clutter_actor_hide()
1381        * wrapper so the entire hide signal emission completes first
1382        * (?)
1383        */
1384       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1385
1386       /* we queue a relayout unless the actor is inside a
1387        * container that explicitly told us not to
1388        */
1389       if (priv->parent != NULL &&
1390           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1391         clutter_actor_queue_relayout (priv->parent);
1392     }
1393 }
1394
1395 /**
1396  * clutter_actor_hide:
1397  * @self: A #ClutterActor
1398  *
1399  * Flags an actor to be hidden. A hidden actor will not be
1400  * rendered on the stage.
1401  *
1402  * Actors are visible by default.
1403  *
1404  * If this function is called on an actor without a parent, the
1405  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1406  * as a side-effect.
1407  */
1408 void
1409 clutter_actor_hide (ClutterActor *self)
1410 {
1411   ClutterActorPrivate *priv;
1412
1413   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1414
1415   /* simple optimization */
1416   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1417     {
1418       /* we still need to set the :show-on-set-parent property, in
1419        * case hide() is called on an unparented actor
1420        */
1421       set_show_on_set_parent (self, FALSE);
1422       return;
1423     }
1424
1425 #ifdef CLUTTER_ENABLE_DEBUG
1426   clutter_actor_verify_map_state (self);
1427 #endif
1428
1429   priv = self->priv;
1430
1431   g_object_freeze_notify (G_OBJECT (self));
1432
1433   set_show_on_set_parent (self, FALSE);
1434
1435   g_signal_emit (self, actor_signals[HIDE], 0);
1436   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1437
1438   if (priv->parent != NULL)
1439     clutter_actor_queue_redraw (priv->parent);
1440
1441   g_object_thaw_notify (G_OBJECT (self));
1442 }
1443
1444 /**
1445  * clutter_actor_hide_all:
1446  * @self: a #ClutterActor
1447  *
1448  * Calls clutter_actor_hide() on all child actors (if any).
1449  *
1450  * Since: 0.2
1451  *
1452  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1453  *   prevent its children from being painted as well.
1454  */
1455 void
1456 clutter_actor_hide_all (ClutterActor *self)
1457 {
1458   ClutterActorClass *klass;
1459
1460   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1461
1462   klass = CLUTTER_ACTOR_GET_CLASS (self);
1463   if (klass->hide_all)
1464     klass->hide_all (self);
1465 }
1466
1467 /**
1468  * clutter_actor_realize:
1469  * @self: A #ClutterActor
1470  *
1471  * Realization informs the actor that it is attached to a stage. It
1472  * can use this to allocate resources if it wanted to delay allocation
1473  * until it would be rendered. However it is perfectly acceptable for
1474  * an actor to create resources before being realized because Clutter
1475  * only ever has a single rendering context so that actor is free to
1476  * be moved from one stage to another.
1477  *
1478  * This function does nothing if the actor is already realized.
1479  *
1480  * Because a realized actor must have realized parent actors, calling
1481  * clutter_actor_realize() will also realize all parents of the actor.
1482  *
1483  * This function does not realize child actors, except in the special
1484  * case that realizing the stage, when the stage is visible, will
1485  * suddenly map (and thus realize) the children of the stage.
1486  **/
1487 void
1488 clutter_actor_realize (ClutterActor *self)
1489 {
1490   ClutterActorPrivate *priv;
1491
1492   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1493
1494   priv = self->priv;
1495
1496 #ifdef CLUTTER_ENABLE_DEBUG
1497   clutter_actor_verify_map_state (self);
1498 #endif
1499
1500   if (CLUTTER_ACTOR_IS_REALIZED (self))
1501     return;
1502
1503   /* To be realized, our parent actors must be realized first.
1504    * This will only succeed if we're inside a toplevel.
1505    */
1506   if (priv->parent != NULL)
1507     clutter_actor_realize (priv->parent);
1508
1509   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1510     {
1511       /* toplevels can be realized at any time */
1512     }
1513   else
1514     {
1515       /* "Fail" the realization if parent is missing or unrealized;
1516        * this should really be a g_warning() not some kind of runtime
1517        * failure; how can an app possibly recover? Instead it's a bug
1518        * in the app and the app should get an explanatory warning so
1519        * someone can fix it. But for now it's too hard to fix this
1520        * because e.g. ClutterTexture needs reworking.
1521        */
1522       if (priv->parent == NULL ||
1523           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1524         return;
1525     }
1526
1527   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1528
1529   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1530   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1531
1532   g_signal_emit (self, actor_signals[REALIZE], 0);
1533
1534   /* Stage actor is allowed to unset the realized flag again in its
1535    * default signal handler, though that is a pathological situation.
1536    */
1537
1538   /* If realization "failed" we'll have to update child state. */
1539   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1540 }
1541
1542 static void
1543 clutter_actor_real_unrealize (ClutterActor *self)
1544 {
1545   /* we must be unmapped (implying our children are also unmapped) */
1546   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1547 }
1548
1549 /**
1550  * clutter_actor_unrealize:
1551  * @self: A #ClutterActor
1552  *
1553  * Unrealization informs the actor that it may be being destroyed or
1554  * moved to another stage. The actor may want to destroy any
1555  * underlying graphics resources at this point. However it is
1556  * perfectly acceptable for it to retain the resources until the actor
1557  * is destroyed because Clutter only ever uses a single rendering
1558  * context and all of the graphics resources are valid on any stage.
1559  *
1560  * Because mapped actors must be realized, actors may not be
1561  * unrealized if they are mapped. This function hides the actor to be
1562  * sure it isn't mapped, an application-visible side effect that you
1563  * may not be expecting.
1564  *
1565  * This function should not be called by application code.
1566  */
1567 void
1568 clutter_actor_unrealize (ClutterActor *self)
1569 {
1570   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1571   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1572
1573 /* This function should not really be in the public API, because
1574  * there isn't a good reason to call it. ClutterActor will already
1575  * unrealize things for you when it's important to do so.
1576  *
1577  * If you were using clutter_actor_unrealize() in a dispose
1578  * implementation, then don't, just chain up to ClutterActor's
1579  * dispose.
1580  *
1581  * If you were using clutter_actor_unrealize() to implement
1582  * unrealizing children of your container, then don't, ClutterActor
1583  * will already take care of that.
1584  *
1585  * If you were using clutter_actor_unrealize() to re-realize to
1586  * create your resources in a different way, then use
1587  * _clutter_actor_rerealize() (inside Clutter) or just call your
1588  * code that recreates your resources directly (outside Clutter).
1589  */
1590
1591 #ifdef CLUTTER_ENABLE_DEBUG
1592   clutter_actor_verify_map_state (self);
1593 #endif
1594
1595   clutter_actor_hide (self);
1596
1597   clutter_actor_unrealize_not_hiding (self);
1598 }
1599
1600 static ClutterActorTraverseVisitFlags
1601 unrealize_actor_before_children_cb (ClutterActor *self,
1602                                     int depth,
1603                                     void *user_data)
1604 {
1605   /* If an actor is already unrealized we know its children have also
1606    * already been unrealized... */
1607   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1608     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1609
1610   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1611
1612   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1613 }
1614
1615 static ClutterActorTraverseVisitFlags
1616 unrealize_actor_after_children_cb (ClutterActor *self,
1617                                    int depth,
1618                                    void *user_data)
1619 {
1620   /* We want to unset the realized flag only _after_
1621    * child actors are unrealized, to maintain invariants.
1622    */
1623   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1624   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1625   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1626 }
1627
1628 /*
1629  * clutter_actor_unrealize_not_hiding:
1630  * @self: A #ClutterActor
1631  *
1632  * Unrealization informs the actor that it may be being destroyed or
1633  * moved to another stage. The actor may want to destroy any
1634  * underlying graphics resources at this point. However it is
1635  * perfectly acceptable for it to retain the resources until the actor
1636  * is destroyed because Clutter only ever uses a single rendering
1637  * context and all of the graphics resources are valid on any stage.
1638  *
1639  * Because mapped actors must be realized, actors may not be
1640  * unrealized if they are mapped. You must hide the actor or one of
1641  * its parents before attempting to unrealize.
1642  *
1643  * This function is separate from clutter_actor_unrealize() because it
1644  * does not automatically hide the actor.
1645  * Actors need not be hidden to be unrealized, they just need to
1646  * be unmapped. In fact we don't want to mess up the application's
1647  * setting of the "visible" flag, so hiding is very undesirable.
1648  *
1649  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1650  * backward compatibility.
1651  */
1652 static void
1653 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1654 {
1655   _clutter_actor_traverse (self,
1656                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1657                            unrealize_actor_before_children_cb,
1658                            unrealize_actor_after_children_cb,
1659                            NULL);
1660 }
1661
1662 /*
1663  * _clutter_actor_rerealize:
1664  * @self: A #ClutterActor
1665  * @callback: Function to call while unrealized
1666  * @data: data for callback
1667  *
1668  * If an actor is already unrealized, this just calls the callback.
1669  *
1670  * If it is realized, it unrealizes temporarily, calls the callback,
1671  * and then re-realizes the actor.
1672  *
1673  * As a side effect, leaves all children of the actor unrealized if
1674  * the actor was realized but not showing.  This is because when we
1675  * unrealize the actor temporarily we must unrealize its children
1676  * (e.g. children of a stage can't be realized if stage window is
1677  * gone). And we aren't clever enough to save the realization state of
1678  * all children. In most cases this should not matter, because
1679  * the children will automatically realize when they next become mapped.
1680  */
1681 void
1682 _clutter_actor_rerealize (ClutterActor    *self,
1683                           ClutterCallback  callback,
1684                           void            *data)
1685 {
1686   gboolean was_mapped;
1687   gboolean was_showing;
1688   gboolean was_realized;
1689
1690   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1691
1692 #ifdef CLUTTER_ENABLE_DEBUG
1693   clutter_actor_verify_map_state (self);
1694 #endif
1695
1696   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1697   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1698   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1699
1700   /* Must be unmapped to unrealize. Note we only have to hide this
1701    * actor if it was mapped (if all parents were showing).  If actor
1702    * is merely visible (but not mapped), then that's fine, we can
1703    * leave it visible.
1704    */
1705   if (was_mapped)
1706     clutter_actor_hide (self);
1707
1708   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1709
1710   /* unrealize self and all children */
1711   clutter_actor_unrealize_not_hiding (self);
1712
1713   if (callback != NULL)
1714     {
1715       (* callback) (self, data);
1716     }
1717
1718   if (was_showing)
1719     clutter_actor_show (self); /* will realize only if mapping implies it */
1720   else if (was_realized)
1721     clutter_actor_realize (self); /* realize self and all parents */
1722 }
1723
1724 static void
1725 clutter_actor_real_pick (ClutterActor       *self,
1726                          const ClutterColor *color)
1727 {
1728   /* the default implementation is just to paint a rectangle
1729    * with the same size of the actor using the passed color
1730    */
1731   if (clutter_actor_should_pick_paint (self))
1732     {
1733       ClutterActorBox box = { 0, };
1734       float width, height;
1735
1736       clutter_actor_get_allocation_box (self, &box);
1737
1738       width = box.x2 - box.x1;
1739       height = box.y2 - box.y1;
1740
1741       cogl_set_source_color4ub (color->red,
1742                                 color->green,
1743                                 color->blue,
1744                                 color->alpha);
1745
1746       cogl_rectangle (0, 0, width, height);
1747     }
1748
1749   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1750    * with existing container classes that override the pick() virtual
1751    * and chain up to the default implementation - otherwise we'll end up
1752    * painting our children twice.
1753    *
1754    * this has to go away for 2.0; hopefully along the pick() itself.
1755    */
1756   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1757     {
1758       ClutterActor *iter;
1759
1760       for (iter = self->priv->first_child;
1761            iter != NULL;
1762            iter = iter->priv->next_sibling)
1763         clutter_actor_paint (iter);
1764     }
1765 }
1766
1767 /**
1768  * clutter_actor_should_pick_paint:
1769  * @self: A #ClutterActor
1770  *
1771  * Should be called inside the implementation of the
1772  * #ClutterActor::pick virtual function in order to check whether
1773  * the actor should paint itself in pick mode or not.
1774  *
1775  * This function should never be called directly by applications.
1776  *
1777  * Return value: %TRUE if the actor should paint its silhouette,
1778  *   %FALSE otherwise
1779  */
1780 gboolean
1781 clutter_actor_should_pick_paint (ClutterActor *self)
1782 {
1783   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1784
1785   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1786       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1787        CLUTTER_ACTOR_IS_REACTIVE (self)))
1788     return TRUE;
1789
1790   return FALSE;
1791 }
1792
1793 static void
1794 clutter_actor_real_get_preferred_width (ClutterActor *self,
1795                                         gfloat        for_height,
1796                                         gfloat       *min_width_p,
1797                                         gfloat       *natural_width_p)
1798 {
1799   ClutterActorPrivate *priv = self->priv;
1800
1801   if (priv->n_children != 0 &&
1802       priv->layout_manager != NULL)
1803     {
1804       ClutterContainer *container = CLUTTER_CONTAINER (self);
1805
1806       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1807                     "for the preferred width",
1808                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1809                     priv->layout_manager);
1810
1811       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1812                                                   container,
1813                                                   for_height,
1814                                                   min_width_p,
1815                                                   natural_width_p);
1816
1817       return;
1818     }
1819
1820   /* Default implementation is always 0x0, usually an actor
1821    * using this default is relying on someone to set the
1822    * request manually
1823    */
1824   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1825
1826   if (min_width_p)
1827     *min_width_p = 0;
1828
1829   if (natural_width_p)
1830     *natural_width_p = 0;
1831 }
1832
1833 static void
1834 clutter_actor_real_get_preferred_height (ClutterActor *self,
1835                                          gfloat        for_width,
1836                                          gfloat       *min_height_p,
1837                                          gfloat       *natural_height_p)
1838 {
1839   ClutterActorPrivate *priv = self->priv;
1840
1841   if (priv->n_children != 0 &&
1842       priv->layout_manager != NULL)
1843     {
1844       ClutterContainer *container = CLUTTER_CONTAINER (self);
1845
1846       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1847                     "for the preferred height",
1848                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1849                     priv->layout_manager);
1850
1851       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1852                                                    container,
1853                                                    for_width,
1854                                                    min_height_p,
1855                                                    natural_height_p);
1856
1857       return;
1858     }
1859   /* Default implementation is always 0x0, usually an actor
1860    * using this default is relying on someone to set the
1861    * request manually
1862    */
1863   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1864
1865   if (min_height_p)
1866     *min_height_p = 0;
1867
1868   if (natural_height_p)
1869     *natural_height_p = 0;
1870 }
1871
1872 static void
1873 clutter_actor_store_old_geometry (ClutterActor    *self,
1874                                   ClutterActorBox *box)
1875 {
1876   *box = self->priv->allocation;
1877 }
1878
1879 static inline void
1880 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1881                                           const ClutterActorBox *old)
1882 {
1883   ClutterActorPrivate *priv = self->priv;
1884   GObject *obj = G_OBJECT (self);
1885
1886   g_object_freeze_notify (obj);
1887
1888   /* to avoid excessive requisition or allocation cycles we
1889    * use the cached values.
1890    *
1891    * - if we don't have an allocation we assume that we need
1892    *   to notify anyway
1893    * - if we don't have a width or a height request we notify
1894    *   width and height
1895    * - if we have a valid allocation then we check the old
1896    *   bounding box with the current allocation and we notify
1897    *   the changes
1898    */
1899   if (priv->needs_allocation)
1900     {
1901       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1902       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1903       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1904       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1905     }
1906   else if (priv->needs_width_request || priv->needs_height_request)
1907     {
1908       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1909       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1910     }
1911   else
1912     {
1913       gfloat xu, yu;
1914       gfloat widthu, heightu;
1915
1916       xu = priv->allocation.x1;
1917       yu = priv->allocation.y1;
1918       widthu = priv->allocation.x2 - priv->allocation.x1;
1919       heightu = priv->allocation.y2 - priv->allocation.y1;
1920
1921       if (xu != old->x1)
1922         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1923
1924       if (yu != old->y1)
1925         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1926
1927       if (widthu != (old->x2 - old->x1))
1928         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1929
1930       if (heightu != (old->y2 - old->y1))
1931         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1932     }
1933
1934   g_object_thaw_notify (obj);
1935 }
1936
1937 /*< private >
1938  * clutter_actor_set_allocation_internal:
1939  * @self: a #ClutterActor
1940  * @box: a #ClutterActorBox
1941  * @flags: allocation flags
1942  *
1943  * Stores the allocation of @self.
1944  *
1945  * This function only performs basic storage and property notification.
1946  *
1947  * This function should be called by clutter_actor_set_allocation()
1948  * and by the default implementation of #ClutterActorClass.allocate().
1949  *
1950  * Return value: %TRUE if the allocation of the #ClutterActor has been
1951  *   changed, and %FALSE otherwise
1952  */
1953 static inline gboolean
1954 clutter_actor_set_allocation_internal (ClutterActor           *self,
1955                                        const ClutterActorBox  *box,
1956                                        ClutterAllocationFlags  flags)
1957 {
1958   ClutterActorPrivate *priv = self->priv;
1959   GObject *obj;
1960   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
1961   gboolean flags_changed;
1962   gboolean retval;
1963   ClutterActorBox old_alloc = { 0, };
1964
1965   obj = G_OBJECT (self);
1966
1967   g_object_freeze_notify (obj);
1968
1969   clutter_actor_store_old_geometry (self, &old_alloc);
1970
1971   x1_changed = priv->allocation.x1 != box->x1;
1972   y1_changed = priv->allocation.y1 != box->y1;
1973   x2_changed = priv->allocation.x2 != box->x2;
1974   y2_changed = priv->allocation.y2 != box->y2;
1975
1976   flags_changed = priv->allocation_flags != flags;
1977
1978   priv->allocation = *box;
1979   priv->allocation_flags = flags;
1980
1981   /* allocation is authoritative */
1982   priv->needs_width_request = FALSE;
1983   priv->needs_height_request = FALSE;
1984   priv->needs_allocation = FALSE;
1985
1986   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1987     {
1988       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
1989                     _clutter_actor_get_debug_name (self));
1990
1991       priv->transform_valid = FALSE;
1992
1993       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
1994
1995       retval = TRUE;
1996     }
1997   else
1998     retval = FALSE;
1999
2000   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2001
2002   g_object_thaw_notify (obj);
2003
2004   return retval;
2005 }
2006
2007 static void clutter_actor_real_allocate (ClutterActor           *self,
2008                                          const ClutterActorBox  *box,
2009                                          ClutterAllocationFlags  flags);
2010
2011 static inline void
2012 clutter_actor_maybe_layout_children (ClutterActor           *self,
2013                                      const ClutterActorBox  *allocation,
2014                                      ClutterAllocationFlags  flags)
2015 {
2016   ClutterActorPrivate *priv = self->priv;
2017
2018   /* this is going to be a bit hard to follow, so let's put an explanation
2019    * here.
2020    *
2021    * we want ClutterActor to have a default layout manager if the actor was
2022    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2023    *
2024    * we also want any subclass of ClutterActor that does not override the
2025    * ::allocate() virtual function to delegate to a layout manager.
2026    *
2027    * finally, we want to allow people subclassing ClutterActor and overriding
2028    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2029    *
2030    * on the other hand, we want existing actor subclasses overriding the
2031    * ::allocate() virtual function and chaining up to the parent's
2032    * implementation to continue working without allocating their children
2033    * twice, or without entering an allocation loop.
2034    *
2035    * for the first two points, we check if the class of the actor is
2036    * overridding the ::allocate() virtual function; if it isn't, then we
2037    * follow through with checking whether we have children and a layout
2038    * manager, and eventually calling clutter_layout_manager_allocate().
2039    *
2040    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2041    * allocation flags that we got passed, and if it is present, we continue
2042    * with the check above.
2043    *
2044    * if neither of these two checks yields a positive result, we just
2045    * assume that the ::allocate() virtual function that resulted in this
2046    * function being called will also allocate the children of the actor.
2047    */
2048
2049   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2050     goto check_layout;
2051
2052   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2053     goto check_layout;
2054
2055   return;
2056
2057 check_layout:
2058   if (priv->n_children != 0 &&
2059       priv->layout_manager != NULL)
2060     {
2061       ClutterContainer *container = CLUTTER_CONTAINER (self);
2062       ClutterAllocationFlags children_flags;
2063       ClutterActorBox children_box;
2064
2065       /* normalize the box passed to the layout manager */
2066       children_box.x1 = children_box.y1 = 0.f;
2067       children_box.x2 = (allocation->x2 - allocation->x1);
2068       children_box.y2 = (allocation->y2 - allocation->y1);
2069
2070       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2071        * the actor's children, since it refers only to the current
2072        * actor's allocation.
2073        */
2074       children_flags = flags;
2075       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2076
2077       CLUTTER_NOTE (LAYOUT,
2078                     "Allocating %d children of %s "
2079                     "at { %.2f, %.2f - %.2f x %.2f } "
2080                     "using %s",
2081                     priv->n_children,
2082                     _clutter_actor_get_debug_name (self),
2083                     allocation->x1,
2084                     allocation->y1,
2085                     (allocation->x2 - allocation->x1),
2086                     (allocation->y2 - allocation->y1),
2087                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2088
2089       clutter_layout_manager_allocate (priv->layout_manager,
2090                                        container,
2091                                        &children_box,
2092                                        children_flags);
2093     }
2094 }
2095
2096 static void
2097 clutter_actor_real_allocate (ClutterActor           *self,
2098                              const ClutterActorBox  *box,
2099                              ClutterAllocationFlags  flags)
2100 {
2101   ClutterActorPrivate *priv = self->priv;
2102   gboolean changed;
2103
2104   g_object_freeze_notify (G_OBJECT (self));
2105
2106   changed = clutter_actor_set_allocation_internal (self, box, flags);
2107
2108   /* we allocate our children before we notify changes in our geometry,
2109    * so that people connecting to properties will be able to get valid
2110    * data out of the sub-tree of the scene graph that has this actor at
2111    * the root.
2112    */
2113   clutter_actor_maybe_layout_children (self, box, flags);
2114
2115   if (changed)
2116     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2117                    &priv->allocation,
2118                    priv->allocation_flags);
2119
2120   g_object_thaw_notify (G_OBJECT (self));
2121 }
2122
2123 static void
2124 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2125                                     ClutterActor *origin)
2126 {
2127   /* no point in queuing a redraw on a destroyed actor */
2128   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2129     return;
2130
2131   /* NB: We can't bail out early here if the actor is hidden in case
2132    * the actor bas been cloned. In this case the clone will need to
2133    * receive the signal so it can queue its own redraw.
2134    */
2135
2136   /* calls klass->queue_redraw in default handler */
2137   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2138 }
2139
2140 static void
2141 clutter_actor_real_queue_redraw (ClutterActor *self,
2142                                  ClutterActor *origin)
2143 {
2144   ClutterActor *parent;
2145
2146   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2147                 _clutter_actor_get_debug_name (self),
2148                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2149                                : "same actor");
2150
2151   /* no point in queuing a redraw on a destroyed actor */
2152   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2153     return;
2154
2155   /* If the queue redraw is coming from a child then the actor has
2156      become dirty and any queued effect is no longer valid */
2157   if (self != origin)
2158     {
2159       self->priv->is_dirty = TRUE;
2160       self->priv->effect_to_redraw = NULL;
2161     }
2162
2163   /* If the actor isn't visible, we still had to emit the signal
2164    * to allow for a ClutterClone, but the appearance of the parent
2165    * won't change so we don't have to propagate up the hierarchy.
2166    */
2167   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2168     return;
2169
2170   /* Although we could determine here that a full stage redraw
2171    * has already been queued and immediately bail out, we actually
2172    * guarantee that we will propagate a queue-redraw signal to our
2173    * parent at least once so that it's possible to implement a
2174    * container that tracks which of its children have queued a
2175    * redraw.
2176    */
2177   if (self->priv->propagated_one_redraw)
2178     {
2179       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2180       if (stage != NULL &&
2181           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2182         return;
2183     }
2184
2185   self->priv->propagated_one_redraw = TRUE;
2186
2187   /* notify parents, if they are all visible eventually we'll
2188    * queue redraw on the stage, which queues the redraw idle.
2189    */
2190   parent = clutter_actor_get_parent (self);
2191   if (parent != NULL)
2192     {
2193       /* this will go up recursively */
2194       _clutter_actor_signal_queue_redraw (parent, origin);
2195     }
2196 }
2197
2198 static void
2199 clutter_actor_real_queue_relayout (ClutterActor *self)
2200 {
2201   ClutterActorPrivate *priv = self->priv;
2202
2203   /* no point in queueing a redraw on a destroyed actor */
2204   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2205     return;
2206
2207   priv->needs_width_request  = TRUE;
2208   priv->needs_height_request = TRUE;
2209   priv->needs_allocation     = TRUE;
2210
2211   /* reset the cached size requests */
2212   memset (priv->width_requests, 0,
2213           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2214   memset (priv->height_requests, 0,
2215           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2216
2217   /* We need to go all the way up the hierarchy */
2218   if (priv->parent != NULL)
2219     _clutter_actor_queue_only_relayout (priv->parent);
2220 }
2221
2222 /**
2223  * clutter_actor_apply_relative_transform_to_point:
2224  * @self: A #ClutterActor
2225  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2226  *   default #ClutterStage
2227  * @point: A point as #ClutterVertex
2228  * @vertex: (out caller-allocates): The translated #ClutterVertex
2229  *
2230  * Transforms @point in coordinates relative to the actor into
2231  * ancestor-relative coordinates using the relevant transform
2232  * stack (i.e. scale, rotation, etc).
2233  *
2234  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2235  * this case, the coordinates returned will be the coordinates on
2236  * the stage before the projection is applied. This is different from
2237  * the behaviour of clutter_actor_apply_transform_to_point().
2238  *
2239  * Since: 0.6
2240  */
2241 void
2242 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2243                                                  ClutterActor        *ancestor,
2244                                                  const ClutterVertex *point,
2245                                                  ClutterVertex       *vertex)
2246 {
2247   gfloat w;
2248   CoglMatrix matrix;
2249
2250   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2251   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2252   g_return_if_fail (point != NULL);
2253   g_return_if_fail (vertex != NULL);
2254
2255   *vertex = *point;
2256   w = 1.0;
2257
2258   if (ancestor == NULL)
2259     ancestor = _clutter_actor_get_stage_internal (self);
2260
2261   if (ancestor == NULL)
2262     {
2263       *vertex = *point;
2264       return;
2265     }
2266
2267   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2268   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2269 }
2270
2271 static gboolean
2272 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2273                                          const ClutterVertex *vertices_in,
2274                                          ClutterVertex *vertices_out,
2275                                          int n_vertices)
2276 {
2277   ClutterActor *stage;
2278   CoglMatrix modelview;
2279   CoglMatrix projection;
2280   float viewport[4];
2281
2282   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2283
2284   stage = _clutter_actor_get_stage_internal (self);
2285
2286   /* We really can't do anything meaningful in this case so don't try
2287    * to do any transform */
2288   if (stage == NULL)
2289     return FALSE;
2290
2291   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2292    * that gets us to stage coordinates, we want to go all the way to eye
2293    * coordinates */
2294   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2295
2296   /* Fetch the projection and viewport */
2297   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2298   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2299                                &viewport[0],
2300                                &viewport[1],
2301                                &viewport[2],
2302                                &viewport[3]);
2303
2304   _clutter_util_fully_transform_vertices (&modelview,
2305                                           &projection,
2306                                           viewport,
2307                                           vertices_in,
2308                                           vertices_out,
2309                                           n_vertices);
2310
2311   return TRUE;
2312 }
2313
2314 /**
2315  * clutter_actor_apply_transform_to_point:
2316  * @self: A #ClutterActor
2317  * @point: A point as #ClutterVertex
2318  * @vertex: (out caller-allocates): The translated #ClutterVertex
2319  *
2320  * Transforms @point in coordinates relative to the actor
2321  * into screen-relative coordinates with the current actor
2322  * transformation (i.e. scale, rotation, etc)
2323  *
2324  * Since: 0.4
2325  **/
2326 void
2327 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2328                                         const ClutterVertex *point,
2329                                         ClutterVertex       *vertex)
2330 {
2331   g_return_if_fail (point != NULL);
2332   g_return_if_fail (vertex != NULL);
2333   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2334 }
2335
2336 /*
2337  * _clutter_actor_get_relative_transformation_matrix:
2338  * @self: The actor whose coordinate space you want to transform from.
2339  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2340  *            or %NULL if you want to transform all the way to eye coordinates.
2341  * @matrix: A #CoglMatrix to store the transformation
2342  *
2343  * This gets a transformation @matrix that will transform coordinates from the
2344  * coordinate space of @self into the coordinate space of @ancestor.
2345  *
2346  * For example if you need a matrix that can transform the local actor
2347  * coordinates of @self into stage coordinates you would pass the actor's stage
2348  * pointer as the @ancestor.
2349  *
2350  * If you pass %NULL then the transformation will take you all the way through
2351  * to eye coordinates. This can be useful if you want to extract the entire
2352  * modelview transform that Clutter applies before applying the projection
2353  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2354  * using cogl_set_modelview_matrix() for example then you would want a matrix
2355  * that transforms into eye coordinates.
2356  *
2357  * <note><para>This function explicitly initializes the given @matrix. If you just
2358  * want clutter to multiply a relative transformation with an existing matrix
2359  * you can use clutter_actor_apply_relative_transformation_matrix()
2360  * instead.</para></note>
2361  *
2362  */
2363 /* XXX: We should consider caching the stage relative modelview along with
2364  * the actor itself */
2365 static void
2366 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2367                                                    ClutterActor *ancestor,
2368                                                    CoglMatrix *matrix)
2369 {
2370   cogl_matrix_init_identity (matrix);
2371
2372   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2373 }
2374
2375 /* Project the given @box into stage window coordinates, writing the
2376  * transformed vertices to @verts[]. */
2377 static gboolean
2378 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2379                                           const ClutterActorBox *box,
2380                                           ClutterVertex          verts[])
2381 {
2382   ClutterVertex box_vertices[4];
2383
2384   box_vertices[0].x = box->x1;
2385   box_vertices[0].y = box->y1;
2386   box_vertices[0].z = 0;
2387   box_vertices[1].x = box->x2;
2388   box_vertices[1].y = box->y1;
2389   box_vertices[1].z = 0;
2390   box_vertices[2].x = box->x1;
2391   box_vertices[2].y = box->y2;
2392   box_vertices[2].z = 0;
2393   box_vertices[3].x = box->x2;
2394   box_vertices[3].y = box->y2;
2395   box_vertices[3].z = 0;
2396
2397   return
2398     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2399 }
2400
2401 /**
2402  * clutter_actor_get_allocation_vertices:
2403  * @self: A #ClutterActor
2404  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2405  *   against, or %NULL to use the #ClutterStage
2406  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2407  *   location for an array of 4 #ClutterVertex in which to store the result
2408  *
2409  * Calculates the transformed coordinates of the four corners of the
2410  * actor in the plane of @ancestor. The returned vertices relate to
2411  * the #ClutterActorBox coordinates as follows:
2412  * <itemizedlist>
2413  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2414  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2415  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2416  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2417  * </itemizedlist>
2418  *
2419  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2420  * this case, the coordinates returned will be the coordinates on
2421  * the stage before the projection is applied. This is different from
2422  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2423  *
2424  * Since: 0.6
2425  */
2426 void
2427 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2428                                        ClutterActor  *ancestor,
2429                                        ClutterVertex  verts[])
2430 {
2431   ClutterActorPrivate *priv;
2432   ClutterActorBox box;
2433   ClutterVertex vertices[4];
2434   CoglMatrix modelview;
2435
2436   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2437   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2438
2439   if (ancestor == NULL)
2440     ancestor = _clutter_actor_get_stage_internal (self);
2441
2442   /* Fallback to a NOP transform if the actor isn't parented under a
2443    * stage. */
2444   if (ancestor == NULL)
2445     ancestor = self;
2446
2447   priv = self->priv;
2448
2449   /* if the actor needs to be allocated we force a relayout, so that
2450    * we will have valid values to use in the transformations */
2451   if (priv->needs_allocation)
2452     {
2453       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2454       if (stage)
2455         _clutter_stage_maybe_relayout (stage);
2456       else
2457         {
2458           box.x1 = box.y1 = 0;
2459           /* The result isn't really meaningful in this case but at
2460            * least try to do something *vaguely* reasonable... */
2461           clutter_actor_get_size (self, &box.x2, &box.y2);
2462         }
2463     }
2464
2465   clutter_actor_get_allocation_box (self, &box);
2466
2467   vertices[0].x = box.x1;
2468   vertices[0].y = box.y1;
2469   vertices[0].z = 0;
2470   vertices[1].x = box.x2;
2471   vertices[1].y = box.y1;
2472   vertices[1].z = 0;
2473   vertices[2].x = box.x1;
2474   vertices[2].y = box.y2;
2475   vertices[2].z = 0;
2476   vertices[3].x = box.x2;
2477   vertices[3].y = box.y2;
2478   vertices[3].z = 0;
2479
2480   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2481                                                      &modelview);
2482
2483   cogl_matrix_transform_points (&modelview,
2484                                 3,
2485                                 sizeof (ClutterVertex),
2486                                 vertices,
2487                                 sizeof (ClutterVertex),
2488                                 vertices,
2489                                 4);
2490 }
2491
2492 /**
2493  * clutter_actor_get_abs_allocation_vertices:
2494  * @self: A #ClutterActor
2495  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2496  *   of 4 #ClutterVertex where to store the result.
2497  *
2498  * Calculates the transformed screen coordinates of the four corners of
2499  * the actor; the returned vertices relate to the #ClutterActorBox
2500  * coordinates  as follows:
2501  * <itemizedlist>
2502  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2503  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2504  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2505  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2506  * </itemizedlist>
2507  *
2508  * Since: 0.4
2509  */
2510 void
2511 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2512                                            ClutterVertex  verts[])
2513 {
2514   ClutterActorPrivate *priv;
2515   ClutterActorBox actor_space_allocation;
2516
2517   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2518
2519   priv = self->priv;
2520
2521   /* if the actor needs to be allocated we force a relayout, so that
2522    * the actor allocation box will be valid for
2523    * _clutter_actor_transform_and_project_box()
2524    */
2525   if (priv->needs_allocation)
2526     {
2527       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2528       /* There's nothing meaningful we can do now */
2529       if (!stage)
2530         return;
2531
2532       _clutter_stage_maybe_relayout (stage);
2533     }
2534
2535   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2536    * own coordinate space... */
2537   actor_space_allocation.x1 = 0;
2538   actor_space_allocation.y1 = 0;
2539   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2540   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2541   _clutter_actor_transform_and_project_box (self,
2542                                             &actor_space_allocation,
2543                                             verts);
2544 }
2545
2546 static void
2547 clutter_actor_real_apply_transform (ClutterActor *self,
2548                                     CoglMatrix   *matrix)
2549 {
2550   ClutterActorPrivate *priv = self->priv;
2551
2552   if (!priv->transform_valid)
2553     {
2554       CoglMatrix *transform = &priv->transform;
2555       const ClutterTransformInfo *info;
2556
2557       info = _clutter_actor_get_transform_info_or_defaults (self);
2558
2559       cogl_matrix_init_identity (transform);
2560
2561       cogl_matrix_translate (transform,
2562                              priv->allocation.x1,
2563                              priv->allocation.y1,
2564                              0.0);
2565
2566       if (priv->z)
2567         cogl_matrix_translate (transform, 0, 0, priv->z);
2568
2569       /*
2570        * because the rotation involves translations, we must scale
2571        * before applying the rotations (if we apply the scale after
2572        * the rotations, the translations included in the rotation are
2573        * not scaled and so the entire object will move on the screen
2574        * as a result of rotating it).
2575        */
2576       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2577         {
2578           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2579                                         &info->scale_center,
2580                                         cogl_matrix_scale (transform,
2581                                                            info->scale_x,
2582                                                            info->scale_y,
2583                                                            1.0));
2584         }
2585
2586       if (info->rz_angle)
2587         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2588                                       &info->rz_center,
2589                                       cogl_matrix_rotate (transform,
2590                                                           info->rz_angle,
2591                                                           0, 0, 1.0));
2592
2593       if (info->ry_angle)
2594         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2595                                       &info->ry_center,
2596                                       cogl_matrix_rotate (transform,
2597                                                           info->ry_angle,
2598                                                           0, 1.0, 0));
2599
2600       if (info->rx_angle)
2601         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2602                                       &info->rx_center,
2603                                       cogl_matrix_rotate (transform,
2604                                                           info->rx_angle,
2605                                                           1.0, 0, 0));
2606
2607       if (!clutter_anchor_coord_is_zero (&info->anchor))
2608         {
2609           gfloat x, y, z;
2610
2611           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2612           cogl_matrix_translate (transform, -x, -y, -z);
2613         }
2614
2615       priv->transform_valid = TRUE;
2616     }
2617
2618   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2619 }
2620
2621 /* Applies the transforms associated with this actor to the given
2622  * matrix. */
2623 void
2624 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2625                                           CoglMatrix *matrix)
2626 {
2627   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2628 }
2629
2630 /*
2631  * clutter_actor_apply_relative_transformation_matrix:
2632  * @self: The actor whose coordinate space you want to transform from.
2633  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2634  *            or %NULL if you want to transform all the way to eye coordinates.
2635  * @matrix: A #CoglMatrix to apply the transformation too.
2636  *
2637  * This multiplies a transform with @matrix that will transform coordinates
2638  * from the coordinate space of @self into the coordinate space of @ancestor.
2639  *
2640  * For example if you need a matrix that can transform the local actor
2641  * coordinates of @self into stage coordinates you would pass the actor's stage
2642  * pointer as the @ancestor.
2643  *
2644  * If you pass %NULL then the transformation will take you all the way through
2645  * to eye coordinates. This can be useful if you want to extract the entire
2646  * modelview transform that Clutter applies before applying the projection
2647  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2648  * using cogl_set_modelview_matrix() for example then you would want a matrix
2649  * that transforms into eye coordinates.
2650  *
2651  * <note>This function doesn't initialize the given @matrix, it simply
2652  * multiplies the requested transformation matrix with the existing contents of
2653  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2654  * before calling this function, or you can use
2655  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2656  */
2657 void
2658 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2659                                                      ClutterActor *ancestor,
2660                                                      CoglMatrix *matrix)
2661 {
2662   ClutterActor *parent;
2663
2664   /* Note we terminate before ever calling stage->apply_transform()
2665    * since that would conceptually be relative to the underlying
2666    * window OpenGL coordinates so we'd need a special @ancestor
2667    * value to represent the fake parent of the stage. */
2668   if (self == ancestor)
2669     return;
2670
2671   parent = clutter_actor_get_parent (self);
2672
2673   if (parent != NULL)
2674     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2675                                                          matrix);
2676
2677   _clutter_actor_apply_modelview_transform (self, matrix);
2678 }
2679
2680 static void
2681 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2682                                        ClutterPaintVolume *pv,
2683                                        const char *label,
2684                                        const CoglColor *color)
2685 {
2686   static CoglPipeline *outline = NULL;
2687   CoglPrimitive *prim;
2688   ClutterVertex line_ends[12 * 2];
2689   int n_vertices;
2690   CoglContext *ctx =
2691     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2692   /* XXX: at some point we'll query this from the stage but we can't
2693    * do that until the osx backend uses Cogl natively. */
2694   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2695
2696   if (outline == NULL)
2697     outline = cogl_pipeline_new (ctx);
2698
2699   _clutter_paint_volume_complete (pv);
2700
2701   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2702
2703   /* Front face */
2704   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2705   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2706   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2707   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2708
2709   if (!pv->is_2d)
2710     {
2711       /* Back face */
2712       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2713       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2714       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2715       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2716
2717       /* Lines connecting front face to back face */
2718       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2719       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2720       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2721       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2722     }
2723
2724   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2725                                 n_vertices,
2726                                 (CoglVertexP3 *)line_ends);
2727
2728   cogl_pipeline_set_color (outline, color);
2729   cogl_framebuffer_draw_primitive (fb, outline, prim);
2730   cogl_object_unref (prim);
2731
2732   if (label)
2733     {
2734       PangoLayout *layout;
2735       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2736       pango_layout_set_text (layout, label, -1);
2737       cogl_pango_render_layout (layout,
2738                                 pv->vertices[0].x,
2739                                 pv->vertices[0].y,
2740                                 color,
2741                                 0);
2742       g_object_unref (layout);
2743     }
2744 }
2745
2746 static void
2747 _clutter_actor_draw_paint_volume (ClutterActor *self)
2748 {
2749   ClutterPaintVolume *pv;
2750   CoglColor color;
2751
2752   pv = _clutter_actor_get_paint_volume_mutable (self);
2753   if (!pv)
2754     {
2755       gfloat width, height;
2756       ClutterPaintVolume fake_pv;
2757
2758       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2759       _clutter_paint_volume_init_static (&fake_pv, stage);
2760
2761       clutter_actor_get_size (self, &width, &height);
2762       clutter_paint_volume_set_width (&fake_pv, width);
2763       clutter_paint_volume_set_height (&fake_pv, height);
2764
2765       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2766       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2767                                              _clutter_actor_get_debug_name (self),
2768                                              &color);
2769
2770       clutter_paint_volume_free (&fake_pv);
2771     }
2772   else
2773     {
2774       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2775       _clutter_actor_draw_paint_volume_full (self, pv,
2776                                              _clutter_actor_get_debug_name (self),
2777                                              &color);
2778     }
2779 }
2780
2781 static void
2782 _clutter_actor_paint_cull_result (ClutterActor *self,
2783                                   gboolean success,
2784                                   ClutterCullResult result)
2785 {
2786   ClutterPaintVolume *pv;
2787   CoglColor color;
2788
2789   if (success)
2790     {
2791       if (result == CLUTTER_CULL_RESULT_IN)
2792         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2793       else if (result == CLUTTER_CULL_RESULT_OUT)
2794         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2795       else
2796         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2797     }
2798   else
2799     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2800
2801   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2802     _clutter_actor_draw_paint_volume_full (self, pv,
2803                                            _clutter_actor_get_debug_name (self),
2804                                            &color);
2805   else
2806     {
2807       PangoLayout *layout;
2808       char *label =
2809         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2810       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2811       cogl_set_source_color (&color);
2812
2813       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2814       pango_layout_set_text (layout, label, -1);
2815       cogl_pango_render_layout (layout,
2816                                 0,
2817                                 0,
2818                                 &color,
2819                                 0);
2820       g_free (label);
2821       g_object_unref (layout);
2822     }
2823 }
2824
2825 static int clone_paint_level = 0;
2826
2827 void
2828 _clutter_actor_push_clone_paint (void)
2829 {
2830   clone_paint_level++;
2831 }
2832
2833 void
2834 _clutter_actor_pop_clone_paint (void)
2835 {
2836   clone_paint_level--;
2837 }
2838
2839 static gboolean
2840 in_clone_paint (void)
2841 {
2842   return clone_paint_level > 0;
2843 }
2844
2845 /* Returns TRUE if the actor can be ignored */
2846 /* FIXME: we should return a ClutterCullResult, and
2847  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2848  * means there's no point in trying to cull descendants of the current
2849  * node. */
2850 static gboolean
2851 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2852 {
2853   ClutterActorPrivate *priv = self->priv;
2854   ClutterActor *stage;
2855   const ClutterPlane *stage_clip;
2856
2857   if (!priv->last_paint_volume_valid)
2858     {
2859       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2860                     "->last_paint_volume_valid == FALSE",
2861                     _clutter_actor_get_debug_name (self));
2862       return FALSE;
2863     }
2864
2865   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2866     return FALSE;
2867
2868   stage = _clutter_actor_get_stage_internal (self);
2869   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2870   if (G_UNLIKELY (!stage_clip))
2871     {
2872       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2873                     "No stage clip set",
2874                     _clutter_actor_get_debug_name (self));
2875       return FALSE;
2876     }
2877
2878   if (cogl_get_draw_framebuffer () !=
2879       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2880     {
2881       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2882                     "Current framebuffer doesn't correspond to stage",
2883                     _clutter_actor_get_debug_name (self));
2884       return FALSE;
2885     }
2886
2887   *result_out =
2888     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2889   return TRUE;
2890 }
2891
2892 static void
2893 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2894 {
2895   ClutterActorPrivate *priv = self->priv;
2896   const ClutterPaintVolume *pv;
2897
2898   if (priv->last_paint_volume_valid)
2899     {
2900       clutter_paint_volume_free (&priv->last_paint_volume);
2901       priv->last_paint_volume_valid = FALSE;
2902     }
2903
2904   pv = clutter_actor_get_paint_volume (self);
2905   if (!pv)
2906     {
2907       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2908                     "Actor failed to report a paint volume",
2909                     _clutter_actor_get_debug_name (self));
2910       return;
2911     }
2912
2913   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2914
2915   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2916                                             NULL); /* eye coordinates */
2917
2918   priv->last_paint_volume_valid = TRUE;
2919 }
2920
2921 static inline gboolean
2922 actor_has_shader_data (ClutterActor *self)
2923 {
2924   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2925 }
2926
2927 guint32
2928 _clutter_actor_get_pick_id (ClutterActor *self)
2929 {
2930   if (self->priv->pick_id < 0)
2931     return 0;
2932
2933   return self->priv->pick_id;
2934 }
2935
2936 /* This is the same as clutter_actor_add_effect except that it doesn't
2937    queue a redraw and it doesn't notify on the effect property */
2938 static void
2939 _clutter_actor_add_effect_internal (ClutterActor  *self,
2940                                     ClutterEffect *effect)
2941 {
2942   ClutterActorPrivate *priv = self->priv;
2943
2944   if (priv->effects == NULL)
2945     {
2946       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
2947       priv->effects->actor = self;
2948     }
2949
2950   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2951 }
2952
2953 /* This is the same as clutter_actor_remove_effect except that it doesn't
2954    queue a redraw and it doesn't notify on the effect property */
2955 static void
2956 _clutter_actor_remove_effect_internal (ClutterActor  *self,
2957                                        ClutterEffect *effect)
2958 {
2959   ClutterActorPrivate *priv = self->priv;
2960
2961   if (priv->effects == NULL)
2962     return;
2963
2964   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2965 }
2966
2967 static gboolean
2968 needs_flatten_effect (ClutterActor *self)
2969 {
2970   ClutterActorPrivate *priv = self->priv;
2971
2972   if (G_UNLIKELY (clutter_paint_debug_flags &
2973                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
2974     return FALSE;
2975
2976   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
2977     return TRUE;
2978   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
2979     {
2980       if (clutter_actor_get_paint_opacity (self) < 255 &&
2981           clutter_actor_has_overlaps (self))
2982         return TRUE;
2983     }
2984
2985   return FALSE;
2986 }
2987
2988 static void
2989 add_or_remove_flatten_effect (ClutterActor *self)
2990 {
2991   ClutterActorPrivate *priv = self->priv;
2992
2993   /* Add or remove the flatten effect depending on the
2994      offscreen-redirect property. */
2995   if (needs_flatten_effect (self))
2996     {
2997       if (priv->flatten_effect == NULL)
2998         {
2999           ClutterActorMeta *actor_meta;
3000           gint priority;
3001
3002           priv->flatten_effect = _clutter_flatten_effect_new ();
3003           /* Keep a reference to the effect so that we can queue
3004              redraws from it */
3005           g_object_ref_sink (priv->flatten_effect);
3006
3007           /* Set the priority of the effect to high so that it will
3008              always be applied to the actor first. It uses an internal
3009              priority so that it won't be visible to applications */
3010           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3011           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3012           _clutter_actor_meta_set_priority (actor_meta, priority);
3013
3014           /* This will add the effect without queueing a redraw */
3015           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3016         }
3017     }
3018   else
3019     {
3020       if (priv->flatten_effect != NULL)
3021         {
3022           /* Destroy the effect so that it will lose its fbo cache of
3023              the actor */
3024           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3025           g_object_unref (priv->flatten_effect);
3026           priv->flatten_effect = NULL;
3027         }
3028     }
3029 }
3030
3031 static void
3032 clutter_actor_real_paint (ClutterActor *actor)
3033 {
3034   ClutterActorPrivate *priv = actor->priv;
3035   ClutterActor *iter;
3036
3037   /* paint the background color, if set */
3038   if (priv->bg_color_set)
3039     {
3040       float width, height;
3041       guint8 real_alpha;
3042
3043       clutter_actor_box_get_size (&priv->allocation, &width, &height);
3044
3045       real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3046                  * priv->bg_color.alpha
3047                  / 255;
3048
3049       cogl_set_source_color4ub (priv->bg_color.red,
3050                                 priv->bg_color.green,
3051                                 priv->bg_color.blue,
3052                                 real_alpha);
3053
3054       cogl_rectangle (0, 0, width, height);
3055     }
3056
3057   for (iter = priv->first_child;
3058        iter != NULL;
3059        iter = iter->priv->next_sibling)
3060     {
3061       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3062                     _clutter_actor_get_debug_name (iter),
3063                     _clutter_actor_get_debug_name (actor),
3064                     iter->priv->allocation.x1,
3065                     iter->priv->allocation.y1,
3066                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3067                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3068
3069       clutter_actor_paint (iter);
3070     }
3071 }
3072
3073 /**
3074  * clutter_actor_paint:
3075  * @self: A #ClutterActor
3076  *
3077  * Renders the actor to display.
3078  *
3079  * This function should not be called directly by applications.
3080  * Call clutter_actor_queue_redraw() to queue paints, instead.
3081  *
3082  * This function is context-aware, and will either cause a
3083  * regular paint or a pick paint.
3084  *
3085  * This function will emit the #ClutterActor::paint signal or
3086  * the #ClutterActor::pick signal, depending on the context.
3087  *
3088  * This function does not paint the actor if the actor is set to 0,
3089  * unless it is performing a pick paint.
3090  */
3091 void
3092 clutter_actor_paint (ClutterActor *self)
3093 {
3094   ClutterActorPrivate *priv;
3095   ClutterPickMode pick_mode;
3096   gboolean clip_set = FALSE;
3097   gboolean shader_applied = FALSE;
3098
3099   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3100                           "Actor real-paint counter",
3101                           "Increments each time any actor is painted",
3102                           0 /* no application private data */);
3103   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3104                           "Actor pick-paint counter",
3105                           "Increments each time any actor is painted "
3106                           "for picking",
3107                           0 /* no application private data */);
3108
3109   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3110
3111   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3112     return;
3113
3114   priv = self->priv;
3115
3116   pick_mode = _clutter_context_get_pick_mode ();
3117
3118   if (pick_mode == CLUTTER_PICK_NONE)
3119     priv->propagated_one_redraw = FALSE;
3120
3121   /* It's an important optimization that we consider painting of
3122    * actors with 0 opacity to be a NOP... */
3123   if (pick_mode == CLUTTER_PICK_NONE &&
3124       /* ignore top-levels, since they might be transparent */
3125       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3126       /* Use the override opacity if its been set */
3127       ((priv->opacity_override >= 0) ?
3128        priv->opacity_override : priv->opacity) == 0)
3129     return;
3130
3131   /* if we aren't paintable (not in a toplevel with all
3132    * parents paintable) then do nothing.
3133    */
3134   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3135     return;
3136
3137   /* mark that we are in the paint process */
3138   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3139
3140   cogl_push_matrix();
3141
3142   if (priv->enable_model_view_transform)
3143     {
3144       CoglMatrix matrix;
3145
3146       /* XXX: It could be better to cache the modelview with the actor
3147        * instead of progressively building up the transformations on
3148        * the matrix stack every time we paint. */
3149       cogl_get_modelview_matrix (&matrix);
3150       _clutter_actor_apply_modelview_transform (self, &matrix);
3151
3152 #ifdef CLUTTER_ENABLE_DEBUG
3153       /* Catch when out-of-band transforms have been made by actors not as part
3154        * of an apply_transform vfunc... */
3155       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3156         {
3157           CoglMatrix expected_matrix;
3158
3159           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3160                                                              &expected_matrix);
3161
3162           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3163             {
3164               GString *buf = g_string_sized_new (1024);
3165               ClutterActor *parent;
3166
3167               parent = self;
3168               while (parent != NULL)
3169                 {
3170                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3171
3172                   if (parent->priv->parent != NULL)
3173                     g_string_append (buf, "->");
3174
3175                   parent = parent->priv->parent;
3176                 }
3177
3178               g_warning ("Unexpected transform found when painting actor "
3179                          "\"%s\". This will be caused by one of the actor's "
3180                          "ancestors (%s) using the Cogl API directly to transform "
3181                          "children instead of using ::apply_transform().",
3182                          _clutter_actor_get_debug_name (self),
3183                          buf->str);
3184
3185               g_string_free (buf, TRUE);
3186             }
3187         }
3188 #endif /* CLUTTER_ENABLE_DEBUG */
3189
3190       cogl_set_modelview_matrix (&matrix);
3191     }
3192
3193   if (priv->has_clip)
3194     {
3195       cogl_clip_push_rectangle (priv->clip.x,
3196                                 priv->clip.y,
3197                                 priv->clip.x + priv->clip.width,
3198                                 priv->clip.y + priv->clip.height);
3199       clip_set = TRUE;
3200     }
3201   else if (priv->clip_to_allocation)
3202     {
3203       gfloat width, height;
3204
3205       width  = priv->allocation.x2 - priv->allocation.x1;
3206       height = priv->allocation.y2 - priv->allocation.y1;
3207
3208       cogl_clip_push_rectangle (0, 0, width, height);
3209       clip_set = TRUE;
3210     }
3211
3212   if (pick_mode == CLUTTER_PICK_NONE)
3213     {
3214       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3215
3216       /* We check whether we need to add the flatten effect before
3217          each paint so that we can avoid having a mechanism for
3218          applications to notify when the value of the
3219          has_overlaps virtual changes. */
3220       add_or_remove_flatten_effect (self);
3221     }
3222   else
3223     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3224
3225   /* We save the current paint volume so that the next time the
3226    * actor queues a redraw we can constrain the redraw to just
3227    * cover the union of the new bounding box and the old.
3228    *
3229    * We also fetch the current paint volume to perform culling so
3230    * we can avoid painting actors outside the current clip region.
3231    *
3232    * If we are painting inside a clone, we should neither update
3233    * the paint volume or use it to cull painting, since the paint
3234    * box represents the location of the source actor on the
3235    * screen.
3236    *
3237    * XXX: We are starting to do a lot of vertex transforms on
3238    * the CPU in a typical paint, so at some point we should
3239    * audit these and consider caching some things.
3240    *
3241    * NB: We don't perform culling while picking at this point because
3242    * clutter-stage.c doesn't setup the clipping planes appropriately.
3243    *
3244    * NB: We don't want to update the last-paint-volume during picking
3245    * because the last-paint-volume is used to determine the old screen
3246    * space location of an actor that has moved so we can know the
3247    * minimal region to redraw to clear an old view of the actor. If we
3248    * update this during picking then by the time we come around to
3249    * paint then the last-paint-volume would likely represent the new
3250    * actor position not the old.
3251    */
3252   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3253     {
3254       gboolean success;
3255       /* annoyingly gcc warns if uninitialized even though
3256        * the initialization is redundant :-( */
3257       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3258
3259       if (G_LIKELY ((clutter_paint_debug_flags &
3260                      (CLUTTER_DEBUG_DISABLE_CULLING |
3261                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3262                     (CLUTTER_DEBUG_DISABLE_CULLING |
3263                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3264         _clutter_actor_update_last_paint_volume (self);
3265
3266       success = cull_actor (self, &result);
3267
3268       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3269         _clutter_actor_paint_cull_result (self, success, result);
3270       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3271         goto done;
3272     }
3273
3274   if (priv->effects == NULL)
3275     {
3276       if (pick_mode == CLUTTER_PICK_NONE &&
3277           actor_has_shader_data (self))
3278         {
3279           _clutter_actor_shader_pre_paint (self, FALSE);
3280           shader_applied = TRUE;
3281         }
3282
3283       priv->next_effect_to_paint = NULL;
3284     }
3285   else
3286     priv->next_effect_to_paint =
3287       _clutter_meta_group_peek_metas (priv->effects);
3288
3289   clutter_actor_continue_paint (self);
3290
3291   if (shader_applied)
3292     _clutter_actor_shader_post_paint (self);
3293
3294   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3295                   pick_mode == CLUTTER_PICK_NONE))
3296     _clutter_actor_draw_paint_volume (self);
3297
3298 done:
3299   /* If we make it here then the actor has run through a complete
3300      paint run including all the effects so it's no longer dirty */
3301   if (pick_mode == CLUTTER_PICK_NONE)
3302     priv->is_dirty = FALSE;
3303
3304   if (clip_set)
3305     cogl_clip_pop();
3306
3307   cogl_pop_matrix();
3308
3309   /* paint sequence complete */
3310   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3311 }
3312
3313 /**
3314  * clutter_actor_continue_paint:
3315  * @self: A #ClutterActor
3316  *
3317  * Run the next stage of the paint sequence. This function should only
3318  * be called within the implementation of the ‘run’ virtual of a
3319  * #ClutterEffect. It will cause the run method of the next effect to
3320  * be applied, or it will paint the actual actor if the current effect
3321  * is the last effect in the chain.
3322  *
3323  * Since: 1.8
3324  */
3325 void
3326 clutter_actor_continue_paint (ClutterActor *self)
3327 {
3328   ClutterActorPrivate *priv;
3329
3330   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3331   /* This should only be called from with in the ‘run’ implementation
3332      of a ClutterEffect */
3333   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3334
3335   priv = self->priv;
3336
3337   /* Skip any effects that are disabled */
3338   while (priv->next_effect_to_paint &&
3339          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3340     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3341
3342   /* If this has come from the last effect then we'll just paint the
3343      actual actor */
3344   if (priv->next_effect_to_paint == NULL)
3345     {
3346       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3347         {
3348           g_signal_emit (self, actor_signals[PAINT], 0);
3349         }
3350       else
3351         {
3352           ClutterColor col = { 0, };
3353
3354           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3355
3356           /* Actor will then paint silhouette of itself in supplied
3357            * color.  See clutter_stage_get_actor_at_pos() for where
3358            * picking is enabled.
3359            */
3360           g_signal_emit (self, actor_signals[PICK], 0, &col);
3361         }
3362     }
3363   else
3364     {
3365       ClutterEffect *old_current_effect;
3366       ClutterEffectPaintFlags run_flags = 0;
3367
3368       /* Cache the current effect so that we can put it back before
3369          returning */
3370       old_current_effect = priv->current_effect;
3371
3372       priv->current_effect = priv->next_effect_to_paint->data;
3373       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3374
3375       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3376         {
3377           if (priv->is_dirty)
3378             {
3379               /* If there's an effect queued with this redraw then all
3380                  effects up to that one will be considered dirty. It
3381                  is expected the queued effect will paint the cached
3382                  image and not call clutter_actor_continue_paint again
3383                  (although it should work ok if it does) */
3384               if (priv->effect_to_redraw == NULL ||
3385                   priv->current_effect != priv->effect_to_redraw)
3386                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3387             }
3388
3389           _clutter_effect_paint (priv->current_effect, run_flags);
3390         }
3391       else
3392         {
3393           /* We can't determine when an actor has been modified since
3394              its last pick so lets just assume it has always been
3395              modified */
3396           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3397
3398           _clutter_effect_pick (priv->current_effect, run_flags);
3399         }
3400
3401       priv->current_effect = old_current_effect;
3402     }
3403 }
3404
3405 static ClutterActorTraverseVisitFlags
3406 invalidate_queue_redraw_entry (ClutterActor *self,
3407                                int           depth,
3408                                gpointer      user_data)
3409 {
3410   ClutterActorPrivate *priv = self->priv;
3411
3412   if (priv->queue_redraw_entry != NULL)
3413     {
3414       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3415       priv->queue_redraw_entry = NULL;
3416     }
3417
3418   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3419 }
3420
3421 static inline void
3422 remove_child (ClutterActor *self,
3423               ClutterActor *child)
3424 {
3425   ClutterActor *prev_sibling, *next_sibling;
3426
3427   prev_sibling = child->priv->prev_sibling;
3428   next_sibling = child->priv->next_sibling;
3429
3430   if (prev_sibling != NULL)
3431     prev_sibling->priv->next_sibling = next_sibling;
3432
3433   if (next_sibling != NULL)
3434     next_sibling->priv->prev_sibling = prev_sibling;
3435
3436   if (self->priv->first_child == child)
3437     self->priv->first_child = next_sibling;
3438
3439   if (self->priv->last_child == child)
3440     self->priv->last_child = prev_sibling;
3441
3442   child->priv->parent = NULL;
3443   child->priv->prev_sibling = NULL;
3444   child->priv->next_sibling = NULL;
3445 }
3446
3447 typedef enum {
3448   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3449   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3450   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3451   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3452   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3453   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3454
3455   /* default flags for public API */
3456   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3457                                     REMOVE_CHILD_EMIT_PARENT_SET |
3458                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3459                                     REMOVE_CHILD_CHECK_STATE |
3460                                     REMOVE_CHILD_FLUSH_QUEUE |
3461                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3462
3463   /* flags for legacy/deprecated API */
3464   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3465                                     REMOVE_CHILD_FLUSH_QUEUE |
3466                                     REMOVE_CHILD_EMIT_PARENT_SET |
3467                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3468 } ClutterActorRemoveChildFlags;
3469
3470 /*< private >
3471  * clutter_actor_remove_child_internal:
3472  * @self: a #ClutterActor
3473  * @child: the child of @self that has to be removed
3474  * @flags: control the removal operations
3475  *
3476  * Removes @child from the list of children of @self.
3477  */
3478 static void
3479 clutter_actor_remove_child_internal (ClutterActor                 *self,
3480                                      ClutterActor                 *child,
3481                                      ClutterActorRemoveChildFlags  flags)
3482 {
3483   ClutterActor *old_first, *old_last;
3484   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3485   gboolean flush_queue;
3486   gboolean notify_first_last;
3487   gboolean was_mapped;
3488
3489   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3490   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3491   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3492   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3493   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3494   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3495
3496   g_object_freeze_notify (G_OBJECT (self));
3497
3498   if (destroy_meta)
3499     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3500
3501   if (check_state)
3502     {
3503       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3504
3505       /* we need to unrealize *before* we set parent_actor to NULL,
3506        * because in an unrealize method actors are dissociating from the
3507        * stage, which means they need to be able to
3508        * clutter_actor_get_stage().
3509        *
3510        * yhis should unmap and unrealize, unless we're reparenting.
3511        */
3512       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3513     }
3514   else
3515     was_mapped = FALSE;
3516
3517   if (flush_queue)
3518     {
3519       /* We take this opportunity to invalidate any queue redraw entry
3520        * associated with the actor and descendants since we won't be able to
3521        * determine the appropriate stage after this.
3522        *
3523        * we do this after we updated the mapped state because actors might
3524        * end up queueing redraws inside their mapped/unmapped virtual
3525        * functions, and if we invalidate the redraw entry we could end up
3526        * with an inconsistent state and weird memory corruption. see
3527        * bugs:
3528        *
3529        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3530        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3531        */
3532       _clutter_actor_traverse (child,
3533                                0,
3534                                invalidate_queue_redraw_entry,
3535                                NULL,
3536                                NULL);
3537     }
3538
3539   old_first = self->priv->first_child;
3540   old_last = self->priv->last_child;
3541
3542   remove_child (self, child);
3543
3544   self->priv->n_children -= 1;
3545
3546   self->priv->age += 1;
3547
3548   /* clutter_actor_reparent() will emit ::parent-set for us */
3549   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3550     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3551
3552   /* if the child was mapped then we need to relayout ourselves to account
3553    * for the removed child
3554    */
3555   if (was_mapped)
3556     clutter_actor_queue_relayout (self);
3557
3558   /* we need to emit the signal before dropping the reference */
3559   if (emit_actor_removed)
3560     g_signal_emit_by_name (self, "actor-removed", child);
3561
3562   if (notify_first_last)
3563     {
3564       if (old_first != self->priv->first_child)
3565         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3566
3567       if (old_last != self->priv->last_child)
3568         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3569     }
3570
3571   g_object_thaw_notify (G_OBJECT (self));
3572
3573   /* remove the reference we acquired in clutter_actor_add_child() */
3574   g_object_unref (child);
3575 }
3576
3577 static const ClutterTransformInfo default_transform_info = {
3578   0.0, { 0, },          /* rotation-x */
3579   0.0, { 0, },          /* rotation-y */
3580   0.0, { 0, },          /* rotation-z */
3581
3582   1.0, 1.0, { 0, },     /* scale */
3583
3584   { 0, },               /* anchor */
3585 };
3586
3587 /*< private >
3588  * _clutter_actor_get_transform_info_or_defaults:
3589  * @self: a #ClutterActor
3590  *
3591  * Retrieves the ClutterTransformInfo structure associated to an actor.
3592  *
3593  * If the actor does not have a ClutterTransformInfo structure associated
3594  * to it, then the default structure will be returned.
3595  *
3596  * This function should only be used for getters.
3597  *
3598  * Return value: a const pointer to the ClutterTransformInfo structure
3599  */
3600 const ClutterTransformInfo *
3601 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3602 {
3603   ClutterTransformInfo *info;
3604
3605   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3606   if (info != NULL)
3607     return info;
3608
3609   return &default_transform_info;
3610 }
3611
3612 static void
3613 clutter_transform_info_free (gpointer data)
3614 {
3615   if (data != NULL)
3616     g_slice_free (ClutterTransformInfo, data);
3617 }
3618
3619 /*< private >
3620  * _clutter_actor_get_transform_info:
3621  * @self: a #ClutterActor
3622  *
3623  * Retrieves a pointer to the ClutterTransformInfo structure.
3624  *
3625  * If the actor does not have a ClutterTransformInfo associated to it, one
3626  * will be created and initialized to the default values.
3627  *
3628  * This function should be used for setters.
3629  *
3630  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3631  * instead.
3632  *
3633  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3634  *   structure
3635  */
3636 ClutterTransformInfo *
3637 _clutter_actor_get_transform_info (ClutterActor *self)
3638 {
3639   ClutterTransformInfo *info;
3640
3641   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3642   if (info == NULL)
3643     {
3644       info = g_slice_new (ClutterTransformInfo);
3645
3646       *info = default_transform_info;
3647
3648       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3649                                info,
3650                                clutter_transform_info_free);
3651     }
3652
3653   return info;
3654 }
3655
3656 /*< private >
3657  * clutter_actor_set_rotation_angle_internal:
3658  * @self: a #ClutterActor
3659  * @axis: the axis of the angle to change
3660  * @angle: the angle of rotation
3661  *
3662  * Sets the rotation angle on the given axis without affecting the
3663  * rotation center point.
3664  */
3665 static inline void
3666 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3667                                            ClutterRotateAxis  axis,
3668                                            gdouble            angle)
3669 {
3670   GObject *obj = G_OBJECT (self);
3671   ClutterTransformInfo *info;
3672
3673   info = _clutter_actor_get_transform_info (self);
3674
3675   g_object_freeze_notify (obj);
3676
3677   switch (axis)
3678     {
3679     case CLUTTER_X_AXIS:
3680       info->rx_angle = angle;
3681       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3682       break;
3683
3684     case CLUTTER_Y_AXIS:
3685       info->ry_angle = angle;
3686       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3687       break;
3688
3689     case CLUTTER_Z_AXIS:
3690       info->rz_angle = angle;
3691       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3692       break;
3693     }
3694
3695   self->priv->transform_valid = FALSE;
3696
3697   g_object_thaw_notify (obj);
3698
3699   clutter_actor_queue_redraw (self);
3700 }
3701
3702 /*< private >
3703  * clutter_actor_set_rotation_center_internal:
3704  * @self: a #ClutterActor
3705  * @axis: the axis of the center to change
3706  * @center: the coordinates of the rotation center
3707  *
3708  * Sets the rotation center on the given axis without affecting the
3709  * rotation angle.
3710  */
3711 static inline void
3712 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3713                                             ClutterRotateAxis    axis,
3714                                             const ClutterVertex *center)
3715 {
3716   GObject *obj = G_OBJECT (self);
3717   ClutterTransformInfo *info;
3718   ClutterVertex v = { 0, 0, 0 };
3719
3720   info = _clutter_actor_get_transform_info (self);
3721
3722   if (center != NULL)
3723     v = *center;
3724
3725   g_object_freeze_notify (obj);
3726
3727   switch (axis)
3728     {
3729     case CLUTTER_X_AXIS:
3730       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3731       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3732       break;
3733
3734     case CLUTTER_Y_AXIS:
3735       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3736       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3737       break;
3738
3739     case CLUTTER_Z_AXIS:
3740       /* if the previously set rotation center was fractional, then
3741        * setting explicit coordinates will have to notify the
3742        * :rotation-center-z-gravity property as well
3743        */
3744       if (info->rz_center.is_fractional)
3745         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3746
3747       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3748       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3749       break;
3750     }
3751
3752   self->priv->transform_valid = FALSE;
3753
3754   g_object_thaw_notify (obj);
3755
3756   clutter_actor_queue_redraw (self);
3757 }
3758
3759 static inline void
3760 clutter_actor_set_scale_factor (ClutterActor      *self,
3761                                 ClutterRotateAxis  axis,
3762                                 gdouble            factor)
3763 {
3764   GObject *obj = G_OBJECT (self);
3765   ClutterTransformInfo *info;
3766
3767   info = _clutter_actor_get_transform_info (self);
3768
3769   g_object_freeze_notify (obj);
3770
3771   switch (axis)
3772     {
3773     case CLUTTER_X_AXIS:
3774       info->scale_x = factor;
3775       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
3776       break;
3777
3778     case CLUTTER_Y_AXIS:
3779       info->scale_y = factor;
3780       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
3781       break;
3782
3783     default:
3784       g_assert_not_reached ();
3785     }
3786
3787   self->priv->transform_valid = FALSE;
3788
3789   clutter_actor_queue_redraw (self);
3790
3791   g_object_thaw_notify (obj);
3792 }
3793
3794 static inline void
3795 clutter_actor_set_scale_center (ClutterActor      *self,
3796                                 ClutterRotateAxis  axis,
3797                                 gfloat             coord)
3798 {
3799   GObject *obj = G_OBJECT (self);
3800   ClutterTransformInfo *info;
3801   gfloat center_x, center_y;
3802
3803   info = _clutter_actor_get_transform_info (self);
3804
3805   g_object_freeze_notify (obj);
3806
3807   /* get the current scale center coordinates */
3808   clutter_anchor_coord_get_units (self, &info->scale_center,
3809                                   &center_x,
3810                                   &center_y,
3811                                   NULL);
3812
3813   /* we need to notify this too, because setting explicit coordinates will
3814    * change the gravity as a side effect
3815    */
3816   if (info->scale_center.is_fractional)
3817     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3818
3819   switch (axis)
3820     {
3821     case CLUTTER_X_AXIS:
3822       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3823       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3824       break;
3825
3826     case CLUTTER_Y_AXIS:
3827       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3828       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3829       break;
3830
3831     default:
3832       g_assert_not_reached ();
3833     }
3834
3835   self->priv->transform_valid = FALSE;
3836
3837   clutter_actor_queue_redraw (self);
3838
3839   g_object_thaw_notify (obj);
3840 }
3841
3842 static inline void
3843 clutter_actor_set_anchor_coord (ClutterActor      *self,
3844                                 ClutterRotateAxis  axis,
3845                                 gfloat             coord)
3846 {
3847   GObject *obj = G_OBJECT (self);
3848   ClutterTransformInfo *info;
3849   gfloat anchor_x, anchor_y;
3850
3851   info = _clutter_actor_get_transform_info (self);
3852
3853   g_object_freeze_notify (obj);
3854
3855   clutter_anchor_coord_get_units (self, &info->anchor,
3856                                   &anchor_x,
3857                                   &anchor_y,
3858                                   NULL);
3859
3860   if (info->anchor.is_fractional)
3861     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
3862
3863   switch (axis)
3864     {
3865     case CLUTTER_X_AXIS:
3866       clutter_anchor_coord_set_units (&info->anchor,
3867                                       coord,
3868                                       anchor_y,
3869                                       0.0);
3870       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
3871       break;
3872
3873     case CLUTTER_Y_AXIS:
3874       clutter_anchor_coord_set_units (&info->anchor,
3875                                       anchor_x,
3876                                       coord,
3877                                       0.0);
3878       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
3879       break;
3880
3881     default:
3882       g_assert_not_reached ();
3883     }
3884
3885   self->priv->transform_valid = FALSE;
3886
3887   clutter_actor_queue_redraw (self);
3888
3889   g_object_thaw_notify (obj);
3890 }
3891
3892 static void
3893 clutter_actor_set_property (GObject      *object,
3894                             guint         prop_id,
3895                             const GValue *value,
3896                             GParamSpec   *pspec)
3897 {
3898   ClutterActor *actor = CLUTTER_ACTOR (object);
3899   ClutterActorPrivate *priv = actor->priv;
3900
3901   switch (prop_id)
3902     {
3903     case PROP_X:
3904       clutter_actor_set_x (actor, g_value_get_float (value));
3905       break;
3906
3907     case PROP_Y:
3908       clutter_actor_set_y (actor, g_value_get_float (value));
3909       break;
3910
3911     case PROP_WIDTH:
3912       clutter_actor_set_width (actor, g_value_get_float (value));
3913       break;
3914
3915     case PROP_HEIGHT:
3916       clutter_actor_set_height (actor, g_value_get_float (value));
3917       break;
3918
3919     case PROP_FIXED_X:
3920       clutter_actor_set_x (actor, g_value_get_float (value));
3921       break;
3922
3923     case PROP_FIXED_Y:
3924       clutter_actor_set_y (actor, g_value_get_float (value));
3925       break;
3926
3927     case PROP_FIXED_POSITION_SET:
3928       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
3929       break;
3930
3931     case PROP_MIN_WIDTH:
3932       clutter_actor_set_min_width (actor, g_value_get_float (value));
3933       break;
3934
3935     case PROP_MIN_HEIGHT:
3936       clutter_actor_set_min_height (actor, g_value_get_float (value));
3937       break;
3938
3939     case PROP_NATURAL_WIDTH:
3940       clutter_actor_set_natural_width (actor, g_value_get_float (value));
3941       break;
3942
3943     case PROP_NATURAL_HEIGHT:
3944       clutter_actor_set_natural_height (actor, g_value_get_float (value));
3945       break;
3946
3947     case PROP_MIN_WIDTH_SET:
3948       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
3949       break;
3950
3951     case PROP_MIN_HEIGHT_SET:
3952       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
3953       break;
3954
3955     case PROP_NATURAL_WIDTH_SET:
3956       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
3957       break;
3958
3959     case PROP_NATURAL_HEIGHT_SET:
3960       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
3961       break;
3962
3963     case PROP_REQUEST_MODE:
3964       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
3965       break;
3966
3967     case PROP_DEPTH:
3968       clutter_actor_set_depth (actor, g_value_get_float (value));
3969       break;
3970
3971     case PROP_OPACITY:
3972       clutter_actor_set_opacity (actor, g_value_get_uint (value));
3973       break;
3974
3975     case PROP_OFFSCREEN_REDIRECT:
3976       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
3977       break;
3978
3979     case PROP_NAME:
3980       clutter_actor_set_name (actor, g_value_get_string (value));
3981       break;
3982
3983     case PROP_VISIBLE:
3984       if (g_value_get_boolean (value) == TRUE)
3985         clutter_actor_show (actor);
3986       else
3987         clutter_actor_hide (actor);
3988       break;
3989
3990     case PROP_SCALE_X:
3991       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
3992                                       g_value_get_double (value));
3993       break;
3994
3995     case PROP_SCALE_Y:
3996       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
3997                                       g_value_get_double (value));
3998       break;
3999
4000     case PROP_SCALE_CENTER_X:
4001       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4002                                       g_value_get_float (value));
4003       break;
4004
4005     case PROP_SCALE_CENTER_Y:
4006       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4007                                       g_value_get_float (value));
4008       break;
4009
4010     case PROP_SCALE_GRAVITY:
4011       {
4012         const ClutterTransformInfo *info;
4013         ClutterGravity gravity;
4014
4015         info = _clutter_actor_get_transform_info_or_defaults (actor);
4016         gravity = g_value_get_enum (value);
4017
4018         clutter_actor_set_scale_with_gravity (actor,
4019                                               info->scale_x,
4020                                               info->scale_y,
4021                                               gravity);
4022       }
4023       break;
4024
4025     case PROP_CLIP:
4026       {
4027         const ClutterGeometry *geom = g_value_get_boxed (value);
4028
4029         clutter_actor_set_clip (actor,
4030                                 geom->x, geom->y,
4031                                 geom->width, geom->height);
4032       }
4033       break;
4034
4035     case PROP_CLIP_TO_ALLOCATION:
4036       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4037       break;
4038
4039     case PROP_REACTIVE:
4040       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4041       break;
4042
4043     case PROP_ROTATION_ANGLE_X:
4044       clutter_actor_set_rotation_angle_internal (actor,
4045                                                  CLUTTER_X_AXIS,
4046                                                  g_value_get_double (value));
4047       break;
4048
4049     case PROP_ROTATION_ANGLE_Y:
4050       clutter_actor_set_rotation_angle_internal (actor,
4051                                                  CLUTTER_Y_AXIS,
4052                                                  g_value_get_double (value));
4053       break;
4054
4055     case PROP_ROTATION_ANGLE_Z:
4056       clutter_actor_set_rotation_angle_internal (actor,
4057                                                  CLUTTER_Z_AXIS,
4058                                                  g_value_get_double (value));
4059       break;
4060
4061     case PROP_ROTATION_CENTER_X:
4062       clutter_actor_set_rotation_center_internal (actor,
4063                                                   CLUTTER_X_AXIS,
4064                                                   g_value_get_boxed (value));
4065       break;
4066
4067     case PROP_ROTATION_CENTER_Y:
4068       clutter_actor_set_rotation_center_internal (actor,
4069                                                   CLUTTER_Y_AXIS,
4070                                                   g_value_get_boxed (value));
4071       break;
4072
4073     case PROP_ROTATION_CENTER_Z:
4074       clutter_actor_set_rotation_center_internal (actor,
4075                                                   CLUTTER_Z_AXIS,
4076                                                   g_value_get_boxed (value));
4077       break;
4078
4079     case PROP_ROTATION_CENTER_Z_GRAVITY:
4080       {
4081         const ClutterTransformInfo *info;
4082
4083         info = _clutter_actor_get_transform_info_or_defaults (actor);
4084         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4085                                                    g_value_get_enum (value));
4086       }
4087       break;
4088
4089     case PROP_ANCHOR_X:
4090       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4091                                       g_value_get_float (value));
4092       break;
4093
4094     case PROP_ANCHOR_Y:
4095       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4096                                       g_value_get_float (value));
4097       break;
4098
4099     case PROP_ANCHOR_GRAVITY:
4100       clutter_actor_set_anchor_point_from_gravity (actor,
4101                                                    g_value_get_enum (value));
4102       break;
4103
4104     case PROP_SHOW_ON_SET_PARENT:
4105       priv->show_on_set_parent = g_value_get_boolean (value);
4106       break;
4107
4108     case PROP_TEXT_DIRECTION:
4109       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4110       break;
4111
4112     case PROP_ACTIONS:
4113       clutter_actor_add_action (actor, g_value_get_object (value));
4114       break;
4115
4116     case PROP_CONSTRAINTS:
4117       clutter_actor_add_constraint (actor, g_value_get_object (value));
4118       break;
4119
4120     case PROP_EFFECT:
4121       clutter_actor_add_effect (actor, g_value_get_object (value));
4122       break;
4123
4124     case PROP_LAYOUT_MANAGER:
4125       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4126       break;
4127
4128     case PROP_X_ALIGN:
4129       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4130       break;
4131
4132     case PROP_Y_ALIGN:
4133       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4134       break;
4135
4136     case PROP_MARGIN_TOP:
4137       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4138       break;
4139
4140     case PROP_MARGIN_BOTTOM:
4141       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4142       break;
4143
4144     case PROP_MARGIN_LEFT:
4145       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4146       break;
4147
4148     case PROP_MARGIN_RIGHT:
4149       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4150       break;
4151
4152     case PROP_BACKGROUND_COLOR:
4153       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4154       break;
4155
4156     default:
4157       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4158       break;
4159     }
4160 }
4161
4162 static void
4163 clutter_actor_get_property (GObject    *object,
4164                             guint       prop_id,
4165                             GValue     *value,
4166                             GParamSpec *pspec)
4167 {
4168   ClutterActor *actor = CLUTTER_ACTOR (object);
4169   ClutterActorPrivate *priv = actor->priv;
4170
4171   switch (prop_id)
4172     {
4173     case PROP_X:
4174       g_value_set_float (value, clutter_actor_get_x (actor));
4175       break;
4176
4177     case PROP_Y:
4178       g_value_set_float (value, clutter_actor_get_y (actor));
4179       break;
4180
4181     case PROP_WIDTH:
4182       g_value_set_float (value, clutter_actor_get_width (actor));
4183       break;
4184
4185     case PROP_HEIGHT:
4186       g_value_set_float (value, clutter_actor_get_height (actor));
4187       break;
4188
4189     case PROP_FIXED_X:
4190       {
4191         const ClutterLayoutInfo *info;
4192
4193         info = _clutter_actor_get_layout_info_or_defaults (actor);
4194         g_value_set_float (value, info->fixed_x);
4195       }
4196       break;
4197
4198     case PROP_FIXED_Y:
4199       {
4200         const ClutterLayoutInfo *info;
4201
4202         info = _clutter_actor_get_layout_info_or_defaults (actor);
4203         g_value_set_float (value, info->fixed_y);
4204       }
4205       break;
4206
4207     case PROP_FIXED_POSITION_SET:
4208       g_value_set_boolean (value, priv->position_set);
4209       break;
4210
4211     case PROP_MIN_WIDTH:
4212       {
4213         const ClutterLayoutInfo *info;
4214
4215         info = _clutter_actor_get_layout_info_or_defaults (actor);
4216         g_value_set_float (value, info->min_width);
4217       }
4218       break;
4219
4220     case PROP_MIN_HEIGHT:
4221       {
4222         const ClutterLayoutInfo *info;
4223
4224         info = _clutter_actor_get_layout_info_or_defaults (actor);
4225         g_value_set_float (value, info->min_height);
4226       }
4227       break;
4228
4229     case PROP_NATURAL_WIDTH:
4230       {
4231         const ClutterLayoutInfo *info;
4232
4233         info = _clutter_actor_get_layout_info_or_defaults (actor);
4234         g_value_set_float (value, info->natural_width);
4235       }
4236       break;
4237
4238     case PROP_NATURAL_HEIGHT:
4239       {
4240         const ClutterLayoutInfo *info;
4241
4242         info = _clutter_actor_get_layout_info_or_defaults (actor);
4243         g_value_set_float (value, info->natural_height);
4244       }
4245       break;
4246
4247     case PROP_MIN_WIDTH_SET:
4248       g_value_set_boolean (value, priv->min_width_set);
4249       break;
4250
4251     case PROP_MIN_HEIGHT_SET:
4252       g_value_set_boolean (value, priv->min_height_set);
4253       break;
4254
4255     case PROP_NATURAL_WIDTH_SET:
4256       g_value_set_boolean (value, priv->natural_width_set);
4257       break;
4258
4259     case PROP_NATURAL_HEIGHT_SET:
4260       g_value_set_boolean (value, priv->natural_height_set);
4261       break;
4262
4263     case PROP_REQUEST_MODE:
4264       g_value_set_enum (value, priv->request_mode);
4265       break;
4266
4267     case PROP_ALLOCATION:
4268       g_value_set_boxed (value, &priv->allocation);
4269       break;
4270
4271     case PROP_DEPTH:
4272       g_value_set_float (value, clutter_actor_get_depth (actor));
4273       break;
4274
4275     case PROP_OPACITY:
4276       g_value_set_uint (value, priv->opacity);
4277       break;
4278
4279     case PROP_OFFSCREEN_REDIRECT:
4280       g_value_set_enum (value, priv->offscreen_redirect);
4281       break;
4282
4283     case PROP_NAME:
4284       g_value_set_string (value, priv->name);
4285       break;
4286
4287     case PROP_VISIBLE:
4288       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4289       break;
4290
4291     case PROP_MAPPED:
4292       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4293       break;
4294
4295     case PROP_REALIZED:
4296       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4297       break;
4298
4299     case PROP_HAS_CLIP:
4300       g_value_set_boolean (value, priv->has_clip);
4301       break;
4302
4303     case PROP_CLIP:
4304       {
4305         ClutterGeometry clip;
4306
4307         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4308         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4309         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4310         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4311
4312         g_value_set_boxed (value, &clip);
4313       }
4314       break;
4315
4316     case PROP_CLIP_TO_ALLOCATION:
4317       g_value_set_boolean (value, priv->clip_to_allocation);
4318       break;
4319
4320     case PROP_SCALE_X:
4321       {
4322         const ClutterTransformInfo *info;
4323
4324         info = _clutter_actor_get_transform_info_or_defaults (actor);
4325         g_value_set_double (value, info->scale_x);
4326       }
4327       break;
4328
4329     case PROP_SCALE_Y:
4330       {
4331         const ClutterTransformInfo *info;
4332
4333         info = _clutter_actor_get_transform_info_or_defaults (actor);
4334         g_value_set_double (value, info->scale_y);
4335       }
4336       break;
4337
4338     case PROP_SCALE_CENTER_X:
4339       {
4340         gfloat center;
4341
4342         clutter_actor_get_scale_center (actor, &center, NULL);
4343
4344         g_value_set_float (value, center);
4345       }
4346       break;
4347
4348     case PROP_SCALE_CENTER_Y:
4349       {
4350         gfloat center;
4351
4352         clutter_actor_get_scale_center (actor, NULL, &center);
4353
4354         g_value_set_float (value, center);
4355       }
4356       break;
4357
4358     case PROP_SCALE_GRAVITY:
4359       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4360       break;
4361
4362     case PROP_REACTIVE:
4363       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4364       break;
4365
4366     case PROP_ROTATION_ANGLE_X:
4367       {
4368         const ClutterTransformInfo *info;
4369
4370         info = _clutter_actor_get_transform_info_or_defaults (actor);
4371         g_value_set_double (value, info->rx_angle);
4372       }
4373       break;
4374
4375     case PROP_ROTATION_ANGLE_Y:
4376       {
4377         const ClutterTransformInfo *info;
4378
4379         info = _clutter_actor_get_transform_info_or_defaults (actor);
4380         g_value_set_double (value, info->ry_angle);
4381       }
4382       break;
4383
4384     case PROP_ROTATION_ANGLE_Z:
4385       {
4386         const ClutterTransformInfo *info;
4387
4388         info = _clutter_actor_get_transform_info_or_defaults (actor);
4389         g_value_set_double (value, info->rz_angle);
4390       }
4391       break;
4392
4393     case PROP_ROTATION_CENTER_X:
4394       {
4395         ClutterVertex center;
4396
4397         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4398                                     &center.x,
4399                                     &center.y,
4400                                     &center.z);
4401
4402         g_value_set_boxed (value, &center);
4403       }
4404       break;
4405
4406     case PROP_ROTATION_CENTER_Y:
4407       {
4408         ClutterVertex center;
4409
4410         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4411                                     &center.x,
4412                                     &center.y,
4413                                     &center.z);
4414
4415         g_value_set_boxed (value, &center);
4416       }
4417       break;
4418
4419     case PROP_ROTATION_CENTER_Z:
4420       {
4421         ClutterVertex center;
4422
4423         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4424                                     &center.x,
4425                                     &center.y,
4426                                     &center.z);
4427
4428         g_value_set_boxed (value, &center);
4429       }
4430       break;
4431
4432     case PROP_ROTATION_CENTER_Z_GRAVITY:
4433       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4434       break;
4435
4436     case PROP_ANCHOR_X:
4437       {
4438         const ClutterTransformInfo *info;
4439         gfloat anchor_x;
4440
4441         info = _clutter_actor_get_transform_info_or_defaults (actor);
4442         clutter_anchor_coord_get_units (actor, &info->anchor,
4443                                         &anchor_x,
4444                                         NULL,
4445                                         NULL);
4446         g_value_set_float (value, anchor_x);
4447       }
4448       break;
4449
4450     case PROP_ANCHOR_Y:
4451       {
4452         const ClutterTransformInfo *info;
4453         gfloat anchor_y;
4454
4455         info = _clutter_actor_get_transform_info_or_defaults (actor);
4456         clutter_anchor_coord_get_units (actor, &info->anchor,
4457                                         NULL,
4458                                         &anchor_y,
4459                                         NULL);
4460         g_value_set_float (value, anchor_y);
4461       }
4462       break;
4463
4464     case PROP_ANCHOR_GRAVITY:
4465       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4466       break;
4467
4468     case PROP_SHOW_ON_SET_PARENT:
4469       g_value_set_boolean (value, priv->show_on_set_parent);
4470       break;
4471
4472     case PROP_TEXT_DIRECTION:
4473       g_value_set_enum (value, priv->text_direction);
4474       break;
4475
4476     case PROP_HAS_POINTER:
4477       g_value_set_boolean (value, priv->has_pointer);
4478       break;
4479
4480     case PROP_LAYOUT_MANAGER:
4481       g_value_set_object (value, priv->layout_manager);
4482       break;
4483
4484     case PROP_X_ALIGN:
4485       {
4486         const ClutterLayoutInfo *info;
4487
4488         info = _clutter_actor_get_layout_info_or_defaults (actor);
4489         g_value_set_enum (value, info->x_align);
4490       }
4491       break;
4492
4493     case PROP_Y_ALIGN:
4494       {
4495         const ClutterLayoutInfo *info;
4496
4497         info = _clutter_actor_get_layout_info_or_defaults (actor);
4498         g_value_set_enum (value, info->y_align);
4499       }
4500       break;
4501
4502     case PROP_MARGIN_TOP:
4503       {
4504         const ClutterLayoutInfo *info;
4505
4506         info = _clutter_actor_get_layout_info_or_defaults (actor);
4507         g_value_set_float (value, info->margin.top);
4508       }
4509       break;
4510
4511     case PROP_MARGIN_BOTTOM:
4512       {
4513         const ClutterLayoutInfo *info;
4514
4515         info = _clutter_actor_get_layout_info_or_defaults (actor);
4516         g_value_set_float (value, info->margin.bottom);
4517       }
4518       break;
4519
4520     case PROP_MARGIN_LEFT:
4521       {
4522         const ClutterLayoutInfo *info;
4523
4524         info = _clutter_actor_get_layout_info_or_defaults (actor);
4525         g_value_set_float (value, info->margin.left);
4526       }
4527       break;
4528
4529     case PROP_MARGIN_RIGHT:
4530       {
4531         const ClutterLayoutInfo *info;
4532
4533         info = _clutter_actor_get_layout_info_or_defaults (actor);
4534         g_value_set_float (value, info->margin.right);
4535       }
4536       break;
4537
4538     case PROP_BACKGROUND_COLOR_SET:
4539       g_value_set_boolean (value, priv->bg_color_set);
4540       break;
4541
4542     case PROP_BACKGROUND_COLOR:
4543       g_value_set_boxed (value, &priv->bg_color);
4544       break;
4545
4546     case PROP_FIRST_CHILD:
4547       g_value_set_object (value, priv->first_child);
4548       break;
4549
4550     case PROP_LAST_CHILD:
4551       g_value_set_object (value, priv->last_child);
4552       break;
4553
4554     default:
4555       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4556       break;
4557     }
4558 }
4559
4560 static void
4561 clutter_actor_dispose (GObject *object)
4562 {
4563   ClutterActor *self = CLUTTER_ACTOR (object);
4564   ClutterActorPrivate *priv = self->priv;
4565
4566   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4567                 priv->id,
4568                 g_type_name (G_OBJECT_TYPE (self)),
4569                 object->ref_count);
4570
4571   g_signal_emit (self, actor_signals[DESTROY], 0);
4572
4573   /* avoid recursing when called from clutter_actor_destroy() */
4574   if (priv->parent != NULL)
4575     {
4576       ClutterActor *parent = priv->parent;
4577
4578       /* go through the Container implementation unless this
4579        * is an internal child and has been marked as such.
4580        *
4581        * removing the actor from its parent will reset the
4582        * realized and mapped states.
4583        */
4584       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4585         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4586       else
4587         clutter_actor_remove_child_internal (parent, self,
4588                                              REMOVE_CHILD_LEGACY_FLAGS);
4589     }
4590
4591   /* parent must be gone at this point */
4592   g_assert (priv->parent == NULL);
4593
4594   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4595     {
4596       /* can't be mapped or realized with no parent */
4597       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4598       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4599     }
4600
4601   g_clear_object (&priv->pango_context);
4602   g_clear_object (&priv->actions);
4603   g_clear_object (&priv->constraints);
4604   g_clear_object (&priv->effects);
4605   g_clear_object (&priv->flatten_effect);
4606
4607   if (priv->layout_manager != NULL)
4608     {
4609       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4610       g_object_unref (priv->layout_manager);
4611       priv->layout_manager = NULL;
4612     }
4613
4614   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4615 }
4616
4617 static void
4618 clutter_actor_finalize (GObject *object)
4619 {
4620   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4621
4622   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4623                 priv->name != NULL ? priv->name : "<none>",
4624                 priv->id,
4625                 g_type_name (G_OBJECT_TYPE (object)));
4626
4627   _clutter_context_release_id (priv->id);
4628
4629   g_free (priv->name);
4630
4631   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4632 }
4633
4634
4635 /**
4636  * clutter_actor_get_accessible:
4637  * @self: a #ClutterActor
4638  *
4639  * Returns the accessible object that describes the actor to an
4640  * assistive technology.
4641  *
4642  * If no class-specific #AtkObject implementation is available for the
4643  * actor instance in question, it will inherit an #AtkObject
4644  * implementation from the first ancestor class for which such an
4645  * implementation is defined.
4646  *
4647  * The documentation of the <ulink
4648  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4649  * library contains more information about accessible objects and
4650  * their uses.
4651  *
4652  * Returns: (transfer none): the #AtkObject associated with @actor
4653  */
4654 AtkObject *
4655 clutter_actor_get_accessible (ClutterActor *self)
4656 {
4657   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4658
4659   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4660 }
4661
4662 static AtkObject *
4663 clutter_actor_real_get_accessible (ClutterActor *actor)
4664 {
4665   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4666 }
4667
4668 static AtkObject *
4669 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4670 {
4671   AtkObject *accessible;
4672
4673   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4674   if (accessible != NULL)
4675     g_object_ref (accessible);
4676
4677   return accessible;
4678 }
4679
4680 static void
4681 atk_implementor_iface_init (AtkImplementorIface *iface)
4682 {
4683   iface->ref_accessible = _clutter_actor_ref_accessible;
4684 }
4685
4686 static gboolean
4687 clutter_actor_update_default_paint_volume (ClutterActor       *self,
4688                                            ClutterPaintVolume *volume)
4689 {
4690   ClutterActorPrivate *priv = self->priv;
4691   gboolean res = FALSE;
4692
4693   /* we start from the allocation */
4694   clutter_paint_volume_set_width (volume,
4695                                   priv->allocation.x2 - priv->allocation.x1);
4696   clutter_paint_volume_set_height (volume,
4697                                    priv->allocation.y2 - priv->allocation.y1);
4698
4699   /* if the actor has a clip set then we have a pretty definite
4700    * size for the paint volume: the actor cannot possibly paint
4701    * outside the clip region.
4702    */
4703   if (priv->clip_to_allocation)
4704     {
4705       /* the allocation has already been set, so we just flip the
4706        * return value
4707        */
4708       res = TRUE;
4709     }
4710   else
4711     {
4712       ClutterActor *child;
4713
4714       if (priv->has_clip &&
4715           priv->clip.width >= 0 &&
4716           priv->clip.height >= 0)
4717         {
4718           ClutterVertex origin;
4719
4720           origin.x = priv->clip.x;
4721           origin.y = priv->clip.y;
4722           origin.z = 0;
4723
4724           clutter_paint_volume_set_origin (volume, &origin);
4725           clutter_paint_volume_set_width (volume, priv->clip.width);
4726           clutter_paint_volume_set_height (volume, priv->clip.height);
4727
4728           res = TRUE;
4729         }
4730
4731       /* if we don't have children we just bail out here... */
4732       if (priv->n_children == 0)
4733         return res;
4734
4735       /* ...but if we have children then we ask for their paint volume in
4736        * our coordinates. if any of our children replies that it doesn't
4737        * have a paint volume, we bail out
4738        */
4739       for (child = priv->first_child;
4740            child != NULL;
4741            child = child->priv->next_sibling)
4742         {
4743           const ClutterPaintVolume *child_volume;
4744
4745           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4746           if (child_volume == NULL)
4747             {
4748               res = FALSE;
4749               break;
4750             }
4751
4752           clutter_paint_volume_union (volume, child_volume);
4753           res = TRUE;
4754         }
4755     }
4756
4757   return res;
4758
4759 }
4760
4761 static gboolean
4762 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4763                                      ClutterPaintVolume *volume)
4764 {
4765   ClutterActorClass *klass;
4766   gboolean res;
4767
4768   klass = CLUTTER_ACTOR_GET_CLASS (self);
4769
4770   /* XXX - this thoroughly sucks, but we don't want to penalize users
4771    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
4772    * redraw. This should go away in 2.0.
4773    */
4774   if (klass->paint == clutter_actor_real_paint &&
4775       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
4776     {
4777       res = TRUE;
4778     }
4779   else
4780     {
4781       /* this is the default return value: we cannot know if a class
4782        * is going to paint outside its allocation, so we take the
4783        * conservative approach.
4784        */
4785       res = FALSE;
4786     }
4787
4788   if (clutter_actor_update_default_paint_volume (self, volume))
4789     return res;
4790
4791   return FALSE;
4792 }
4793
4794 /**
4795  * clutter_actor_get_default_paint_volume:
4796  * @self: a #ClutterActor
4797  *
4798  * Retrieves the default paint volume for @self.
4799  *
4800  * This function provides the same #ClutterPaintVolume that would be
4801  * computed by the default implementation inside #ClutterActor of the
4802  * #ClutterActorClass.get_paint_volume() virtual function.
4803  *
4804  * This function should only be used by #ClutterActor subclasses that
4805  * cannot chain up to the parent implementation when computing their
4806  * paint volume.
4807  *
4808  * Return value: (transfer none): a pointer to the default
4809  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
4810  *   the actor could not compute a valid paint volume. The returned value
4811  *   is not guaranteed to be stable across multiple frames, so if you
4812  *   want to retain it, you will need to copy it using
4813  *   clutter_paint_volume_copy().
4814  *
4815  * Since: 1.10
4816  */
4817 const ClutterPaintVolume *
4818 clutter_actor_get_default_paint_volume (ClutterActor *self)
4819 {
4820   ClutterPaintVolume volume;
4821   ClutterPaintVolume *res;
4822
4823   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4824
4825   res = NULL;
4826   _clutter_paint_volume_init_static (&volume, self);
4827   if (clutter_actor_update_default_paint_volume (self, &volume))
4828     {
4829       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
4830
4831       if (stage != NULL)
4832         {
4833           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
4834           _clutter_paint_volume_copy_static (&volume, res);
4835         }
4836     }
4837
4838   clutter_paint_volume_free (&volume);
4839
4840   return res;
4841 }
4842
4843 static gboolean
4844 clutter_actor_real_has_overlaps (ClutterActor *self)
4845 {
4846   /* By default we'll assume that all actors need an offscreen redirect to get
4847    * the correct opacity. Actors such as ClutterTexture that would never need
4848    * an offscreen redirect can override this to return FALSE. */
4849   return TRUE;
4850 }
4851
4852 static void
4853 clutter_actor_real_destroy (ClutterActor *actor)
4854 {
4855   ClutterActorIter iter;
4856
4857   clutter_actor_iter_init (&iter, actor);
4858   while (clutter_actor_iter_next (&iter, NULL))
4859     clutter_actor_iter_destroy (&iter);
4860 }
4861
4862 static GObject *
4863 clutter_actor_constructor (GType gtype,
4864                            guint n_props,
4865                            GObjectConstructParam *props)
4866 {
4867   GObjectClass *gobject_class;
4868   ClutterActor *self;
4869   GObject *retval;
4870
4871   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
4872   retval = gobject_class->constructor (gtype, n_props, props);
4873   self = CLUTTER_ACTOR (retval);
4874
4875   if (self->priv->layout_manager == NULL)
4876     {
4877       ClutterLayoutManager *default_layout;
4878
4879       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
4880
4881       default_layout = clutter_fixed_layout_new ();
4882       clutter_actor_set_layout_manager (self, default_layout);
4883     }
4884
4885   return retval;
4886 }
4887
4888 static void
4889 clutter_actor_class_init (ClutterActorClass *klass)
4890 {
4891   GObjectClass *object_class = G_OBJECT_CLASS (klass);
4892
4893   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
4894   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
4895   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
4896
4897   object_class->constructor = clutter_actor_constructor;
4898   object_class->set_property = clutter_actor_set_property;
4899   object_class->get_property = clutter_actor_get_property;
4900   object_class->dispose = clutter_actor_dispose;
4901   object_class->finalize = clutter_actor_finalize;
4902
4903   klass->show = clutter_actor_real_show;
4904   klass->show_all = clutter_actor_show;
4905   klass->hide = clutter_actor_real_hide;
4906   klass->hide_all = clutter_actor_hide;
4907   klass->map = clutter_actor_real_map;
4908   klass->unmap = clutter_actor_real_unmap;
4909   klass->unrealize = clutter_actor_real_unrealize;
4910   klass->pick = clutter_actor_real_pick;
4911   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
4912   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4913   klass->allocate = clutter_actor_real_allocate;
4914   klass->queue_redraw = clutter_actor_real_queue_redraw;
4915   klass->queue_relayout = clutter_actor_real_queue_relayout;
4916   klass->apply_transform = clutter_actor_real_apply_transform;
4917   klass->get_accessible = clutter_actor_real_get_accessible;
4918   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
4919   klass->has_overlaps = clutter_actor_real_has_overlaps;
4920   klass->paint = clutter_actor_real_paint;
4921   klass->destroy = clutter_actor_real_destroy;
4922
4923   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
4924
4925   /**
4926    * ClutterActor:x:
4927    *
4928    * X coordinate of the actor in pixels. If written, forces a fixed
4929    * position for the actor. If read, returns the fixed position if any,
4930    * otherwise the allocation if available, otherwise 0.
4931    */
4932   obj_props[PROP_X] =
4933     g_param_spec_float ("x",
4934                         P_("X coordinate"),
4935                         P_("X coordinate of the actor"),
4936                         -G_MAXFLOAT, G_MAXFLOAT,
4937                         0.0,
4938                         CLUTTER_PARAM_READWRITE);
4939
4940   /**
4941    * ClutterActor:y:
4942    *
4943    * Y coordinate of the actor in pixels. If written, forces a fixed
4944    * position for the actor.  If read, returns the fixed position if
4945    * any, otherwise the allocation if available, otherwise 0.
4946    */
4947   obj_props[PROP_Y] =
4948     g_param_spec_float ("y",
4949                         P_("Y coordinate"),
4950                         P_("Y coordinate of the actor"),
4951                         -G_MAXFLOAT, G_MAXFLOAT,
4952                         0.0,
4953                         CLUTTER_PARAM_READWRITE);
4954
4955   /**
4956    * ClutterActor:width:
4957    *
4958    * Width of the actor (in pixels). If written, forces the minimum and
4959    * natural size request of the actor to the given width. If read, returns
4960    * the allocated width if available, otherwise the width request.
4961    */
4962   obj_props[PROP_WIDTH] =
4963     g_param_spec_float ("width",
4964                         P_("Width"),
4965                         P_("Width of the actor"),
4966                         0.0, G_MAXFLOAT,
4967                         0.0,
4968                         CLUTTER_PARAM_READWRITE);
4969
4970   /**
4971    * ClutterActor:height:
4972    *
4973    * Height of the actor (in pixels).  If written, forces the minimum and
4974    * natural size request of the actor to the given height. If read, returns
4975    * the allocated height if available, otherwise the height request.
4976    */
4977   obj_props[PROP_HEIGHT] =
4978     g_param_spec_float ("height",
4979                         P_("Height"),
4980                         P_("Height of the actor"),
4981                         0.0, G_MAXFLOAT,
4982                         0.0,
4983                         CLUTTER_PARAM_READWRITE);
4984
4985   /**
4986    * ClutterActor:fixed-x:
4987    *
4988    * The fixed X position of the actor in pixels.
4989    *
4990    * Writing this property sets #ClutterActor:fixed-position-set
4991    * property as well, as a side effect
4992    *
4993    * Since: 0.8
4994    */
4995   obj_props[PROP_FIXED_X] =
4996     g_param_spec_float ("fixed-x",
4997                         P_("Fixed X"),
4998                         P_("Forced X position of the actor"),
4999                         -G_MAXFLOAT, G_MAXFLOAT,
5000                         0.0,
5001                         CLUTTER_PARAM_READWRITE);
5002
5003   /**
5004    * ClutterActor:fixed-y:
5005    *
5006    * The fixed Y position of the actor in pixels.
5007    *
5008    * Writing this property sets the #ClutterActor:fixed-position-set
5009    * property as well, as a side effect
5010    *
5011    * Since: 0.8
5012    */
5013   obj_props[PROP_FIXED_Y] =
5014     g_param_spec_float ("fixed-y",
5015                         P_("Fixed Y"),
5016                         P_("Forced Y position of the actor"),
5017                         -G_MAXFLOAT, G_MAXFLOAT,
5018                         0,
5019                         CLUTTER_PARAM_READWRITE);
5020
5021   /**
5022    * ClutterActor:fixed-position-set:
5023    *
5024    * This flag controls whether the #ClutterActor:fixed-x and
5025    * #ClutterActor:fixed-y properties are used
5026    *
5027    * Since: 0.8
5028    */
5029   obj_props[PROP_FIXED_POSITION_SET] =
5030     g_param_spec_boolean ("fixed-position-set",
5031                           P_("Fixed position set"),
5032                           P_("Whether to use fixed positioning for the actor"),
5033                           FALSE,
5034                           CLUTTER_PARAM_READWRITE);
5035
5036   /**
5037    * ClutterActor:min-width:
5038    *
5039    * A forced minimum width request for the actor, in pixels
5040    *
5041    * Writing this property sets the #ClutterActor:min-width-set property
5042    * as well, as a side effect.
5043    *
5044    *This property overrides the usual width request of the actor.
5045    *
5046    * Since: 0.8
5047    */
5048   obj_props[PROP_MIN_WIDTH] =
5049     g_param_spec_float ("min-width",
5050                         P_("Min Width"),
5051                         P_("Forced minimum width request for the actor"),
5052                         0.0, G_MAXFLOAT,
5053                         0.0,
5054                         CLUTTER_PARAM_READWRITE);
5055
5056   /**
5057    * ClutterActor:min-height:
5058    *
5059    * A forced minimum height request for the actor, in pixels
5060    *
5061    * Writing this property sets the #ClutterActor:min-height-set property
5062    * as well, as a side effect. This property overrides the usual height
5063    * request of the actor.
5064    *
5065    * Since: 0.8
5066    */
5067   obj_props[PROP_MIN_HEIGHT] =
5068     g_param_spec_float ("min-height",
5069                         P_("Min Height"),
5070                         P_("Forced minimum height request for the actor"),
5071                         0.0, G_MAXFLOAT,
5072                         0.0,
5073                         CLUTTER_PARAM_READWRITE);
5074
5075   /**
5076    * ClutterActor:natural-width:
5077    *
5078    * A forced natural width request for the actor, in pixels
5079    *
5080    * Writing this property sets the #ClutterActor:natural-width-set
5081    * property as well, as a side effect. This property overrides the
5082    * usual width request of the actor
5083    *
5084    * Since: 0.8
5085    */
5086   obj_props[PROP_NATURAL_WIDTH] =
5087     g_param_spec_float ("natural-width",
5088                         P_("Natural Width"),
5089                         P_("Forced natural width request for the actor"),
5090                         0.0, G_MAXFLOAT,
5091                         0.0,
5092                         CLUTTER_PARAM_READWRITE);
5093
5094   /**
5095    * ClutterActor:natural-height:
5096    *
5097    * A forced natural height request for the actor, in pixels
5098    *
5099    * Writing this property sets the #ClutterActor:natural-height-set
5100    * property as well, as a side effect. This property overrides the
5101    * usual height request of the actor
5102    *
5103    * Since: 0.8
5104    */
5105   obj_props[PROP_NATURAL_HEIGHT] =
5106     g_param_spec_float ("natural-height",
5107                         P_("Natural Height"),
5108                         P_("Forced natural height request for the actor"),
5109                         0.0, G_MAXFLOAT,
5110                         0.0,
5111                         CLUTTER_PARAM_READWRITE);
5112
5113   /**
5114    * ClutterActor:min-width-set:
5115    *
5116    * This flag controls whether the #ClutterActor:min-width property
5117    * is used
5118    *
5119    * Since: 0.8
5120    */
5121   obj_props[PROP_MIN_WIDTH_SET] =
5122     g_param_spec_boolean ("min-width-set",
5123                           P_("Minimum width set"),
5124                           P_("Whether to use the min-width property"),
5125                           FALSE,
5126                           CLUTTER_PARAM_READWRITE);
5127
5128   /**
5129    * ClutterActor:min-height-set:
5130    *
5131    * This flag controls whether the #ClutterActor:min-height property
5132    * is used
5133    *
5134    * Since: 0.8
5135    */
5136   obj_props[PROP_MIN_HEIGHT_SET] =
5137     g_param_spec_boolean ("min-height-set",
5138                           P_("Minimum height set"),
5139                           P_("Whether to use the min-height property"),
5140                           FALSE,
5141                           CLUTTER_PARAM_READWRITE);
5142
5143   /**
5144    * ClutterActor:natural-width-set:
5145    *
5146    * This flag controls whether the #ClutterActor:natural-width property
5147    * is used
5148    *
5149    * Since: 0.8
5150    */
5151   obj_props[PROP_NATURAL_WIDTH_SET] =
5152     g_param_spec_boolean ("natural-width-set",
5153                           P_("Natural width set"),
5154                           P_("Whether to use the natural-width property"),
5155                           FALSE,
5156                           CLUTTER_PARAM_READWRITE);
5157
5158   /**
5159    * ClutterActor:natural-height-set:
5160    *
5161    * This flag controls whether the #ClutterActor:natural-height property
5162    * is used
5163    *
5164    * Since: 0.8
5165    */
5166   obj_props[PROP_NATURAL_HEIGHT_SET] =
5167     g_param_spec_boolean ("natural-height-set",
5168                           P_("Natural height set"),
5169                           P_("Whether to use the natural-height property"),
5170                           FALSE,
5171                           CLUTTER_PARAM_READWRITE);
5172
5173   /**
5174    * ClutterActor:allocation:
5175    *
5176    * The allocation for the actor, in pixels
5177    *
5178    * This is property is read-only, but you might monitor it to know when an
5179    * actor moves or resizes
5180    *
5181    * Since: 0.8
5182    */
5183   obj_props[PROP_ALLOCATION] =
5184     g_param_spec_boxed ("allocation",
5185                         P_("Allocation"),
5186                         P_("The actor's allocation"),
5187                         CLUTTER_TYPE_ACTOR_BOX,
5188                         CLUTTER_PARAM_READABLE);
5189
5190   /**
5191    * ClutterActor:request-mode:
5192    *
5193    * Request mode for the #ClutterActor. The request mode determines the
5194    * type of geometry management used by the actor, either height for width
5195    * (the default) or width for height.
5196    *
5197    * For actors implementing height for width, the parent container should get
5198    * the preferred width first, and then the preferred height for that width.
5199    *
5200    * For actors implementing width for height, the parent container should get
5201    * the preferred height first, and then the preferred width for that height.
5202    *
5203    * For instance:
5204    *
5205    * |[
5206    *   ClutterRequestMode mode;
5207    *   gfloat natural_width, min_width;
5208    *   gfloat natural_height, min_height;
5209    *
5210    *   mode = clutter_actor_get_request_mode (child);
5211    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5212    *     {
5213    *       clutter_actor_get_preferred_width (child, -1,
5214    *                                          &amp;min_width,
5215    *                                          &amp;natural_width);
5216    *       clutter_actor_get_preferred_height (child, natural_width,
5217    *                                           &amp;min_height,
5218    *                                           &amp;natural_height);
5219    *     }
5220    *   else
5221    *     {
5222    *       clutter_actor_get_preferred_height (child, -1,
5223    *                                           &amp;min_height,
5224    *                                           &amp;natural_height);
5225    *       clutter_actor_get_preferred_width (child, natural_height,
5226    *                                          &amp;min_width,
5227    *                                          &amp;natural_width);
5228    *     }
5229    * ]|
5230    *
5231    * will retrieve the minimum and natural width and height depending on the
5232    * preferred request mode of the #ClutterActor "child".
5233    *
5234    * The clutter_actor_get_preferred_size() function will implement this
5235    * check for you.
5236    *
5237    * Since: 0.8
5238    */
5239   obj_props[PROP_REQUEST_MODE] =
5240     g_param_spec_enum ("request-mode",
5241                        P_("Request Mode"),
5242                        P_("The actor's request mode"),
5243                        CLUTTER_TYPE_REQUEST_MODE,
5244                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5245                        CLUTTER_PARAM_READWRITE);
5246
5247   /**
5248    * ClutterActor:depth:
5249    *
5250    * The position of the actor on the Z axis
5251    *
5252    * Since: 0.6
5253    */
5254   obj_props[PROP_DEPTH] =
5255     g_param_spec_float ("depth",
5256                         P_("Depth"),
5257                         P_("Position on the Z axis"),
5258                         -G_MAXFLOAT, G_MAXFLOAT,
5259                         0.0,
5260                         CLUTTER_PARAM_READWRITE);
5261
5262   /**
5263    * ClutterActor:opacity:
5264    *
5265    * Opacity of an actor, between 0 (fully transparent) and
5266    * 255 (fully opaque)
5267    */
5268   obj_props[PROP_OPACITY] =
5269     g_param_spec_uint ("opacity",
5270                        P_("Opacity"),
5271                        P_("Opacity of an actor"),
5272                        0, 255,
5273                        255,
5274                        CLUTTER_PARAM_READWRITE);
5275
5276   /**
5277    * ClutterActor:offscreen-redirect:
5278    *
5279    * Determines the conditions in which the actor will be redirected
5280    * to an offscreen framebuffer while being painted. For example this
5281    * can be used to cache an actor in a framebuffer or for improved
5282    * handling of transparent actors. See
5283    * clutter_actor_set_offscreen_redirect() for details.
5284    *
5285    * Since: 1.8
5286    */
5287   obj_props[PROP_OFFSCREEN_REDIRECT] =
5288     g_param_spec_flags ("offscreen-redirect",
5289                         P_("Offscreen redirect"),
5290                         P_("Flags controlling when to flatten the actor into a single image"),
5291                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5292                         0,
5293                         CLUTTER_PARAM_READWRITE);
5294
5295   /**
5296    * ClutterActor:visible:
5297    *
5298    * Whether the actor is set to be visible or not
5299    *
5300    * See also #ClutterActor:mapped
5301    */
5302   obj_props[PROP_VISIBLE] =
5303     g_param_spec_boolean ("visible",
5304                           P_("Visible"),
5305                           P_("Whether the actor is visible or not"),
5306                           FALSE,
5307                           CLUTTER_PARAM_READWRITE);
5308
5309   /**
5310    * ClutterActor:mapped:
5311    *
5312    * Whether the actor is mapped (will be painted when the stage
5313    * to which it belongs is mapped)
5314    *
5315    * Since: 1.0
5316    */
5317   obj_props[PROP_MAPPED] =
5318     g_param_spec_boolean ("mapped",
5319                           P_("Mapped"),
5320                           P_("Whether the actor will be painted"),
5321                           FALSE,
5322                           CLUTTER_PARAM_READABLE);
5323
5324   /**
5325    * ClutterActor:realized:
5326    *
5327    * Whether the actor has been realized
5328    *
5329    * Since: 1.0
5330    */
5331   obj_props[PROP_REALIZED] =
5332     g_param_spec_boolean ("realized",
5333                           P_("Realized"),
5334                           P_("Whether the actor has been realized"),
5335                           FALSE,
5336                           CLUTTER_PARAM_READABLE);
5337
5338   /**
5339    * ClutterActor:reactive:
5340    *
5341    * Whether the actor is reactive to events or not
5342    *
5343    * Only reactive actors will emit event-related signals
5344    *
5345    * Since: 0.6
5346    */
5347   obj_props[PROP_REACTIVE] =
5348     g_param_spec_boolean ("reactive",
5349                           P_("Reactive"),
5350                           P_("Whether the actor is reactive to events"),
5351                           FALSE,
5352                           CLUTTER_PARAM_READWRITE);
5353
5354   /**
5355    * ClutterActor:has-clip:
5356    *
5357    * Whether the actor has the #ClutterActor:clip property set or not
5358    */
5359   obj_props[PROP_HAS_CLIP] =
5360     g_param_spec_boolean ("has-clip",
5361                           P_("Has Clip"),
5362                           P_("Whether the actor has a clip set"),
5363                           FALSE,
5364                           CLUTTER_PARAM_READABLE);
5365
5366   /**
5367    * ClutterActor:clip:
5368    *
5369    * The clip region for the actor, in actor-relative coordinates
5370    *
5371    * Every part of the actor outside the clip region will not be
5372    * painted
5373    */
5374   obj_props[PROP_CLIP] =
5375     g_param_spec_boxed ("clip",
5376                         P_("Clip"),
5377                         P_("The clip region for the actor"),
5378                         CLUTTER_TYPE_GEOMETRY,
5379                         CLUTTER_PARAM_READWRITE);
5380
5381   /**
5382    * ClutterActor:name:
5383    *
5384    * The name of the actor
5385    *
5386    * Since: 0.2
5387    */
5388   obj_props[PROP_NAME] =
5389     g_param_spec_string ("name",
5390                          P_("Name"),
5391                          P_("Name of the actor"),
5392                          NULL,
5393                          CLUTTER_PARAM_READWRITE);
5394
5395   /**
5396    * ClutterActor:scale-x:
5397    *
5398    * The horizontal scale of the actor
5399    *
5400    * Since: 0.6
5401    */
5402   obj_props[PROP_SCALE_X] =
5403     g_param_spec_double ("scale-x",
5404                          P_("Scale X"),
5405                          P_("Scale factor on the X axis"),
5406                          0.0, G_MAXDOUBLE,
5407                          1.0,
5408                          CLUTTER_PARAM_READWRITE);
5409
5410   /**
5411    * ClutterActor:scale-y:
5412    *
5413    * The vertical scale of the actor
5414    *
5415    * Since: 0.6
5416    */
5417   obj_props[PROP_SCALE_Y] =
5418     g_param_spec_double ("scale-y",
5419                          P_("Scale Y"),
5420                          P_("Scale factor on the Y axis"),
5421                          0.0, G_MAXDOUBLE,
5422                          1.0,
5423                          CLUTTER_PARAM_READWRITE);
5424
5425   /**
5426    * ClutterActor:scale-center-x:
5427    *
5428    * The horizontal center point for scaling
5429    *
5430    * Since: 1.0
5431    */
5432   obj_props[PROP_SCALE_CENTER_X] =
5433     g_param_spec_float ("scale-center-x",
5434                         P_("Scale Center X"),
5435                         P_("Horizontal scale center"),
5436                         -G_MAXFLOAT, G_MAXFLOAT,
5437                         0.0,
5438                         CLUTTER_PARAM_READWRITE);
5439
5440   /**
5441    * ClutterActor:scale-center-y:
5442    *
5443    * The vertical center point for scaling
5444    *
5445    * Since: 1.0
5446    */
5447   obj_props[PROP_SCALE_CENTER_Y] =
5448     g_param_spec_float ("scale-center-y",
5449                         P_("Scale Center Y"),
5450                         P_("Vertical scale center"),
5451                         -G_MAXFLOAT, G_MAXFLOAT,
5452                         0.0,
5453                         CLUTTER_PARAM_READWRITE);
5454
5455   /**
5456    * ClutterActor:scale-gravity:
5457    *
5458    * The center point for scaling expressed as a #ClutterGravity
5459    *
5460    * Since: 1.0
5461    */
5462   obj_props[PROP_SCALE_GRAVITY] =
5463     g_param_spec_enum ("scale-gravity",
5464                        P_("Scale Gravity"),
5465                        P_("The center of scaling"),
5466                        CLUTTER_TYPE_GRAVITY,
5467                        CLUTTER_GRAVITY_NONE,
5468                        CLUTTER_PARAM_READWRITE);
5469
5470   /**
5471    * ClutterActor:rotation-angle-x:
5472    *
5473    * The rotation angle on the X axis
5474    *
5475    * Since: 0.6
5476    */
5477   obj_props[PROP_ROTATION_ANGLE_X] =
5478     g_param_spec_double ("rotation-angle-x",
5479                          P_("Rotation Angle X"),
5480                          P_("The rotation angle on the X axis"),
5481                          -G_MAXDOUBLE, G_MAXDOUBLE,
5482                          0.0,
5483                          CLUTTER_PARAM_READWRITE);
5484
5485   /**
5486    * ClutterActor:rotation-angle-y:
5487    *
5488    * The rotation angle on the Y axis
5489    *
5490    * Since: 0.6
5491    */
5492   obj_props[PROP_ROTATION_ANGLE_Y] =
5493     g_param_spec_double ("rotation-angle-y",
5494                          P_("Rotation Angle Y"),
5495                          P_("The rotation angle on the Y axis"),
5496                          -G_MAXDOUBLE, G_MAXDOUBLE,
5497                          0.0,
5498                          CLUTTER_PARAM_READWRITE);
5499
5500   /**
5501    * ClutterActor:rotation-angle-z:
5502    *
5503    * The rotation angle on the Z axis
5504    *
5505    * Since: 0.6
5506    */
5507   obj_props[PROP_ROTATION_ANGLE_Z] =
5508     g_param_spec_double ("rotation-angle-z",
5509                          P_("Rotation Angle Z"),
5510                          P_("The rotation angle on the Z axis"),
5511                          -G_MAXDOUBLE, G_MAXDOUBLE,
5512                          0.0,
5513                          CLUTTER_PARAM_READWRITE);
5514
5515   /**
5516    * ClutterActor:rotation-center-x:
5517    *
5518    * The rotation center on the X axis.
5519    *
5520    * Since: 0.6
5521    */
5522   obj_props[PROP_ROTATION_CENTER_X] =
5523     g_param_spec_boxed ("rotation-center-x",
5524                         P_("Rotation Center X"),
5525                         P_("The rotation center on the X axis"),
5526                         CLUTTER_TYPE_VERTEX,
5527                         CLUTTER_PARAM_READWRITE);
5528
5529   /**
5530    * ClutterActor:rotation-center-y:
5531    *
5532    * The rotation center on the Y axis.
5533    *
5534    * Since: 0.6
5535    */
5536   obj_props[PROP_ROTATION_CENTER_Y] =
5537     g_param_spec_boxed ("rotation-center-y",
5538                         P_("Rotation Center Y"),
5539                         P_("The rotation center on the Y axis"),
5540                         CLUTTER_TYPE_VERTEX,
5541                         CLUTTER_PARAM_READWRITE);
5542
5543   /**
5544    * ClutterActor:rotation-center-z:
5545    *
5546    * The rotation center on the Z axis.
5547    *
5548    * Since: 0.6
5549    */
5550   obj_props[PROP_ROTATION_CENTER_Z] =
5551     g_param_spec_boxed ("rotation-center-z",
5552                         P_("Rotation Center Z"),
5553                         P_("The rotation center on the Z axis"),
5554                         CLUTTER_TYPE_VERTEX,
5555                         CLUTTER_PARAM_READWRITE);
5556
5557   /**
5558    * ClutterActor:rotation-center-z-gravity:
5559    *
5560    * The rotation center on the Z axis expressed as a #ClutterGravity.
5561    *
5562    * Since: 1.0
5563    */
5564   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5565     g_param_spec_enum ("rotation-center-z-gravity",
5566                        P_("Rotation Center Z Gravity"),
5567                        P_("Center point for rotation around the Z axis"),
5568                        CLUTTER_TYPE_GRAVITY,
5569                        CLUTTER_GRAVITY_NONE,
5570                        CLUTTER_PARAM_READWRITE);
5571
5572   /**
5573    * ClutterActor:anchor-x:
5574    *
5575    * The X coordinate of an actor's anchor point, relative to
5576    * the actor coordinate space, in pixels
5577    *
5578    * Since: 0.8
5579    */
5580   obj_props[PROP_ANCHOR_X] =
5581     g_param_spec_float ("anchor-x",
5582                         P_("Anchor X"),
5583                         P_("X coordinate of the anchor point"),
5584                         -G_MAXFLOAT, G_MAXFLOAT,
5585                         0,
5586                         CLUTTER_PARAM_READWRITE);
5587
5588   /**
5589    * ClutterActor:anchor-y:
5590    *
5591    * The Y coordinate of an actor's anchor point, relative to
5592    * the actor coordinate space, in pixels
5593    *
5594    * Since: 0.8
5595    */
5596   obj_props[PROP_ANCHOR_Y] =
5597     g_param_spec_float ("anchor-y",
5598                         P_("Anchor Y"),
5599                         P_("Y coordinate of the anchor point"),
5600                         -G_MAXFLOAT, G_MAXFLOAT,
5601                         0,
5602                         CLUTTER_PARAM_READWRITE);
5603
5604   /**
5605    * ClutterActor:anchor-gravity:
5606    *
5607    * The anchor point expressed as a #ClutterGravity
5608    *
5609    * Since: 1.0
5610    */
5611   obj_props[PROP_ANCHOR_GRAVITY] =
5612     g_param_spec_enum ("anchor-gravity",
5613                        P_("Anchor Gravity"),
5614                        P_("The anchor point as a ClutterGravity"),
5615                        CLUTTER_TYPE_GRAVITY,
5616                        CLUTTER_GRAVITY_NONE,
5617                        CLUTTER_PARAM_READWRITE);
5618
5619   /**
5620    * ClutterActor:show-on-set-parent:
5621    *
5622    * If %TRUE, the actor is automatically shown when parented.
5623    *
5624    * Calling clutter_actor_hide() on an actor which has not been
5625    * parented will set this property to %FALSE as a side effect.
5626    *
5627    * Since: 0.8
5628    */
5629   obj_props[PROP_SHOW_ON_SET_PARENT] =
5630     g_param_spec_boolean ("show-on-set-parent",
5631                           P_("Show on set parent"),
5632                           P_("Whether the actor is shown when parented"),
5633                           TRUE,
5634                           CLUTTER_PARAM_READWRITE);
5635
5636   /**
5637    * ClutterActor:clip-to-allocation:
5638    *
5639    * Whether the clip region should track the allocated area
5640    * of the actor.
5641    *
5642    * This property is ignored if a clip area has been explicitly
5643    * set using clutter_actor_set_clip().
5644    *
5645    * Since: 1.0
5646    */
5647   obj_props[PROP_CLIP_TO_ALLOCATION] =
5648     g_param_spec_boolean ("clip-to-allocation",
5649                           P_("Clip to Allocation"),
5650                           P_("Sets the clip region to track the actor's allocation"),
5651                           FALSE,
5652                           CLUTTER_PARAM_READWRITE);
5653
5654   /**
5655    * ClutterActor:text-direction:
5656    *
5657    * The direction of the text inside a #ClutterActor.
5658    *
5659    * Since: 1.0
5660    */
5661   obj_props[PROP_TEXT_DIRECTION] =
5662     g_param_spec_enum ("text-direction",
5663                        P_("Text Direction"),
5664                        P_("Direction of the text"),
5665                        CLUTTER_TYPE_TEXT_DIRECTION,
5666                        CLUTTER_TEXT_DIRECTION_LTR,
5667                        CLUTTER_PARAM_READWRITE);
5668
5669   /**
5670    * ClutterActor:has-pointer:
5671    *
5672    * Whether the actor contains the pointer of a #ClutterInputDevice
5673    * or not.
5674    *
5675    * Since: 1.2
5676    */
5677   obj_props[PROP_HAS_POINTER] =
5678     g_param_spec_boolean ("has-pointer",
5679                           P_("Has Pointer"),
5680                           P_("Whether the actor contains the pointer of an input device"),
5681                           FALSE,
5682                           CLUTTER_PARAM_READABLE);
5683
5684   /**
5685    * ClutterActor:actions:
5686    *
5687    * Adds a #ClutterAction to the actor
5688    *
5689    * Since: 1.4
5690    */
5691   obj_props[PROP_ACTIONS] =
5692     g_param_spec_object ("actions",
5693                          P_("Actions"),
5694                          P_("Adds an action to the actor"),
5695                          CLUTTER_TYPE_ACTION,
5696                          CLUTTER_PARAM_WRITABLE);
5697
5698   /**
5699    * ClutterActor:constraints:
5700    *
5701    * Adds a #ClutterConstraint to the actor
5702    *
5703    * Since: 1.4
5704    */
5705   obj_props[PROP_CONSTRAINTS] =
5706     g_param_spec_object ("constraints",
5707                          P_("Constraints"),
5708                          P_("Adds a constraint to the actor"),
5709                          CLUTTER_TYPE_CONSTRAINT,
5710                          CLUTTER_PARAM_WRITABLE);
5711
5712   /**
5713    * ClutterActor:effect:
5714    *
5715    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5716    *
5717    * Since: 1.4
5718    */
5719   obj_props[PROP_EFFECT] =
5720     g_param_spec_object ("effect",
5721                          P_("Effect"),
5722                          P_("Add an effect to be applied on the actor"),
5723                          CLUTTER_TYPE_EFFECT,
5724                          CLUTTER_PARAM_WRITABLE);
5725
5726   /**
5727    * ClutterActor:layout-manager:
5728    *
5729    * A delegate object for controlling the layout of the children of
5730    * an actor.
5731    *
5732    * Since: 1.10
5733    */
5734   obj_props[PROP_LAYOUT_MANAGER] =
5735     g_param_spec_object ("layout-manager",
5736                          P_("Layout Manager"),
5737                          P_("The object controlling the layout of an actor's children"),
5738                          CLUTTER_TYPE_LAYOUT_MANAGER,
5739                          CLUTTER_PARAM_READWRITE);
5740
5741
5742   /**
5743    * ClutterActor:x-align:
5744    *
5745    * The alignment of an actor on the X axis, if the actor has been given
5746    * extra space for its allocation.
5747    *
5748    * Since: 1.10
5749    */
5750   obj_props[PROP_X_ALIGN] =
5751     g_param_spec_enum ("x-align",
5752                        P_("X Alignment"),
5753                        P_("The alignment of the actor on the X axis within its allocation"),
5754                        CLUTTER_TYPE_ACTOR_ALIGN,
5755                        CLUTTER_ACTOR_ALIGN_FILL,
5756                        CLUTTER_PARAM_READWRITE);
5757
5758   /**
5759    * ClutterActor:y-align:
5760    *
5761    * The alignment of an actor on the Y axis, if the actor has been given
5762    * extra space for its allocation.
5763    *
5764    * Since: 1.10
5765    */
5766   obj_props[PROP_Y_ALIGN] =
5767     g_param_spec_enum ("y-align",
5768                        P_("Y Alignment"),
5769                        P_("The alignment of the actor on the Y axis within its allocation"),
5770                        CLUTTER_TYPE_ACTOR_ALIGN,
5771                        CLUTTER_ACTOR_ALIGN_FILL,
5772                        CLUTTER_PARAM_READWRITE);
5773
5774   /**
5775    * ClutterActor:margin-top:
5776    *
5777    * The margin (in pixels) from the top of the actor.
5778    *
5779    * This property adds a margin to the actor's preferred size; the margin
5780    * will be automatically taken into account when allocating the actor.
5781    *
5782    * Since: 1.10
5783    */
5784   obj_props[PROP_MARGIN_TOP] =
5785     g_param_spec_float ("margin-top",
5786                         P_("Margin Top"),
5787                         P_("Extra space at the top"),
5788                         0.0, G_MAXFLOAT,
5789                         0.0,
5790                         CLUTTER_PARAM_READWRITE);
5791
5792   /**
5793    * ClutterActor:margin-bottom:
5794    *
5795    * The margin (in pixels) from the bottom of the actor.
5796    *
5797    * This property adds a margin to the actor's preferred size; the margin
5798    * will be automatically taken into account when allocating the actor.
5799    *
5800    * Since: 1.10
5801    */
5802   obj_props[PROP_MARGIN_BOTTOM] =
5803     g_param_spec_float ("margin-bottom",
5804                         P_("Margin Bottom"),
5805                         P_("Extra space at the bottom"),
5806                         0.0, G_MAXFLOAT,
5807                         0.0,
5808                         CLUTTER_PARAM_READWRITE);
5809
5810   /**
5811    * ClutterActor:margin-left:
5812    *
5813    * The margin (in pixels) from the left of the actor.
5814    *
5815    * This property adds a margin to the actor's preferred size; the margin
5816    * will be automatically taken into account when allocating the actor.
5817    *
5818    * Since: 1.10
5819    */
5820   obj_props[PROP_MARGIN_LEFT] =
5821     g_param_spec_float ("margin-left",
5822                         P_("Margin Left"),
5823                         P_("Extra space at the left"),
5824                         0.0, G_MAXFLOAT,
5825                         0.0,
5826                         CLUTTER_PARAM_READWRITE);
5827
5828   /**
5829    * ClutterActor:margin-right:
5830    *
5831    * The margin (in pixels) from the right of the actor.
5832    *
5833    * This property adds a margin to the actor's preferred size; the margin
5834    * will be automatically taken into account when allocating the actor.
5835    *
5836    * Since: 1.10
5837    */
5838   obj_props[PROP_MARGIN_RIGHT] =
5839     g_param_spec_float ("margin-right",
5840                         P_("Margin Right"),
5841                         P_("Extra space at the right"),
5842                         0.0, G_MAXFLOAT,
5843                         0.0,
5844                         CLUTTER_PARAM_READWRITE);
5845
5846   /**
5847    * ClutterActor:background-color-set:
5848    *
5849    * Whether the #ClutterActor:background-color property has been set.
5850    *
5851    * Since: 1.10
5852    */
5853   obj_props[PROP_BACKGROUND_COLOR_SET] =
5854     g_param_spec_boolean ("background-color-set",
5855                           P_("Background Color Set"),
5856                           P_("Whether the background color is set"),
5857                           FALSE,
5858                           CLUTTER_PARAM_READABLE);
5859
5860   /**
5861    * ClutterActor:background-color:
5862    *
5863    * Paints a solid fill of the actor's allocation using the specified
5864    * color.
5865    *
5866    * Since: 1.10
5867    */
5868   obj_props[PROP_BACKGROUND_COLOR] =
5869     clutter_param_spec_color ("background-color",
5870                               P_("Background color"),
5871                               P_("The actor's background color"),
5872                               CLUTTER_COLOR_Transparent,
5873                               CLUTTER_PARAM_READWRITE);
5874
5875   /**
5876    * ClutterActor:first-child:
5877    *
5878    * The actor's first child.
5879    *
5880    * Since: 1.10
5881    */
5882   obj_props[PROP_FIRST_CHILD] =
5883     g_param_spec_object ("first-child",
5884                          P_("First Child"),
5885                          P_("The actor's first child"),
5886                          CLUTTER_TYPE_ACTOR,
5887                          CLUTTER_PARAM_READABLE);
5888
5889   /**
5890    * ClutterActor:last-child:
5891    *
5892    * The actor's last child.
5893    *
5894    * Since: 1.10
5895    */
5896   obj_props[PROP_LAST_CHILD] =
5897     g_param_spec_object ("last-child",
5898                          P_("Last Child"),
5899                          P_("The actor's last child"),
5900                          CLUTTER_TYPE_ACTOR,
5901                          CLUTTER_PARAM_READABLE);
5902
5903   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
5904
5905   /**
5906    * ClutterActor::destroy:
5907    * @actor: the #ClutterActor which emitted the signal
5908    *
5909    * The ::destroy signal notifies that all references held on the
5910    * actor which emitted it should be released.
5911    *
5912    * The ::destroy signal should be used by all holders of a reference
5913    * on @actor.
5914    *
5915    * This signal might result in the finalization of the #ClutterActor
5916    * if all references are released.
5917    *
5918    * Composite actors and actors implementing the #ClutterContainer
5919    * interface should override the default implementation of the
5920    * class handler of this signal and call clutter_actor_destroy() on
5921    * their children. When overriding the default class handler, it is
5922    * required to chain up to the parent's implementation.
5923    *
5924    * Since: 0.2
5925    */
5926   actor_signals[DESTROY] =
5927     g_signal_new (I_("destroy"),
5928                   G_TYPE_FROM_CLASS (object_class),
5929                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
5930                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
5931                   NULL, NULL,
5932                   _clutter_marshal_VOID__VOID,
5933                   G_TYPE_NONE, 0);
5934   /**
5935    * ClutterActor::show:
5936    * @actor: the object which received the signal
5937    *
5938    * The ::show signal is emitted when an actor is visible and
5939    * rendered on the stage.
5940    *
5941    * Since: 0.2
5942    */
5943   actor_signals[SHOW] =
5944     g_signal_new (I_("show"),
5945                   G_TYPE_FROM_CLASS (object_class),
5946                   G_SIGNAL_RUN_FIRST,
5947                   G_STRUCT_OFFSET (ClutterActorClass, show),
5948                   NULL, NULL,
5949                   _clutter_marshal_VOID__VOID,
5950                   G_TYPE_NONE, 0);
5951   /**
5952    * ClutterActor::hide:
5953    * @actor: the object which received the signal
5954    *
5955    * The ::hide signal is emitted when an actor is no longer rendered
5956    * on the stage.
5957    *
5958    * Since: 0.2
5959    */
5960   actor_signals[HIDE] =
5961     g_signal_new (I_("hide"),
5962                   G_TYPE_FROM_CLASS (object_class),
5963                   G_SIGNAL_RUN_FIRST,
5964                   G_STRUCT_OFFSET (ClutterActorClass, hide),
5965                   NULL, NULL,
5966                   _clutter_marshal_VOID__VOID,
5967                   G_TYPE_NONE, 0);
5968   /**
5969    * ClutterActor::parent-set:
5970    * @actor: the object which received the signal
5971    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
5972    *
5973    * This signal is emitted when the parent of the actor changes.
5974    *
5975    * Since: 0.2
5976    */
5977   actor_signals[PARENT_SET] =
5978     g_signal_new (I_("parent-set"),
5979                   G_TYPE_FROM_CLASS (object_class),
5980                   G_SIGNAL_RUN_LAST,
5981                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
5982                   NULL, NULL,
5983                   _clutter_marshal_VOID__OBJECT,
5984                   G_TYPE_NONE, 1,
5985                   CLUTTER_TYPE_ACTOR);
5986
5987   /**
5988    * ClutterActor::queue-redraw:
5989    * @actor: the actor we're bubbling the redraw request through
5990    * @origin: the actor which initiated the redraw request
5991    *
5992    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
5993    * is called on @origin.
5994    *
5995    * The default implementation for #ClutterActor chains up to the
5996    * parent actor and queues a redraw on the parent, thus "bubbling"
5997    * the redraw queue up through the actor graph. The default
5998    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
5999    * in a main loop idle handler.
6000    *
6001    * Note that the @origin actor may be the stage, or a container; it
6002    * does not have to be a leaf node in the actor graph.
6003    *
6004    * Toolkits embedding a #ClutterStage which require a redraw and
6005    * relayout cycle can stop the emission of this signal using the
6006    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6007    * themselves, like:
6008    *
6009    * |[
6010    *   static void
6011    *   on_redraw_complete (gpointer data)
6012    *   {
6013    *     ClutterStage *stage = data;
6014    *
6015    *     /&ast; execute the Clutter drawing pipeline &ast;/
6016    *     clutter_stage_ensure_redraw (stage);
6017    *   }
6018    *
6019    *   static void
6020    *   on_stage_queue_redraw (ClutterStage *stage)
6021    *   {
6022    *     /&ast; this prevents the default handler to run &ast;/
6023    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6024    *
6025    *     /&ast; queue a redraw with the host toolkit and call
6026    *      &ast; a function when the redraw has been completed
6027    *      &ast;/
6028    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6029    *   }
6030    * ]|
6031    *
6032    * <note><para>This signal is emitted before the Clutter paint
6033    * pipeline is executed. If you want to know when the pipeline has
6034    * been completed you should connect to the ::paint signal on the
6035    * Stage with g_signal_connect_after().</para></note>
6036    *
6037    * Since: 1.0
6038    */
6039   actor_signals[QUEUE_REDRAW] =
6040     g_signal_new (I_("queue-redraw"),
6041                   G_TYPE_FROM_CLASS (object_class),
6042                   G_SIGNAL_RUN_LAST,
6043                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6044                   NULL, NULL,
6045                   _clutter_marshal_VOID__OBJECT,
6046                   G_TYPE_NONE, 1,
6047                   CLUTTER_TYPE_ACTOR);
6048
6049   /**
6050    * ClutterActor::queue-relayout
6051    * @actor: the actor being queued for relayout
6052    *
6053    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6054    * is called on an actor.
6055    *
6056    * The default implementation for #ClutterActor chains up to the
6057    * parent actor and queues a relayout on the parent, thus "bubbling"
6058    * the relayout queue up through the actor graph.
6059    *
6060    * The main purpose of this signal is to allow relayout to be propagated
6061    * properly in the procense of #ClutterClone actors. Applications will
6062    * not normally need to connect to this signal.
6063    *
6064    * Since: 1.2
6065    */
6066   actor_signals[QUEUE_RELAYOUT] =
6067     g_signal_new (I_("queue-relayout"),
6068                   G_TYPE_FROM_CLASS (object_class),
6069                   G_SIGNAL_RUN_LAST,
6070                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6071                   NULL, NULL,
6072                   _clutter_marshal_VOID__VOID,
6073                   G_TYPE_NONE, 0);
6074
6075   /**
6076    * ClutterActor::event:
6077    * @actor: the actor which received the event
6078    * @event: a #ClutterEvent
6079    *
6080    * The ::event signal is emitted each time an event is received
6081    * by the @actor. This signal will be emitted on every actor,
6082    * following the hierarchy chain, until it reaches the top-level
6083    * container (the #ClutterStage).
6084    *
6085    * Return value: %TRUE if the event has been handled by the actor,
6086    *   or %FALSE to continue the emission.
6087    *
6088    * Since: 0.6
6089    */
6090   actor_signals[EVENT] =
6091     g_signal_new (I_("event"),
6092                   G_TYPE_FROM_CLASS (object_class),
6093                   G_SIGNAL_RUN_LAST,
6094                   G_STRUCT_OFFSET (ClutterActorClass, event),
6095                   _clutter_boolean_handled_accumulator, NULL,
6096                   _clutter_marshal_BOOLEAN__BOXED,
6097                   G_TYPE_BOOLEAN, 1,
6098                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6099   /**
6100    * ClutterActor::button-press-event:
6101    * @actor: the actor which received the event
6102    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6103    *
6104    * The ::button-press-event signal is emitted each time a mouse button
6105    * is pressed on @actor.
6106    *
6107    * Return value: %TRUE if the event has been handled by the actor,
6108    *   or %FALSE to continue the emission.
6109    *
6110    * Since: 0.6
6111    */
6112   actor_signals[BUTTON_PRESS_EVENT] =
6113     g_signal_new (I_("button-press-event"),
6114                   G_TYPE_FROM_CLASS (object_class),
6115                   G_SIGNAL_RUN_LAST,
6116                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6117                   _clutter_boolean_handled_accumulator, NULL,
6118                   _clutter_marshal_BOOLEAN__BOXED,
6119                   G_TYPE_BOOLEAN, 1,
6120                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6121   /**
6122    * ClutterActor::button-release-event:
6123    * @actor: the actor which received the event
6124    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6125    *
6126    * The ::button-release-event signal is emitted each time a mouse button
6127    * is released on @actor.
6128    *
6129    * Return value: %TRUE if the event has been handled by the actor,
6130    *   or %FALSE to continue the emission.
6131    *
6132    * Since: 0.6
6133    */
6134   actor_signals[BUTTON_RELEASE_EVENT] =
6135     g_signal_new (I_("button-release-event"),
6136                   G_TYPE_FROM_CLASS (object_class),
6137                   G_SIGNAL_RUN_LAST,
6138                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6139                   _clutter_boolean_handled_accumulator, NULL,
6140                   _clutter_marshal_BOOLEAN__BOXED,
6141                   G_TYPE_BOOLEAN, 1,
6142                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6143   /**
6144    * ClutterActor::scroll-event:
6145    * @actor: the actor which received the event
6146    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6147    *
6148    * The ::scroll-event signal is emitted each time the mouse is
6149    * scrolled on @actor
6150    *
6151    * Return value: %TRUE if the event has been handled by the actor,
6152    *   or %FALSE to continue the emission.
6153    *
6154    * Since: 0.6
6155    */
6156   actor_signals[SCROLL_EVENT] =
6157     g_signal_new (I_("scroll-event"),
6158                   G_TYPE_FROM_CLASS (object_class),
6159                   G_SIGNAL_RUN_LAST,
6160                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6161                   _clutter_boolean_handled_accumulator, NULL,
6162                   _clutter_marshal_BOOLEAN__BOXED,
6163                   G_TYPE_BOOLEAN, 1,
6164                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6165   /**
6166    * ClutterActor::key-press-event:
6167    * @actor: the actor which received the event
6168    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6169    *
6170    * The ::key-press-event signal is emitted each time a keyboard button
6171    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6172    *
6173    * Return value: %TRUE if the event has been handled by the actor,
6174    *   or %FALSE to continue the emission.
6175    *
6176    * Since: 0.6
6177    */
6178   actor_signals[KEY_PRESS_EVENT] =
6179     g_signal_new (I_("key-press-event"),
6180                   G_TYPE_FROM_CLASS (object_class),
6181                   G_SIGNAL_RUN_LAST,
6182                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6183                   _clutter_boolean_handled_accumulator, NULL,
6184                   _clutter_marshal_BOOLEAN__BOXED,
6185                   G_TYPE_BOOLEAN, 1,
6186                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6187   /**
6188    * ClutterActor::key-release-event:
6189    * @actor: the actor which received the event
6190    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6191    *
6192    * The ::key-release-event signal is emitted each time a keyboard button
6193    * is released while @actor has key focus (see
6194    * clutter_stage_set_key_focus()).
6195    *
6196    * Return value: %TRUE if the event has been handled by the actor,
6197    *   or %FALSE to continue the emission.
6198    *
6199    * Since: 0.6
6200    */
6201   actor_signals[KEY_RELEASE_EVENT] =
6202     g_signal_new (I_("key-release-event"),
6203                   G_TYPE_FROM_CLASS (object_class),
6204                   G_SIGNAL_RUN_LAST,
6205                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6206                   _clutter_boolean_handled_accumulator, NULL,
6207                   _clutter_marshal_BOOLEAN__BOXED,
6208                   G_TYPE_BOOLEAN, 1,
6209                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6210   /**
6211    * ClutterActor::motion-event:
6212    * @actor: the actor which received the event
6213    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6214    *
6215    * The ::motion-event signal is emitted each time the mouse pointer is
6216    * moved over @actor.
6217    *
6218    * Return value: %TRUE if the event has been handled by the actor,
6219    *   or %FALSE to continue the emission.
6220    *
6221    * Since: 0.6
6222    */
6223   actor_signals[MOTION_EVENT] =
6224     g_signal_new (I_("motion-event"),
6225                   G_TYPE_FROM_CLASS (object_class),
6226                   G_SIGNAL_RUN_LAST,
6227                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6228                   _clutter_boolean_handled_accumulator, NULL,
6229                   _clutter_marshal_BOOLEAN__BOXED,
6230                   G_TYPE_BOOLEAN, 1,
6231                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6232
6233   /**
6234    * ClutterActor::key-focus-in:
6235    * @actor: the actor which now has key focus
6236    *
6237    * The ::key-focus-in signal is emitted when @actor receives key focus.
6238    *
6239    * Since: 0.6
6240    */
6241   actor_signals[KEY_FOCUS_IN] =
6242     g_signal_new (I_("key-focus-in"),
6243                   G_TYPE_FROM_CLASS (object_class),
6244                   G_SIGNAL_RUN_LAST,
6245                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6246                   NULL, NULL,
6247                   _clutter_marshal_VOID__VOID,
6248                   G_TYPE_NONE, 0);
6249
6250   /**
6251    * ClutterActor::key-focus-out:
6252    * @actor: the actor which now has key focus
6253    *
6254    * The ::key-focus-out signal is emitted when @actor loses key focus.
6255    *
6256    * Since: 0.6
6257    */
6258   actor_signals[KEY_FOCUS_OUT] =
6259     g_signal_new (I_("key-focus-out"),
6260                   G_TYPE_FROM_CLASS (object_class),
6261                   G_SIGNAL_RUN_LAST,
6262                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6263                   NULL, NULL,
6264                   _clutter_marshal_VOID__VOID,
6265                   G_TYPE_NONE, 0);
6266
6267   /**
6268    * ClutterActor::enter-event:
6269    * @actor: the actor which the pointer has entered.
6270    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6271    *
6272    * The ::enter-event signal is emitted when the pointer enters the @actor
6273    *
6274    * Return value: %TRUE if the event has been handled by the actor,
6275    *   or %FALSE to continue the emission.
6276    *
6277    * Since: 0.6
6278    */
6279   actor_signals[ENTER_EVENT] =
6280     g_signal_new (I_("enter-event"),
6281                   G_TYPE_FROM_CLASS (object_class),
6282                   G_SIGNAL_RUN_LAST,
6283                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6284                   _clutter_boolean_handled_accumulator, NULL,
6285                   _clutter_marshal_BOOLEAN__BOXED,
6286                   G_TYPE_BOOLEAN, 1,
6287                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6288
6289   /**
6290    * ClutterActor::leave-event:
6291    * @actor: the actor which the pointer has left
6292    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6293    *
6294    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6295    *
6296    * Return value: %TRUE if the event has been handled by the actor,
6297    *   or %FALSE to continue the emission.
6298    *
6299    * Since: 0.6
6300    */
6301   actor_signals[LEAVE_EVENT] =
6302     g_signal_new (I_("leave-event"),
6303                   G_TYPE_FROM_CLASS (object_class),
6304                   G_SIGNAL_RUN_LAST,
6305                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6306                   _clutter_boolean_handled_accumulator, NULL,
6307                   _clutter_marshal_BOOLEAN__BOXED,
6308                   G_TYPE_BOOLEAN, 1,
6309                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6310
6311   /**
6312    * ClutterActor::captured-event:
6313    * @actor: the actor which received the signal
6314    * @event: a #ClutterEvent
6315    *
6316    * The ::captured-event signal is emitted when an event is captured
6317    * by Clutter. This signal will be emitted starting from the top-level
6318    * container (the #ClutterStage) to the actor which received the event
6319    * going down the hierarchy. This signal can be used to intercept every
6320    * event before the specialized events (like
6321    * ClutterActor::button-press-event or ::key-released-event) are
6322    * emitted.
6323    *
6324    * Return value: %TRUE if the event has been handled by the actor,
6325    *   or %FALSE to continue the emission.
6326    *
6327    * Since: 0.6
6328    */
6329   actor_signals[CAPTURED_EVENT] =
6330     g_signal_new (I_("captured-event"),
6331                   G_TYPE_FROM_CLASS (object_class),
6332                   G_SIGNAL_RUN_LAST,
6333                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6334                   _clutter_boolean_handled_accumulator, NULL,
6335                   _clutter_marshal_BOOLEAN__BOXED,
6336                   G_TYPE_BOOLEAN, 1,
6337                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6338
6339   /**
6340    * ClutterActor::paint:
6341    * @actor: the #ClutterActor that received the signal
6342    *
6343    * The ::paint signal is emitted each time an actor is being painted.
6344    *
6345    * Subclasses of #ClutterActor should override the class signal handler
6346    * and paint themselves in that function.
6347    *
6348    * It is possible to connect a handler to the ::paint signal in order
6349    * to set up some custom aspect of a paint.
6350    *
6351    * Since: 0.8
6352    */
6353   actor_signals[PAINT] =
6354     g_signal_new (I_("paint"),
6355                   G_TYPE_FROM_CLASS (object_class),
6356                   G_SIGNAL_RUN_LAST,
6357                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6358                   NULL, NULL,
6359                   _clutter_marshal_VOID__VOID,
6360                   G_TYPE_NONE, 0);
6361   /**
6362    * ClutterActor::realize:
6363    * @actor: the #ClutterActor that received the signal
6364    *
6365    * The ::realize signal is emitted each time an actor is being
6366    * realized.
6367    *
6368    * Since: 0.8
6369    */
6370   actor_signals[REALIZE] =
6371     g_signal_new (I_("realize"),
6372                   G_TYPE_FROM_CLASS (object_class),
6373                   G_SIGNAL_RUN_LAST,
6374                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6375                   NULL, NULL,
6376                   _clutter_marshal_VOID__VOID,
6377                   G_TYPE_NONE, 0);
6378   /**
6379    * ClutterActor::unrealize:
6380    * @actor: the #ClutterActor that received the signal
6381    *
6382    * The ::unrealize signal is emitted each time an actor is being
6383    * unrealized.
6384    *
6385    * Since: 0.8
6386    */
6387   actor_signals[UNREALIZE] =
6388     g_signal_new (I_("unrealize"),
6389                   G_TYPE_FROM_CLASS (object_class),
6390                   G_SIGNAL_RUN_LAST,
6391                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6392                   NULL, NULL,
6393                   _clutter_marshal_VOID__VOID,
6394                   G_TYPE_NONE, 0);
6395
6396   /**
6397    * ClutterActor::pick:
6398    * @actor: the #ClutterActor that received the signal
6399    * @color: the #ClutterColor to be used when picking
6400    *
6401    * The ::pick signal is emitted each time an actor is being painted
6402    * in "pick mode". The pick mode is used to identify the actor during
6403    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6404    * The actor should paint its shape using the passed @pick_color.
6405    *
6406    * Subclasses of #ClutterActor should override the class signal handler
6407    * and paint themselves in that function.
6408    *
6409    * It is possible to connect a handler to the ::pick signal in order
6410    * to set up some custom aspect of a paint in pick mode.
6411    *
6412    * Since: 1.0
6413    */
6414   actor_signals[PICK] =
6415     g_signal_new (I_("pick"),
6416                   G_TYPE_FROM_CLASS (object_class),
6417                   G_SIGNAL_RUN_LAST,
6418                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6419                   NULL, NULL,
6420                   _clutter_marshal_VOID__BOXED,
6421                   G_TYPE_NONE, 1,
6422                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6423
6424   /**
6425    * ClutterActor::allocation-changed:
6426    * @actor: the #ClutterActor that emitted the signal
6427    * @box: a #ClutterActorBox with the new allocation
6428    * @flags: #ClutterAllocationFlags for the allocation
6429    *
6430    * The ::allocation-changed signal is emitted when the
6431    * #ClutterActor:allocation property changes. Usually, application
6432    * code should just use the notifications for the :allocation property
6433    * but if you want to track the allocation flags as well, for instance
6434    * to know whether the absolute origin of @actor changed, then you might
6435    * want use this signal instead.
6436    *
6437    * Since: 1.0
6438    */
6439   actor_signals[ALLOCATION_CHANGED] =
6440     g_signal_new (I_("allocation-changed"),
6441                   G_TYPE_FROM_CLASS (object_class),
6442                   G_SIGNAL_RUN_LAST,
6443                   0,
6444                   NULL, NULL,
6445                   _clutter_marshal_VOID__BOXED_FLAGS,
6446                   G_TYPE_NONE, 2,
6447                   CLUTTER_TYPE_ACTOR_BOX,
6448                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6449 }
6450
6451 static void
6452 clutter_actor_init (ClutterActor *self)
6453 {
6454   ClutterActorPrivate *priv;
6455
6456   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6457
6458   priv->id = _clutter_context_acquire_id (self);
6459   priv->pick_id = -1;
6460
6461   priv->opacity = 0xff;
6462   priv->show_on_set_parent = TRUE;
6463
6464   priv->needs_width_request = TRUE;
6465   priv->needs_height_request = TRUE;
6466   priv->needs_allocation = TRUE;
6467
6468   priv->cached_width_age = 1;
6469   priv->cached_height_age = 1;
6470
6471   priv->opacity_override = -1;
6472   priv->enable_model_view_transform = TRUE;
6473
6474   /* Initialize an empty paint volume to start with */
6475   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6476   priv->last_paint_volume_valid = TRUE;
6477
6478   priv->transform_valid = FALSE;
6479 }
6480
6481 /**
6482  * clutter_actor_new:
6483  *
6484  * Creates a new #ClutterActor.
6485  *
6486  * A newly created actor has a floating reference, which will be sunk
6487  * when it is added to another actor.
6488  *
6489  * Return value: (transfer full): the newly created #ClutterActor
6490  *
6491  * Since: 1.10
6492  */
6493 ClutterActor *
6494 clutter_actor_new (void)
6495 {
6496   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6497 }
6498
6499 /**
6500  * clutter_actor_destroy:
6501  * @self: a #ClutterActor
6502  *
6503  * Destroys an actor.  When an actor is destroyed, it will break any
6504  * references it holds to other objects.  If the actor is inside a
6505  * container, the actor will be removed.
6506  *
6507  * When you destroy a container, its children will be destroyed as well.
6508  *
6509  * Note: you cannot destroy the #ClutterStage returned by
6510  * clutter_stage_get_default().
6511  */
6512 void
6513 clutter_actor_destroy (ClutterActor *self)
6514 {
6515   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6516
6517   g_object_ref (self);
6518
6519   /* avoid recursion while destroying */
6520   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6521     {
6522       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6523
6524       g_object_run_dispose (G_OBJECT (self));
6525
6526       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6527     }
6528
6529   g_object_unref (self);
6530 }
6531
6532 void
6533 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6534                                     ClutterPaintVolume *clip)
6535 {
6536   ClutterActorPrivate *priv = self->priv;
6537   ClutterPaintVolume *pv;
6538   gboolean clipped;
6539
6540   /* Remove queue entry early in the process, otherwise a new
6541      queue_redraw() during signal handling could put back this
6542      object in the stage redraw list (but the entry is freed as
6543      soon as we return from this function, causing a segfault
6544      later)
6545   */
6546   priv->queue_redraw_entry = NULL;
6547
6548   /* If we've been explicitly passed a clip volume then there's
6549    * nothing more to calculate, but otherwise the only thing we know
6550    * is that the change is constrained to the given actor.
6551    *
6552    * The idea is that if we know the paint volume for where the actor
6553    * was last drawn (in eye coordinates) and we also have the paint
6554    * volume for where it will be drawn next (in actor coordinates)
6555    * then if we queue a redraw for both these volumes that will cover
6556    * everything that needs to be redrawn to clear the old view and
6557    * show the latest view of the actor.
6558    *
6559    * Don't clip this redraw if we don't know what position we had for
6560    * the previous redraw since we don't know where to set the clip so
6561    * it will clear the actor as it is currently.
6562    */
6563   if (clip)
6564     {
6565       _clutter_actor_set_queue_redraw_clip (self, clip);
6566       clipped = TRUE;
6567     }
6568   else if (G_LIKELY (priv->last_paint_volume_valid))
6569     {
6570       pv = _clutter_actor_get_paint_volume_mutable (self);
6571       if (pv)
6572         {
6573           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6574
6575           /* make sure we redraw the actors old position... */
6576           _clutter_actor_set_queue_redraw_clip (stage,
6577                                                 &priv->last_paint_volume);
6578           _clutter_actor_signal_queue_redraw (stage, stage);
6579           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6580
6581           /* XXX: Ideally the redraw signal would take a clip volume
6582            * argument, but that would be an ABI break. Until we can
6583            * break the ABI we pass the argument out-of-band
6584            */
6585
6586           /* setup the clip for the actors new position... */
6587           _clutter_actor_set_queue_redraw_clip (self, pv);
6588           clipped = TRUE;
6589         }
6590       else
6591         clipped = FALSE;
6592     }
6593   else
6594     clipped = FALSE;
6595
6596   _clutter_actor_signal_queue_redraw (self, self);
6597
6598   /* Just in case anyone is manually firing redraw signals without
6599    * using the public queue_redraw() API we are careful to ensure that
6600    * our out-of-band clip member is cleared before returning...
6601    *
6602    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6603    */
6604   if (G_LIKELY (clipped))
6605     _clutter_actor_set_queue_redraw_clip (self, NULL);
6606 }
6607
6608 static void
6609 _clutter_actor_get_allocation_clip (ClutterActor *self,
6610                                     ClutterActorBox *clip)
6611 {
6612   ClutterActorBox allocation;
6613
6614   /* XXX: we don't care if we get an out of date allocation here
6615    * because clutter_actor_queue_redraw_with_clip knows to ignore
6616    * the clip if the actor's allocation is invalid.
6617    *
6618    * This is noted because clutter_actor_get_allocation_box does some
6619    * unnecessary work to support buggy code with a comment suggesting
6620    * that it could be changed later which would be good for this use
6621    * case!
6622    */
6623   clutter_actor_get_allocation_box (self, &allocation);
6624
6625   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6626    * actor's own coordinate space but the allocation is in parent
6627    * coordinates */
6628   clip->x1 = 0;
6629   clip->y1 = 0;
6630   clip->x2 = allocation.x2 - allocation.x1;
6631   clip->y2 = allocation.y2 - allocation.y1;
6632 }
6633
6634 void
6635 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6636                                   ClutterRedrawFlags  flags,
6637                                   ClutterPaintVolume *volume,
6638                                   ClutterEffect      *effect)
6639 {
6640   ClutterActorPrivate *priv = self->priv;
6641   ClutterPaintVolume allocation_pv;
6642   ClutterPaintVolume *pv;
6643   gboolean should_free_pv;
6644   ClutterActor *stage;
6645
6646   /* Here's an outline of the actor queue redraw mechanism:
6647    *
6648    * The process starts in one of the following two functions which
6649    * are wrappers for this function:
6650    * clutter_actor_queue_redraw
6651    * _clutter_actor_queue_redraw_with_clip
6652    *
6653    * additionally, an effect can queue a redraw by wrapping this
6654    * function in clutter_effect_queue_rerun
6655    *
6656    * This functions queues an entry in a list associated with the
6657    * stage which is a list of actors that queued a redraw while
6658    * updating the timelines, performing layouting and processing other
6659    * mainloop sources before the next paint starts.
6660    *
6661    * We aim to minimize the processing done at this point because
6662    * there is a good chance other events will happen while updating
6663    * the scenegraph that would invalidate any expensive work we might
6664    * otherwise try to do here. For example we don't try and resolve
6665    * the screen space bounding box of an actor at this stage so as to
6666    * minimize how much of the screen redraw because it's possible
6667    * something else will happen which will force a full redraw anyway.
6668    *
6669    * When all updates are complete and we come to paint the stage then
6670    * we iterate this list and actually emit the "queue-redraw" signals
6671    * for each of the listed actors which will bubble up to the stage
6672    * for each actor and at that point we will transform the actors
6673    * paint volume into screen coordinates to determine the clip region
6674    * for what needs to be redrawn in the next paint.
6675    *
6676    * Besides minimizing redundant work another reason for this
6677    * deferred design is that it's more likely we will be able to
6678    * determine the paint volume of an actor once we've finished
6679    * updating the scenegraph because its allocation should be up to
6680    * date. NB: If we can't determine an actors paint volume then we
6681    * can't automatically queue a clipped redraw which can make a big
6682    * difference to performance.
6683    *
6684    * So the control flow goes like this:
6685    * One of clutter_actor_queue_redraw,
6686    *        _clutter_actor_queue_redraw_with_clip
6687    *     or clutter_effect_queue_rerun
6688    *
6689    * then control moves to:
6690    *   _clutter_stage_queue_actor_redraw
6691    *
6692    * later during _clutter_stage_do_update, once relayouting is done
6693    * and the scenegraph has been updated we will call:
6694    * _clutter_stage_finish_queue_redraws
6695    *
6696    * _clutter_stage_finish_queue_redraws will call
6697    * _clutter_actor_finish_queue_redraw for each listed actor.
6698    * Note: actors *are* allowed to queue further redraws during this
6699    * process (considering clone actors or texture_new_from_actor which
6700    * respond to their source queueing a redraw by queuing a redraw
6701    * themselves). We repeat the process until the list is empty.
6702    *
6703    * This will result in the "queue-redraw" signal being fired for
6704    * each actor which will pass control to the default signal handler:
6705    * clutter_actor_real_queue_redraw
6706    *
6707    * This will bubble up to the stages handler:
6708    * clutter_stage_real_queue_redraw
6709    *
6710    * clutter_stage_real_queue_redraw will transform the actors paint
6711    * volume into screen space and add it as a clip region for the next
6712    * paint.
6713    */
6714
6715   /* ignore queueing a redraw for actors being destroyed */
6716   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6717     return;
6718
6719   stage = _clutter_actor_get_stage_internal (self);
6720
6721   /* Ignore queueing a redraw for actors not descended from a stage */
6722   if (stage == NULL)
6723     return;
6724
6725   /* ignore queueing a redraw on stages that are being destroyed */
6726   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6727     return;
6728
6729   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6730     {
6731       ClutterActorBox allocation_clip;
6732       ClutterVertex origin;
6733
6734       /* If the actor doesn't have a valid allocation then we will
6735        * queue a full stage redraw. */
6736       if (priv->needs_allocation)
6737         {
6738           /* NB: NULL denotes an undefined clip which will result in a
6739            * full redraw... */
6740           _clutter_actor_set_queue_redraw_clip (self, NULL);
6741           _clutter_actor_signal_queue_redraw (self, self);
6742           return;
6743         }
6744
6745       _clutter_paint_volume_init_static (&allocation_pv, self);
6746       pv = &allocation_pv;
6747
6748       _clutter_actor_get_allocation_clip (self, &allocation_clip);
6749
6750       origin.x = allocation_clip.x1;
6751       origin.y = allocation_clip.y1;
6752       origin.z = 0;
6753       clutter_paint_volume_set_origin (pv, &origin);
6754       clutter_paint_volume_set_width (pv,
6755                                       allocation_clip.x2 - allocation_clip.x1);
6756       clutter_paint_volume_set_height (pv,
6757                                        allocation_clip.y2 -
6758                                        allocation_clip.y1);
6759       should_free_pv = TRUE;
6760     }
6761   else
6762     {
6763       pv = volume;
6764       should_free_pv = FALSE;
6765     }
6766
6767   self->priv->queue_redraw_entry =
6768     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6769                                        priv->queue_redraw_entry,
6770                                        self,
6771                                        pv);
6772
6773   if (should_free_pv)
6774     clutter_paint_volume_free (pv);
6775
6776   /* If this is the first redraw queued then we can directly use the
6777      effect parameter */
6778   if (!priv->is_dirty)
6779     priv->effect_to_redraw = effect;
6780   /* Otherwise we need to merge it with the existing effect parameter */
6781   else if (effect != NULL)
6782     {
6783       /* If there's already an effect then we need to use whichever is
6784          later in the chain of actors. Otherwise a full redraw has
6785          already been queued on the actor so we need to ignore the
6786          effect parameter */
6787       if (priv->effect_to_redraw != NULL)
6788         {
6789           if (priv->effects == NULL)
6790             g_warning ("Redraw queued with an effect that is "
6791                        "not applied to the actor");
6792           else
6793             {
6794               const GList *l;
6795
6796               for (l = _clutter_meta_group_peek_metas (priv->effects);
6797                    l != NULL;
6798                    l = l->next)
6799                 {
6800                   if (l->data == priv->effect_to_redraw ||
6801                       l->data == effect)
6802                     priv->effect_to_redraw = l->data;
6803                 }
6804             }
6805         }
6806     }
6807   else
6808     {
6809       /* If no effect is specified then we need to redraw the whole
6810          actor */
6811       priv->effect_to_redraw = NULL;
6812     }
6813
6814   priv->is_dirty = TRUE;
6815 }
6816
6817 /**
6818  * clutter_actor_queue_redraw:
6819  * @self: A #ClutterActor
6820  *
6821  * Queues up a redraw of an actor and any children. The redraw occurs
6822  * once the main loop becomes idle (after the current batch of events
6823  * has been processed, roughly).
6824  *
6825  * Applications rarely need to call this, as redraws are handled
6826  * automatically by modification functions.
6827  *
6828  * This function will not do anything if @self is not visible, or
6829  * if the actor is inside an invisible part of the scenegraph.
6830  *
6831  * Also be aware that painting is a NOP for actors with an opacity of
6832  * 0
6833  *
6834  * When you are implementing a custom actor you must queue a redraw
6835  * whenever some private state changes that will affect painting or
6836  * picking of your actor.
6837  */
6838 void
6839 clutter_actor_queue_redraw (ClutterActor *self)
6840 {
6841   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6842
6843   _clutter_actor_queue_redraw_full (self,
6844                                     0, /* flags */
6845                                     NULL, /* clip volume */
6846                                     NULL /* effect */);
6847 }
6848
6849 /*< private >
6850  * _clutter_actor_queue_redraw_with_clip:
6851  * @self: A #ClutterActor
6852  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
6853  *   this queue redraw.
6854  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
6855  *   redrawn or %NULL if you are just using a @flag to state your
6856  *   desired clipping.
6857  *
6858  * Queues up a clipped redraw of an actor and any children. The redraw
6859  * occurs once the main loop becomes idle (after the current batch of
6860  * events has been processed, roughly).
6861  *
6862  * If no flags are given the clip volume is defined by @volume
6863  * specified in actor coordinates and tells Clutter that only content
6864  * within this volume has been changed so Clutter can optionally
6865  * optimize the redraw.
6866  *
6867  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
6868  * should be %NULL and this tells Clutter to use the actor's current
6869  * allocation as a clip box. This flag can only be used for 2D actors,
6870  * because any actor with depth may be projected outside its
6871  * allocation.
6872  *
6873  * Applications rarely need to call this, as redraws are handled
6874  * automatically by modification functions.
6875  *
6876  * This function will not do anything if @self is not visible, or if
6877  * the actor is inside an invisible part of the scenegraph.
6878  *
6879  * Also be aware that painting is a NOP for actors with an opacity of
6880  * 0
6881  *
6882  * When you are implementing a custom actor you must queue a redraw
6883  * whenever some private state changes that will affect painting or
6884  * picking of your actor.
6885  */
6886 void
6887 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
6888                                        ClutterRedrawFlags  flags,
6889                                        ClutterPaintVolume *volume)
6890 {
6891   _clutter_actor_queue_redraw_full (self,
6892                                     flags, /* flags */
6893                                     volume, /* clip volume */
6894                                     NULL /* effect */);
6895 }
6896
6897 static void
6898 _clutter_actor_queue_only_relayout (ClutterActor *self)
6899 {
6900   ClutterActorPrivate *priv = self->priv;
6901
6902   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6903     return;
6904
6905   if (priv->needs_width_request &&
6906       priv->needs_height_request &&
6907       priv->needs_allocation)
6908     return; /* save some cpu cycles */
6909
6910 #if CLUTTER_ENABLE_DEBUG
6911   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
6912     {
6913       g_warning ("The actor '%s' is currently inside an allocation "
6914                  "cycle; calling clutter_actor_queue_relayout() is "
6915                  "not recommended",
6916                  _clutter_actor_get_debug_name (self));
6917     }
6918 #endif /* CLUTTER_ENABLE_DEBUG */
6919
6920   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
6921 }
6922
6923 /**
6924  * clutter_actor_queue_redraw_with_clip:
6925  * @self: a #ClutterActor
6926  * @clip: (allow-none): a rectangular clip region, or %NULL
6927  *
6928  * Queues a redraw on @self limited to a specific, actor-relative
6929  * rectangular area.
6930  *
6931  * If @clip is %NULL this function is equivalent to
6932  * clutter_actor_queue_redraw().
6933  *
6934  * Since: 1.10
6935  */
6936 void
6937 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
6938                                       const cairo_rectangle_int_t *clip)
6939 {
6940   ClutterPaintVolume volume;
6941   ClutterVertex origin;
6942
6943   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6944
6945   if (clip == NULL)
6946     {
6947       clutter_actor_queue_redraw (self);
6948       return;
6949     }
6950
6951   _clutter_paint_volume_init_static (&volume, self);
6952
6953   origin.x = clip->x;
6954   origin.y = clip->y;
6955   origin.z = 0.0f;
6956
6957   clutter_paint_volume_set_origin (&volume, &origin);
6958   clutter_paint_volume_set_width (&volume, clip->width);
6959   clutter_paint_volume_set_height (&volume, clip->height);
6960
6961   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
6962
6963   clutter_paint_volume_free (&volume);
6964 }
6965
6966 /**
6967  * clutter_actor_queue_relayout:
6968  * @self: A #ClutterActor
6969  *
6970  * Indicates that the actor's size request or other layout-affecting
6971  * properties may have changed. This function is used inside #ClutterActor
6972  * subclass implementations, not by applications directly.
6973  *
6974  * Queueing a new layout automatically queues a redraw as well.
6975  *
6976  * Since: 0.8
6977  */
6978 void
6979 clutter_actor_queue_relayout (ClutterActor *self)
6980 {
6981   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6982
6983   _clutter_actor_queue_only_relayout (self);
6984   clutter_actor_queue_redraw (self);
6985 }
6986
6987 /**
6988  * clutter_actor_get_preferred_size:
6989  * @self: a #ClutterActor
6990  * @min_width_p: (out) (allow-none): return location for the minimum
6991  *   width, or %NULL
6992  * @min_height_p: (out) (allow-none): return location for the minimum
6993  *   height, or %NULL
6994  * @natural_width_p: (out) (allow-none): return location for the natural
6995  *   width, or %NULL
6996  * @natural_height_p: (out) (allow-none): return location for the natural
6997  *   height, or %NULL
6998  *
6999  * Computes the preferred minimum and natural size of an actor, taking into
7000  * account the actor's geometry management (either height-for-width
7001  * or width-for-height).
7002  *
7003  * The width and height used to compute the preferred height and preferred
7004  * width are the actor's natural ones.
7005  *
7006  * If you need to control the height for the preferred width, or the width for
7007  * the preferred height, you should use clutter_actor_get_preferred_width()
7008  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7009  * geometry management using the #ClutterActor:request-mode property.
7010  *
7011  * Since: 0.8
7012  */
7013 void
7014 clutter_actor_get_preferred_size (ClutterActor *self,
7015                                   gfloat       *min_width_p,
7016                                   gfloat       *min_height_p,
7017                                   gfloat       *natural_width_p,
7018                                   gfloat       *natural_height_p)
7019 {
7020   ClutterActorPrivate *priv;
7021   gfloat min_width, min_height;
7022   gfloat natural_width, natural_height;
7023
7024   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7025
7026   priv = self->priv;
7027
7028   min_width = min_height = 0;
7029   natural_width = natural_height = 0;
7030
7031   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7032     {
7033       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7034       clutter_actor_get_preferred_width (self, -1,
7035                                          &min_width,
7036                                          &natural_width);
7037       clutter_actor_get_preferred_height (self, natural_width,
7038                                           &min_height,
7039                                           &natural_height);
7040     }
7041   else
7042     {
7043       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7044       clutter_actor_get_preferred_height (self, -1,
7045                                           &min_height,
7046                                           &natural_height);
7047       clutter_actor_get_preferred_width (self, natural_height,
7048                                          &min_width,
7049                                          &natural_width);
7050     }
7051
7052   if (min_width_p)
7053     *min_width_p = min_width;
7054
7055   if (min_height_p)
7056     *min_height_p = min_height;
7057
7058   if (natural_width_p)
7059     *natural_width_p = natural_width;
7060
7061   if (natural_height_p)
7062     *natural_height_p = natural_height;
7063 }
7064
7065 /*< private >
7066  * effective_align:
7067  * @align: a #ClutterActorAlign
7068  * @direction: a #ClutterTextDirection
7069  *
7070  * Retrieves the correct alignment depending on the text direction
7071  *
7072  * Return value: the effective alignment
7073  */
7074 static ClutterActorAlign
7075 effective_align (ClutterActorAlign    align,
7076                  ClutterTextDirection direction)
7077 {
7078   ClutterActorAlign res;
7079
7080   switch (align)
7081     {
7082     case CLUTTER_ACTOR_ALIGN_START:
7083       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7084           ? CLUTTER_ACTOR_ALIGN_END
7085           : CLUTTER_ACTOR_ALIGN_START;
7086       break;
7087
7088     case CLUTTER_ACTOR_ALIGN_END:
7089       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7090           ? CLUTTER_ACTOR_ALIGN_START
7091           : CLUTTER_ACTOR_ALIGN_END;
7092       break;
7093
7094     default:
7095       res = align;
7096       break;
7097     }
7098
7099   return res;
7100 }
7101
7102 static inline void
7103 adjust_for_margin (float  margin_start,
7104                    float  margin_end,
7105                    float *minimum_size,
7106                    float *natural_size,
7107                    float *allocated_start,
7108                    float *allocated_end)
7109 {
7110   *minimum_size -= (margin_start + margin_end);
7111   *natural_size -= (margin_start + margin_end);
7112   *allocated_start += margin_start;
7113   *allocated_end -= margin_end;
7114 }
7115
7116 static inline void
7117 adjust_for_alignment (ClutterActorAlign  alignment,
7118                       float              natural_size,
7119                       float             *allocated_start,
7120                       float             *allocated_end)
7121 {
7122   float allocated_size = *allocated_end - *allocated_start;
7123
7124   switch (alignment)
7125     {
7126     case CLUTTER_ACTOR_ALIGN_FILL:
7127       /* do nothing */
7128       break;
7129
7130     case CLUTTER_ACTOR_ALIGN_START:
7131       /* keep start */
7132       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7133       break;
7134
7135     case CLUTTER_ACTOR_ALIGN_END:
7136       if (allocated_size > natural_size)
7137         {
7138           *allocated_start += (allocated_size - natural_size);
7139           *allocated_end = *allocated_start + natural_size;
7140         }
7141       break;
7142
7143     case CLUTTER_ACTOR_ALIGN_CENTER:
7144       if (allocated_size > natural_size)
7145         {
7146           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7147           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7148         }
7149       break;
7150     }
7151 }
7152
7153 /*< private >
7154  * clutter_actor_adjust_width:
7155  * @self: a #ClutterActor
7156  * @minimum_width: (inout): the actor's preferred minimum width, which
7157  *   will be adjusted depending on the margin
7158  * @natural_width: (inout): the actor's preferred natural width, which
7159  *   will be adjusted depending on the margin
7160  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7161  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7162  *
7163  * Adjusts the preferred and allocated position and size of an actor,
7164  * depending on the margin and alignment properties.
7165  */
7166 static void
7167 clutter_actor_adjust_width (ClutterActor *self,
7168                             gfloat       *minimum_width,
7169                             gfloat       *natural_width,
7170                             gfloat       *adjusted_x1,
7171                             gfloat       *adjusted_x2)
7172 {
7173   ClutterTextDirection text_dir;
7174   const ClutterLayoutInfo *info;
7175
7176   info = _clutter_actor_get_layout_info_or_defaults (self);
7177   text_dir = clutter_actor_get_text_direction (self);
7178
7179   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7180
7181   /* this will tweak natural_width to remove the margin, so that
7182    * adjust_for_alignment() will use the correct size
7183    */
7184   adjust_for_margin (info->margin.left, info->margin.right,
7185                      minimum_width, natural_width,
7186                      adjusted_x1, adjusted_x2);
7187
7188   adjust_for_alignment (effective_align (info->x_align, text_dir),
7189                         *natural_width,
7190                         adjusted_x1, adjusted_x2);
7191 }
7192
7193 /*< private >
7194  * clutter_actor_adjust_height:
7195  * @self: a #ClutterActor
7196  * @minimum_height: (inout): the actor's preferred minimum height, which
7197  *   will be adjusted depending on the margin
7198  * @natural_height: (inout): the actor's preferred natural height, which
7199  *   will be adjusted depending on the margin
7200  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7201  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7202  *
7203  * Adjusts the preferred and allocated position and size of an actor,
7204  * depending on the margin and alignment properties.
7205  */
7206 static void
7207 clutter_actor_adjust_height (ClutterActor *self,
7208                              gfloat       *minimum_height,
7209                              gfloat       *natural_height,
7210                              gfloat       *adjusted_y1,
7211                              gfloat       *adjusted_y2)
7212 {
7213   const ClutterLayoutInfo *info;
7214
7215   info = _clutter_actor_get_layout_info_or_defaults (self);
7216
7217   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7218
7219   /* this will tweak natural_height to remove the margin, so that
7220    * adjust_for_alignment() will use the correct size
7221    */
7222   adjust_for_margin (info->margin.top, info->margin.bottom,
7223                      minimum_height, natural_height,
7224                      adjusted_y1,
7225                      adjusted_y2);
7226
7227   /* we don't use effective_align() here, because text direction
7228    * only affects the horizontal axis
7229    */
7230   adjust_for_alignment (info->y_align,
7231                         *natural_height,
7232                         adjusted_y1,
7233                         adjusted_y2);
7234
7235 }
7236
7237 /* looks for a cached size request for this for_size. If not
7238  * found, returns the oldest entry so it can be overwritten */
7239 static gboolean
7240 _clutter_actor_get_cached_size_request (gfloat         for_size,
7241                                         SizeRequest   *cached_size_requests,
7242                                         SizeRequest  **result)
7243 {
7244   guint i;
7245
7246   *result = &cached_size_requests[0];
7247
7248   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7249     {
7250       SizeRequest *sr;
7251
7252       sr = &cached_size_requests[i];
7253
7254       if (sr->age > 0 &&
7255           sr->for_size == for_size)
7256         {
7257           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7258           *result = sr;
7259           return TRUE;
7260         }
7261       else if (sr->age < (*result)->age)
7262         {
7263           *result = sr;
7264         }
7265     }
7266
7267   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7268
7269   return FALSE;
7270 }
7271
7272 /**
7273  * clutter_actor_get_preferred_width:
7274  * @self: A #ClutterActor
7275  * @for_height: available height when computing the preferred width,
7276  *   or a negative value to indicate that no height is defined
7277  * @min_width_p: (out) (allow-none): return location for minimum width,
7278  *   or %NULL
7279  * @natural_width_p: (out) (allow-none): return location for the natural
7280  *   width, or %NULL
7281  *
7282  * Computes the requested minimum and natural widths for an actor,
7283  * optionally depending on the specified height, or if they are
7284  * already computed, returns the cached values.
7285  *
7286  * An actor may not get its request - depending on the layout
7287  * manager that's in effect.
7288  *
7289  * A request should not incorporate the actor's scale or anchor point;
7290  * those transformations do not affect layout, only rendering.
7291  *
7292  * Since: 0.8
7293  */
7294 void
7295 clutter_actor_get_preferred_width (ClutterActor *self,
7296                                    gfloat        for_height,
7297                                    gfloat       *min_width_p,
7298                                    gfloat       *natural_width_p)
7299 {
7300   float request_min_width, request_natural_width;
7301   SizeRequest *cached_size_request;
7302   const ClutterLayoutInfo *info;
7303   ClutterActorPrivate *priv;
7304   gboolean found_in_cache;
7305
7306   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7307
7308   priv = self->priv;
7309
7310   info = _clutter_actor_get_layout_info_or_defaults (self);
7311
7312   /* we shortcircuit the case of a fixed size set using set_width() */
7313   if (priv->min_width_set && priv->natural_width_set)
7314     {
7315       if (min_width_p != NULL)
7316         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7317
7318       if (natural_width_p != NULL)
7319         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7320
7321       return;
7322     }
7323
7324   /* the remaining cases are:
7325    *
7326    *   - either min_width or natural_width have been set
7327    *   - neither min_width or natural_width have been set
7328    *
7329    * in both cases, we go through the cache (and through the actor in case
7330    * of cache misses) and determine the authoritative value depending on
7331    * the *_set flags.
7332    */
7333
7334   if (!priv->needs_width_request)
7335     {
7336       found_in_cache =
7337         _clutter_actor_get_cached_size_request (for_height,
7338                                                 priv->width_requests,
7339                                                 &cached_size_request);
7340     }
7341   else
7342     {
7343       /* if the actor needs a width request we use the first slot */
7344       found_in_cache = FALSE;
7345       cached_size_request = &priv->width_requests[0];
7346     }
7347
7348   if (!found_in_cache)
7349     {
7350       gfloat minimum_width, natural_width;
7351       ClutterActorClass *klass;
7352
7353       minimum_width = natural_width = 0;
7354
7355       /* adjust for the margin */
7356       if (for_height >= 0)
7357         {
7358           for_height -= (info->margin.top + info->margin.bottom);
7359           if (for_height < 0)
7360             for_height = 0;
7361         }
7362
7363       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7364
7365       klass = CLUTTER_ACTOR_GET_CLASS (self);
7366       klass->get_preferred_width (self, for_height,
7367                                   &minimum_width,
7368                                   &natural_width);
7369
7370       /* adjust for the margin */
7371       minimum_width += (info->margin.left + info->margin.right);
7372       natural_width += (info->margin.left + info->margin.right);
7373
7374       /* Due to accumulated float errors, it's better not to warn
7375        * on this, but just fix it.
7376        */
7377       if (natural_width < minimum_width)
7378         natural_width = minimum_width;
7379
7380       cached_size_request->min_size = minimum_width;
7381       cached_size_request->natural_size = natural_width;
7382       cached_size_request->for_size = for_height;
7383       cached_size_request->age = priv->cached_width_age;
7384
7385       priv->cached_width_age += 1;
7386       priv->needs_width_request = FALSE;
7387     }
7388
7389   if (!priv->min_width_set)
7390     request_min_width = cached_size_request->min_size;
7391   else
7392     request_min_width = info->min_width;
7393
7394   if (!priv->natural_width_set)
7395     request_natural_width = cached_size_request->natural_size;
7396   else
7397     request_natural_width = info->natural_width;
7398
7399   if (min_width_p)
7400     *min_width_p = request_min_width;
7401
7402   if (natural_width_p)
7403     *natural_width_p = request_natural_width;
7404 }
7405
7406 /**
7407  * clutter_actor_get_preferred_height:
7408  * @self: A #ClutterActor
7409  * @for_width: available width to assume in computing desired height,
7410  *   or a negative value to indicate that no width is defined
7411  * @min_height_p: (out) (allow-none): return location for minimum height,
7412  *   or %NULL
7413  * @natural_height_p: (out) (allow-none): return location for natural
7414  *   height, or %NULL
7415  *
7416  * Computes the requested minimum and natural heights for an actor,
7417  * or if they are already computed, returns the cached values.
7418  *
7419  * An actor may not get its request - depending on the layout
7420  * manager that's in effect.
7421  *
7422  * A request should not incorporate the actor's scale or anchor point;
7423  * those transformations do not affect layout, only rendering.
7424  *
7425  * Since: 0.8
7426  */
7427 void
7428 clutter_actor_get_preferred_height (ClutterActor *self,
7429                                     gfloat        for_width,
7430                                     gfloat       *min_height_p,
7431                                     gfloat       *natural_height_p)
7432 {
7433   float request_min_height, request_natural_height;
7434   SizeRequest *cached_size_request;
7435   const ClutterLayoutInfo *info;
7436   ClutterActorPrivate *priv;
7437   gboolean found_in_cache;
7438
7439   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7440
7441   priv = self->priv;
7442
7443   info = _clutter_actor_get_layout_info_or_defaults (self);
7444
7445   /* we shortcircuit the case of a fixed size set using set_height() */
7446   if (priv->min_height_set && priv->natural_height_set)
7447     {
7448       if (min_height_p != NULL)
7449         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7450
7451       if (natural_height_p != NULL)
7452         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7453
7454       return;
7455     }
7456
7457   /* the remaining cases are:
7458    *
7459    *   - either min_height or natural_height have been set
7460    *   - neither min_height or natural_height have been set
7461    *
7462    * in both cases, we go through the cache (and through the actor in case
7463    * of cache misses) and determine the authoritative value depending on
7464    * the *_set flags.
7465    */
7466
7467   if (!priv->needs_height_request)
7468     {
7469       found_in_cache =
7470         _clutter_actor_get_cached_size_request (for_width,
7471                                                 priv->height_requests,
7472                                                 &cached_size_request);
7473     }
7474   else
7475     {
7476       found_in_cache = FALSE;
7477       cached_size_request = &priv->height_requests[0];
7478     }
7479
7480   if (!found_in_cache)
7481     {
7482       gfloat minimum_height, natural_height;
7483       ClutterActorClass *klass;
7484
7485       minimum_height = natural_height = 0;
7486
7487       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7488
7489       /* adjust for margin */
7490       if (for_width >= 0)
7491         {
7492           for_width -= (info->margin.left + info->margin.right);
7493           if (for_width < 0)
7494             for_width = 0;
7495         }
7496
7497       klass = CLUTTER_ACTOR_GET_CLASS (self);
7498       klass->get_preferred_height (self, for_width,
7499                                    &minimum_height,
7500                                    &natural_height);
7501
7502       /* adjust for margin */
7503       minimum_height += (info->margin.top + info->margin.bottom);
7504       natural_height += (info->margin.top + info->margin.bottom);
7505
7506       /* Due to accumulated float errors, it's better not to warn
7507        * on this, but just fix it.
7508        */
7509       if (natural_height < minimum_height)
7510         natural_height = minimum_height;
7511
7512       cached_size_request->min_size = minimum_height;
7513       cached_size_request->natural_size = natural_height;
7514       cached_size_request->for_size = for_width;
7515       cached_size_request->age = priv->cached_height_age;
7516
7517       priv->cached_height_age += 1;
7518       priv->needs_height_request = FALSE;
7519     }
7520
7521   if (!priv->min_height_set)
7522     request_min_height = cached_size_request->min_size;
7523   else
7524     request_min_height = info->min_height;
7525
7526   if (!priv->natural_height_set)
7527     request_natural_height = cached_size_request->natural_size;
7528   else
7529     request_natural_height = info->natural_height;
7530
7531   if (min_height_p)
7532     *min_height_p = request_min_height;
7533
7534   if (natural_height_p)
7535     *natural_height_p = request_natural_height;
7536 }
7537
7538 /**
7539  * clutter_actor_get_allocation_box:
7540  * @self: A #ClutterActor
7541  * @box: (out): the function fills this in with the actor's allocation
7542  *
7543  * Gets the layout box an actor has been assigned. The allocation can
7544  * only be assumed valid inside a paint() method; anywhere else, it
7545  * may be out-of-date.
7546  *
7547  * An allocation does not incorporate the actor's scale or anchor point;
7548  * those transformations do not affect layout, only rendering.
7549  *
7550  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7551  * of functions inside the implementation of the get_preferred_width()
7552  * or get_preferred_height() virtual functions.</note>
7553  *
7554  * Since: 0.8
7555  */
7556 void
7557 clutter_actor_get_allocation_box (ClutterActor    *self,
7558                                   ClutterActorBox *box)
7559 {
7560   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7561
7562   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7563    * which limits calling get_allocation to inside paint() basically; or
7564    * we can 2) force a layout, which could be expensive if someone calls
7565    * get_allocation somewhere silly; or we can 3) just return the latest
7566    * value, allowing it to be out-of-date, and assume people know what
7567    * they are doing.
7568    *
7569    * The least-surprises approach that keeps existing code working is
7570    * likely to be 2). People can end up doing some inefficient things,
7571    * though, and in general code that requires 2) is probably broken.
7572    */
7573
7574   /* this implements 2) */
7575   if (G_UNLIKELY (self->priv->needs_allocation))
7576     {
7577       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7578
7579       /* do not queue a relayout on an unparented actor */
7580       if (stage)
7581         _clutter_stage_maybe_relayout (stage);
7582     }
7583
7584   /* commenting out the code above and just keeping this assigment
7585    * implements 3)
7586    */
7587   *box = self->priv->allocation;
7588 }
7589
7590 /**
7591  * clutter_actor_get_allocation_geometry:
7592  * @self: A #ClutterActor
7593  * @geom: (out): allocation geometry in pixels
7594  *
7595  * Gets the layout box an actor has been assigned.  The allocation can
7596  * only be assumed valid inside a paint() method; anywhere else, it
7597  * may be out-of-date.
7598  *
7599  * An allocation does not incorporate the actor's scale or anchor point;
7600  * those transformations do not affect layout, only rendering.
7601  *
7602  * The returned rectangle is in pixels.
7603  *
7604  * Since: 0.8
7605  */
7606 void
7607 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7608                                        ClutterGeometry *geom)
7609 {
7610   ClutterActorBox box;
7611
7612   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7613   g_return_if_fail (geom != NULL);
7614
7615   clutter_actor_get_allocation_box (self, &box);
7616
7617   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7618   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7619   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7620   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7621 }
7622
7623 static void
7624 clutter_actor_update_constraints (ClutterActor    *self,
7625                                   ClutterActorBox *allocation)
7626 {
7627   ClutterActorPrivate *priv = self->priv;
7628   const GList *constraints, *l;
7629
7630   if (priv->constraints == NULL)
7631     return;
7632
7633   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7634   for (l = constraints; l != NULL; l = l->next)
7635     {
7636       ClutterConstraint *constraint = l->data;
7637       ClutterActorMeta *meta = l->data;
7638
7639       if (clutter_actor_meta_get_enabled (meta))
7640         {
7641           _clutter_constraint_update_allocation (constraint,
7642                                                  self,
7643                                                  allocation);
7644         }
7645     }
7646 }
7647
7648 /*< private >
7649  * clutter_actor_adjust_allocation:
7650  * @self: a #ClutterActor
7651  * @allocation: (inout): the allocation to adjust
7652  *
7653  * Adjusts the passed allocation box taking into account the actor's
7654  * layout information, like alignment, expansion, and margin.
7655  */
7656 static void
7657 clutter_actor_adjust_allocation (ClutterActor    *self,
7658                                  ClutterActorBox *allocation)
7659 {
7660   ClutterActorBox adj_allocation;
7661   float alloc_width, alloc_height;
7662   float min_width, min_height;
7663   float nat_width, nat_height;
7664   ClutterRequestMode req_mode;
7665
7666   adj_allocation = *allocation;
7667
7668   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7669
7670   /* we want to hit the cache, so we use the public API */
7671   req_mode = clutter_actor_get_request_mode (self);
7672
7673   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7674     {
7675       clutter_actor_get_preferred_width (self, -1,
7676                                          &min_width,
7677                                          &nat_width);
7678       clutter_actor_get_preferred_height (self, alloc_width,
7679                                           &min_height,
7680                                           &nat_height);
7681     }
7682   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7683     {
7684       clutter_actor_get_preferred_height (self, -1,
7685                                           &min_height,
7686                                           &nat_height);
7687       clutter_actor_get_preferred_height (self, alloc_height,
7688                                           &min_width,
7689                                           &nat_width);
7690     }
7691
7692 #ifdef CLUTTER_ENABLE_DEBUG
7693   /* warn about underallocations */
7694   if (_clutter_diagnostic_enabled () &&
7695       (floorf (min_width - alloc_width) > 0 ||
7696        floorf (min_height - alloc_height) > 0))
7697     {
7698       ClutterActor *parent = clutter_actor_get_parent (self);
7699
7700       /* the only actors that are allowed to be underallocated are the Stage,
7701        * as it doesn't have an implicit size, and Actors that specifically
7702        * told us that they want to opt-out from layout control mechanisms
7703        * through the NO_LAYOUT escape hatch.
7704        */
7705       if (parent != NULL &&
7706           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7707         {
7708           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7709                      "of %.2f x %.2f from its parent actor '%s', but its "
7710                      "requested minimum size is of %.2f x %.2f",
7711                      _clutter_actor_get_debug_name (self),
7712                      alloc_width, alloc_height,
7713                      _clutter_actor_get_debug_name (parent),
7714                      min_width, min_height);
7715         }
7716     }
7717 #endif
7718
7719   clutter_actor_adjust_width (self,
7720                               &min_width,
7721                               &nat_width,
7722                               &adj_allocation.x1,
7723                               &adj_allocation.x2);
7724
7725   clutter_actor_adjust_height (self,
7726                                &min_height,
7727                                &nat_height,
7728                                &adj_allocation.y1,
7729                                &adj_allocation.y2);
7730
7731   /* we maintain the invariant that an allocation cannot be adjusted
7732    * to be outside the parent-given box
7733    */
7734   if (adj_allocation.x1 < allocation->x1 ||
7735       adj_allocation.y1 < allocation->y1 ||
7736       adj_allocation.x2 > allocation->x2 ||
7737       adj_allocation.y2 > allocation->y2)
7738     {
7739       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7740                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7741                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7742                  _clutter_actor_get_debug_name (self),
7743                  adj_allocation.x1, adj_allocation.y1,
7744                  adj_allocation.x2 - adj_allocation.x1,
7745                  adj_allocation.y2 - adj_allocation.y1,
7746                  allocation->x1, allocation->y1,
7747                  allocation->x2 - allocation->x1,
7748                  allocation->y2 - allocation->y1);
7749       return;
7750     }
7751
7752   *allocation = adj_allocation;
7753 }
7754
7755 /**
7756  * clutter_actor_allocate:
7757  * @self: A #ClutterActor
7758  * @box: new allocation of the actor, in parent-relative coordinates
7759  * @flags: flags that control the allocation
7760  *
7761  * Called by the parent of an actor to assign the actor its size.
7762  * Should never be called by applications (except when implementing
7763  * a container or layout manager).
7764  *
7765  * Actors can know from their allocation box whether they have moved
7766  * with respect to their parent actor. The @flags parameter describes
7767  * additional information about the allocation, for instance whether
7768  * the parent has moved with respect to the stage, for example because
7769  * a grandparent's origin has moved.
7770  *
7771  * Since: 0.8
7772  */
7773 void
7774 clutter_actor_allocate (ClutterActor           *self,
7775                         const ClutterActorBox  *box,
7776                         ClutterAllocationFlags  flags)
7777 {
7778   ClutterActorPrivate *priv;
7779   ClutterActorClass *klass;
7780   ClutterActorBox old_allocation, real_allocation;
7781   gboolean origin_changed, child_moved, size_changed;
7782   gboolean stage_allocation_changed;
7783
7784   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7785   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
7786     {
7787       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
7788                  "which isn't a descendent of the stage!\n",
7789                  self, _clutter_actor_get_debug_name (self));
7790       return;
7791     }
7792
7793   priv = self->priv;
7794
7795   old_allocation = priv->allocation;
7796   real_allocation = *box;
7797
7798   /* constraints are allowed to modify the allocation only here; we do
7799    * this prior to all the other checks so that we can bail out if the
7800    * allocation did not change
7801    */
7802   clutter_actor_update_constraints (self, &real_allocation);
7803
7804   /* adjust the allocation depending on the align/margin properties */
7805   clutter_actor_adjust_allocation (self, &real_allocation);
7806
7807   if (real_allocation.x2 < real_allocation.x1 ||
7808       real_allocation.y2 < real_allocation.y1)
7809     {
7810       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
7811                  _clutter_actor_get_debug_name (self),
7812                  real_allocation.x2 - real_allocation.x1,
7813                  real_allocation.y2 - real_allocation.y1);
7814     }
7815
7816   /* we allow 0-sized actors, but not negative-sized ones */
7817   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
7818   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
7819
7820   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
7821
7822   child_moved = (real_allocation.x1 != old_allocation.x1 ||
7823                  real_allocation.y1 != old_allocation.y1);
7824
7825   size_changed = (real_allocation.x2 != old_allocation.x2 ||
7826                   real_allocation.y2 != old_allocation.y2);
7827
7828   if (origin_changed || child_moved || size_changed)
7829     stage_allocation_changed = TRUE;
7830   else
7831     stage_allocation_changed = FALSE;
7832
7833   /* If we get an allocation "out of the blue"
7834    * (we did not queue relayout), then we want to
7835    * ignore it. But if we have needs_allocation set,
7836    * we want to guarantee that allocate() virtual
7837    * method is always called, i.e. that queue_relayout()
7838    * always results in an allocate() invocation on
7839    * an actor.
7840    *
7841    * The optimization here is to avoid re-allocating
7842    * actors that did not queue relayout and were
7843    * not moved.
7844    */
7845   if (!priv->needs_allocation && !stage_allocation_changed)
7846     {
7847       CLUTTER_NOTE (LAYOUT, "No allocation needed");
7848       return;
7849     }
7850
7851   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
7852    * clutter_actor_allocate(), it indicates whether the parent has its
7853    * absolute origin moved; when passed in to ClutterActor::allocate()
7854    * virtual method though, it indicates whether the child has its
7855    * absolute origin moved.  So we set it when child_moved is TRUE
7856    */
7857   if (child_moved)
7858     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
7859
7860   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7861
7862   klass = CLUTTER_ACTOR_GET_CLASS (self);
7863   klass->allocate (self, &real_allocation, flags);
7864
7865   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7866
7867   if (stage_allocation_changed)
7868     clutter_actor_queue_redraw (self);
7869 }
7870
7871 /**
7872  * clutter_actor_set_allocation:
7873  * @self: a #ClutterActor
7874  * @box: a #ClutterActorBox
7875  * @flags: allocation flags
7876  *
7877  * Stores the allocation of @self as defined by @box.
7878  *
7879  * This function can only be called from within the implementation of
7880  * the #ClutterActorClass.allocate() virtual function.
7881  *
7882  * The allocation should have been adjusted to take into account constraints,
7883  * alignment, and margin properties. If you are implementing a #ClutterActor
7884  * subclass that provides its own layout management policy for its children
7885  * instead of using a #ClutterLayoutManager delegate, you should not call
7886  * this function on the children of @self; instead, you should call
7887  * clutter_actor_allocate(), which will adjust the allocation box for
7888  * you.
7889  *
7890  * This function should only be used by subclasses of #ClutterActor
7891  * that wish to store their allocation but cannot chain up to the
7892  * parent's implementation; the default implementation of the
7893  * #ClutterActorClass.allocate() virtual function will call this
7894  * function.
7895  *
7896  * It is important to note that, while chaining up was the recommended
7897  * behaviour for #ClutterActor subclasses prior to the introduction of
7898  * this function, it is recommended to call clutter_actor_set_allocation()
7899  * instead.
7900  *
7901  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
7902  * to handle the allocation of its children, this function will call
7903  * the clutter_layout_manager_allocate() function only if the
7904  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
7905  * expected that the subclass will call clutter_layout_manager_allocate()
7906  * by itself. For instance, the following code:
7907  *
7908  * |[
7909  * static void
7910  * my_actor_allocate (ClutterActor *actor,
7911  *                    const ClutterActorBox *allocation,
7912  *                    ClutterAllocationFlags flags)
7913  * {
7914  *   ClutterActorBox new_alloc;
7915  *   ClutterAllocationFlags new_flags;
7916  *
7917  *   adjust_allocation (allocation, &amp;new_alloc);
7918  *
7919  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
7920  *
7921  *   /&ast; this will use the layout manager set on the actor &ast;/
7922  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
7923  * }
7924  * ]|
7925  *
7926  * is equivalent to this:
7927  *
7928  * |[
7929  * static void
7930  * my_actor_allocate (ClutterActor *actor,
7931  *                    const ClutterActorBox *allocation,
7932  *                    ClutterAllocationFlags flags)
7933  * {
7934  *   ClutterLayoutManager *layout;
7935  *   ClutterActorBox new_alloc;
7936  *
7937  *   adjust_allocation (allocation, &amp;new_alloc);
7938  *
7939  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
7940  *
7941  *   layout = clutter_actor_get_layout_manager (actor);
7942  *   clutter_layout_manager_allocate (layout,
7943  *                                    CLUTTER_CONTAINER (actor),
7944  *                                    &amp;new_alloc,
7945  *                                    flags);
7946  * }
7947  * ]|
7948  *
7949  * Since: 1.10
7950  */
7951 void
7952 clutter_actor_set_allocation (ClutterActor           *self,
7953                               const ClutterActorBox  *box,
7954                               ClutterAllocationFlags  flags)
7955 {
7956   ClutterActorPrivate *priv;
7957   gboolean changed;
7958
7959   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7960   g_return_if_fail (box != NULL);
7961
7962   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
7963     {
7964       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
7965                   "can only be called from within the implementation of "
7966                   "the ClutterActor::allocate() virtual function.");
7967       return;
7968     }
7969
7970   priv = self->priv;
7971
7972   g_object_freeze_notify (G_OBJECT (self));
7973
7974   changed = clutter_actor_set_allocation_internal (self, box, flags);
7975
7976   /* we allocate our children before we notify changes in our geometry,
7977    * so that people connecting to properties will be able to get valid
7978    * data out of the sub-tree of the scene graph that has this actor at
7979    * the root.
7980    */
7981   clutter_actor_maybe_layout_children (self, box, flags);
7982
7983   if (changed)
7984     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
7985                    &priv->allocation,
7986                    priv->allocation_flags);
7987
7988   g_object_thaw_notify (G_OBJECT (self));
7989 }
7990
7991 /**
7992  * clutter_actor_set_geometry:
7993  * @self: A #ClutterActor
7994  * @geometry: A #ClutterGeometry
7995  *
7996  * Sets the actor's fixed position and forces its minimum and natural
7997  * size, in pixels. This means the untransformed actor will have the
7998  * given geometry. This is the same as calling clutter_actor_set_position()
7999  * and clutter_actor_set_size().
8000  *
8001  * Deprecated: 1.10: Use clutter_actor_set_position() and
8002  *   clutter_actor_set_size() instead.
8003  */
8004 void
8005 clutter_actor_set_geometry (ClutterActor          *self,
8006                             const ClutterGeometry *geometry)
8007 {
8008   g_object_freeze_notify (G_OBJECT (self));
8009
8010   clutter_actor_set_position (self, geometry->x, geometry->y);
8011   clutter_actor_set_size (self, geometry->width, geometry->height);
8012
8013   g_object_thaw_notify (G_OBJECT (self));
8014 }
8015
8016 /**
8017  * clutter_actor_get_geometry:
8018  * @self: A #ClutterActor
8019  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8020  *
8021  * Gets the size and position of an actor relative to its parent
8022  * actor. This is the same as calling clutter_actor_get_position() and
8023  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8024  * requested size and position if the actor's allocation is invalid.
8025  *
8026  * Deprecated: 1.10: Use clutter_actor_get_position() and
8027  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8028  *   instead.
8029  */
8030 void
8031 clutter_actor_get_geometry (ClutterActor    *self,
8032                             ClutterGeometry *geometry)
8033 {
8034   gfloat x, y, width, height;
8035
8036   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8037   g_return_if_fail (geometry != NULL);
8038
8039   clutter_actor_get_position (self, &x, &y);
8040   clutter_actor_get_size (self, &width, &height);
8041
8042   geometry->x = (int) x;
8043   geometry->y = (int) y;
8044   geometry->width = (int) width;
8045   geometry->height = (int) height;
8046 }
8047
8048 /**
8049  * clutter_actor_set_position:
8050  * @self: A #ClutterActor
8051  * @x: New left position of actor in pixels.
8052  * @y: New top position of actor in pixels.
8053  *
8054  * Sets the actor's fixed position in pixels relative to any parent
8055  * actor.
8056  *
8057  * If a layout manager is in use, this position will override the
8058  * layout manager and force a fixed position.
8059  */
8060 void
8061 clutter_actor_set_position (ClutterActor *self,
8062                             gfloat        x,
8063                             gfloat        y)
8064 {
8065   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8066
8067   g_object_freeze_notify (G_OBJECT (self));
8068
8069   clutter_actor_set_x (self, x);
8070   clutter_actor_set_y (self, y);
8071
8072   g_object_thaw_notify (G_OBJECT (self));
8073 }
8074
8075 /**
8076  * clutter_actor_get_fixed_position_set:
8077  * @self: A #ClutterActor
8078  *
8079  * Checks whether an actor has a fixed position set (and will thus be
8080  * unaffected by any layout manager).
8081  *
8082  * Return value: %TRUE if the fixed position is set on the actor
8083  *
8084  * Since: 0.8
8085  */
8086 gboolean
8087 clutter_actor_get_fixed_position_set (ClutterActor *self)
8088 {
8089   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8090
8091   return self->priv->position_set;
8092 }
8093
8094 /**
8095  * clutter_actor_set_fixed_position_set:
8096  * @self: A #ClutterActor
8097  * @is_set: whether to use fixed position
8098  *
8099  * Sets whether an actor has a fixed position set (and will thus be
8100  * unaffected by any layout manager).
8101  *
8102  * Since: 0.8
8103  */
8104 void
8105 clutter_actor_set_fixed_position_set (ClutterActor *self,
8106                                       gboolean      is_set)
8107 {
8108   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8109
8110   if (self->priv->position_set == (is_set != FALSE))
8111     return;
8112
8113   self->priv->position_set = is_set != FALSE;
8114   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8115
8116   clutter_actor_queue_relayout (self);
8117 }
8118
8119 /**
8120  * clutter_actor_move_by:
8121  * @self: A #ClutterActor
8122  * @dx: Distance to move Actor on X axis.
8123  * @dy: Distance to move Actor on Y axis.
8124  *
8125  * Moves an actor by the specified distance relative to its current
8126  * position in pixels.
8127  *
8128  * This function modifies the fixed position of an actor and thus removes
8129  * it from any layout management. Another way to move an actor is with an
8130  * anchor point, see clutter_actor_set_anchor_point().
8131  *
8132  * Since: 0.2
8133  */
8134 void
8135 clutter_actor_move_by (ClutterActor *self,
8136                        gfloat        dx,
8137                        gfloat        dy)
8138 {
8139   const ClutterLayoutInfo *info;
8140   gfloat x, y;
8141
8142   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8143
8144   info = _clutter_actor_get_layout_info_or_defaults (self);
8145   x = info->fixed_x;
8146   y = info->fixed_y;
8147
8148   clutter_actor_set_position (self, x + dx, y + dy);
8149 }
8150
8151 static void
8152 clutter_actor_set_min_width (ClutterActor *self,
8153                              gfloat        min_width)
8154 {
8155   ClutterActorPrivate *priv = self->priv;
8156   ClutterActorBox old = { 0, };
8157   ClutterLayoutInfo *info;
8158
8159   /* if we are setting the size on a top-level actor and the
8160    * backend only supports static top-levels (e.g. framebuffers)
8161    * then we ignore the passed value and we override it with
8162    * the stage implementation's preferred size.
8163    */
8164   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8165       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8166     return;
8167
8168   info = _clutter_actor_get_layout_info (self);
8169
8170   if (priv->min_width_set && min_width == info->min_width)
8171     return;
8172
8173   g_object_freeze_notify (G_OBJECT (self));
8174
8175   clutter_actor_store_old_geometry (self, &old);
8176
8177   info->min_width = min_width;
8178   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8179   clutter_actor_set_min_width_set (self, TRUE);
8180
8181   clutter_actor_notify_if_geometry_changed (self, &old);
8182
8183   g_object_thaw_notify (G_OBJECT (self));
8184
8185   clutter_actor_queue_relayout (self);
8186 }
8187
8188 static void
8189 clutter_actor_set_min_height (ClutterActor *self,
8190                               gfloat        min_height)
8191
8192 {
8193   ClutterActorPrivate *priv = self->priv;
8194   ClutterActorBox old = { 0, };
8195   ClutterLayoutInfo *info;
8196
8197   /* if we are setting the size on a top-level actor and the
8198    * backend only supports static top-levels (e.g. framebuffers)
8199    * then we ignore the passed value and we override it with
8200    * the stage implementation's preferred size.
8201    */
8202   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8203       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8204     return;
8205
8206   info = _clutter_actor_get_layout_info (self);
8207
8208   if (priv->min_height_set && min_height == info->min_height)
8209     return;
8210
8211   g_object_freeze_notify (G_OBJECT (self));
8212
8213   clutter_actor_store_old_geometry (self, &old);
8214
8215   info->min_height = min_height;
8216   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8217   clutter_actor_set_min_height_set (self, TRUE);
8218
8219   clutter_actor_notify_if_geometry_changed (self, &old);
8220
8221   g_object_thaw_notify (G_OBJECT (self));
8222
8223   clutter_actor_queue_relayout (self);
8224 }
8225
8226 static void
8227 clutter_actor_set_natural_width (ClutterActor *self,
8228                                  gfloat        natural_width)
8229 {
8230   ClutterActorPrivate *priv = self->priv;
8231   ClutterActorBox old = { 0, };
8232   ClutterLayoutInfo *info;
8233
8234   /* if we are setting the size on a top-level actor and the
8235    * backend only supports static top-levels (e.g. framebuffers)
8236    * then we ignore the passed value and we override it with
8237    * the stage implementation's preferred size.
8238    */
8239   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8240       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8241     return;
8242
8243   info = _clutter_actor_get_layout_info (self);
8244
8245   if (priv->natural_width_set && natural_width == info->natural_width)
8246     return;
8247
8248   g_object_freeze_notify (G_OBJECT (self));
8249
8250   clutter_actor_store_old_geometry (self, &old);
8251
8252   info->natural_width = natural_width;
8253   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8254   clutter_actor_set_natural_width_set (self, TRUE);
8255
8256   clutter_actor_notify_if_geometry_changed (self, &old);
8257
8258   g_object_thaw_notify (G_OBJECT (self));
8259
8260   clutter_actor_queue_relayout (self);
8261 }
8262
8263 static void
8264 clutter_actor_set_natural_height (ClutterActor *self,
8265                                   gfloat        natural_height)
8266 {
8267   ClutterActorPrivate *priv = self->priv;
8268   ClutterActorBox old = { 0, };
8269   ClutterLayoutInfo *info;
8270
8271   /* if we are setting the size on a top-level actor and the
8272    * backend only supports static top-levels (e.g. framebuffers)
8273    * then we ignore the passed value and we override it with
8274    * the stage implementation's preferred size.
8275    */
8276   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8277       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8278     return;
8279
8280   info = _clutter_actor_get_layout_info (self);
8281
8282   if (priv->natural_height_set && natural_height == info->natural_height)
8283     return;
8284
8285   g_object_freeze_notify (G_OBJECT (self));
8286
8287   clutter_actor_store_old_geometry (self, &old);
8288
8289   info->natural_height = natural_height;
8290   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8291   clutter_actor_set_natural_height_set (self, TRUE);
8292
8293   clutter_actor_notify_if_geometry_changed (self, &old);
8294
8295   g_object_thaw_notify (G_OBJECT (self));
8296
8297   clutter_actor_queue_relayout (self);
8298 }
8299
8300 static void
8301 clutter_actor_set_min_width_set (ClutterActor *self,
8302                                  gboolean      use_min_width)
8303 {
8304   ClutterActorPrivate *priv = self->priv;
8305   ClutterActorBox old = { 0, };
8306
8307   if (priv->min_width_set == (use_min_width != FALSE))
8308     return;
8309
8310   clutter_actor_store_old_geometry (self, &old);
8311
8312   priv->min_width_set = use_min_width != FALSE;
8313   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8314
8315   clutter_actor_notify_if_geometry_changed (self, &old);
8316
8317   clutter_actor_queue_relayout (self);
8318 }
8319
8320 static void
8321 clutter_actor_set_min_height_set (ClutterActor *self,
8322                                   gboolean      use_min_height)
8323 {
8324   ClutterActorPrivate *priv = self->priv;
8325   ClutterActorBox old = { 0, };
8326
8327   if (priv->min_height_set == (use_min_height != FALSE))
8328     return;
8329
8330   clutter_actor_store_old_geometry (self, &old);
8331
8332   priv->min_height_set = use_min_height != FALSE;
8333   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8334
8335   clutter_actor_notify_if_geometry_changed (self, &old);
8336
8337   clutter_actor_queue_relayout (self);
8338 }
8339
8340 static void
8341 clutter_actor_set_natural_width_set (ClutterActor *self,
8342                                      gboolean      use_natural_width)
8343 {
8344   ClutterActorPrivate *priv = self->priv;
8345   ClutterActorBox old = { 0, };
8346
8347   if (priv->natural_width_set == (use_natural_width != FALSE))
8348     return;
8349
8350   clutter_actor_store_old_geometry (self, &old);
8351
8352   priv->natural_width_set = use_natural_width != FALSE;
8353   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8354
8355   clutter_actor_notify_if_geometry_changed (self, &old);
8356
8357   clutter_actor_queue_relayout (self);
8358 }
8359
8360 static void
8361 clutter_actor_set_natural_height_set (ClutterActor *self,
8362                                       gboolean      use_natural_height)
8363 {
8364   ClutterActorPrivate *priv = self->priv;
8365   ClutterActorBox old = { 0, };
8366
8367   if (priv->natural_height_set == (use_natural_height != FALSE))
8368     return;
8369
8370   clutter_actor_store_old_geometry (self, &old);
8371
8372   priv->natural_height_set = use_natural_height != FALSE;
8373   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8374
8375   clutter_actor_notify_if_geometry_changed (self, &old);
8376
8377   clutter_actor_queue_relayout (self);
8378 }
8379
8380 /**
8381  * clutter_actor_set_request_mode:
8382  * @self: a #ClutterActor
8383  * @mode: the request mode
8384  *
8385  * Sets the geometry request mode of @self.
8386  *
8387  * The @mode determines the order for invoking
8388  * clutter_actor_get_preferred_width() and
8389  * clutter_actor_get_preferred_height()
8390  *
8391  * Since: 1.2
8392  */
8393 void
8394 clutter_actor_set_request_mode (ClutterActor       *self,
8395                                 ClutterRequestMode  mode)
8396 {
8397   ClutterActorPrivate *priv;
8398
8399   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8400
8401   priv = self->priv;
8402
8403   if (priv->request_mode == mode)
8404     return;
8405
8406   priv->request_mode = mode;
8407
8408   priv->needs_width_request = TRUE;
8409   priv->needs_height_request = TRUE;
8410
8411   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8412
8413   clutter_actor_queue_relayout (self);
8414 }
8415
8416 /**
8417  * clutter_actor_get_request_mode:
8418  * @self: a #ClutterActor
8419  *
8420  * Retrieves the geometry request mode of @self
8421  *
8422  * Return value: the request mode for the actor
8423  *
8424  * Since: 1.2
8425  */
8426 ClutterRequestMode
8427 clutter_actor_get_request_mode (ClutterActor *self)
8428 {
8429   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8430                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8431
8432   return self->priv->request_mode;
8433 }
8434
8435 /* variant of set_width() without checks and without notification
8436  * freeze+thaw, for internal usage only
8437  */
8438 static inline void
8439 clutter_actor_set_width_internal (ClutterActor *self,
8440                                   gfloat        width)
8441 {
8442   if (width >= 0)
8443     {
8444       /* the Stage will use the :min-width to control the minimum
8445        * width to be resized to, so we should not be setting it
8446        * along with the :natural-width
8447        */
8448       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8449         clutter_actor_set_min_width (self, width);
8450
8451       clutter_actor_set_natural_width (self, width);
8452     }
8453   else
8454     {
8455       /* we only unset the :natural-width for the Stage */
8456       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8457         clutter_actor_set_min_width_set (self, FALSE);
8458
8459       clutter_actor_set_natural_width_set (self, FALSE);
8460     }
8461 }
8462
8463 /* variant of set_height() without checks and without notification
8464  * freeze+thaw, for internal usage only
8465  */
8466 static inline void
8467 clutter_actor_set_height_internal (ClutterActor *self,
8468                                    gfloat        height)
8469 {
8470   if (height >= 0)
8471     {
8472       /* see the comment above in set_width_internal() */
8473       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8474         clutter_actor_set_min_height (self, height);
8475
8476       clutter_actor_set_natural_height (self, height);
8477     }
8478   else
8479     {
8480       /* see the comment above in set_width_internal() */
8481       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8482         clutter_actor_set_min_height_set (self, FALSE);
8483
8484       clutter_actor_set_natural_height_set (self, FALSE);
8485     }
8486 }
8487
8488 /**
8489  * clutter_actor_set_size:
8490  * @self: A #ClutterActor
8491  * @width: New width of actor in pixels, or -1
8492  * @height: New height of actor in pixels, or -1
8493  *
8494  * Sets the actor's size request in pixels. This overrides any
8495  * "normal" size request the actor would have. For example
8496  * a text actor might normally request the size of the text;
8497  * this function would force a specific size instead.
8498  *
8499  * If @width and/or @height are -1 the actor will use its
8500  * "normal" size request instead of overriding it, i.e.
8501  * you can "unset" the size with -1.
8502  *
8503  * This function sets or unsets both the minimum and natural size.
8504  */
8505 void
8506 clutter_actor_set_size (ClutterActor *self,
8507                         gfloat        width,
8508                         gfloat        height)
8509 {
8510   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8511
8512   g_object_freeze_notify (G_OBJECT (self));
8513
8514   clutter_actor_set_width_internal (self, width);
8515   clutter_actor_set_height_internal (self, height);
8516
8517   g_object_thaw_notify (G_OBJECT (self));
8518 }
8519
8520 /**
8521  * clutter_actor_get_size:
8522  * @self: A #ClutterActor
8523  * @width: (out) (allow-none): return location for the width, or %NULL.
8524  * @height: (out) (allow-none): return location for the height, or %NULL.
8525  *
8526  * This function tries to "do what you mean" and return
8527  * the size an actor will have. If the actor has a valid
8528  * allocation, the allocation will be returned; otherwise,
8529  * the actors natural size request will be returned.
8530  *
8531  * If you care whether you get the request vs. the allocation, you
8532  * should probably call a different function like
8533  * clutter_actor_get_allocation_box() or
8534  * clutter_actor_get_preferred_width().
8535  *
8536  * Since: 0.2
8537  */
8538 void
8539 clutter_actor_get_size (ClutterActor *self,
8540                         gfloat       *width,
8541                         gfloat       *height)
8542 {
8543   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8544
8545   if (width)
8546     *width = clutter_actor_get_width (self);
8547
8548   if (height)
8549     *height = clutter_actor_get_height (self);
8550 }
8551
8552 /**
8553  * clutter_actor_get_position:
8554  * @self: a #ClutterActor
8555  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8556  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8557  *
8558  * This function tries to "do what you mean" and tell you where the
8559  * actor is, prior to any transformations. Retrieves the fixed
8560  * position of an actor in pixels, if one has been set; otherwise, if
8561  * the allocation is valid, returns the actor's allocated position;
8562  * otherwise, returns 0,0.
8563  *
8564  * The returned position is in pixels.
8565  *
8566  * Since: 0.6
8567  */
8568 void
8569 clutter_actor_get_position (ClutterActor *self,
8570                             gfloat       *x,
8571                             gfloat       *y)
8572 {
8573   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8574
8575   if (x)
8576     *x = clutter_actor_get_x (self);
8577
8578   if (y)
8579     *y = clutter_actor_get_y (self);
8580 }
8581
8582 /**
8583  * clutter_actor_get_transformed_position:
8584  * @self: A #ClutterActor
8585  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8586  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8587  *
8588  * Gets the absolute position of an actor, in pixels relative to the stage.
8589  *
8590  * Since: 0.8
8591  */
8592 void
8593 clutter_actor_get_transformed_position (ClutterActor *self,
8594                                         gfloat       *x,
8595                                         gfloat       *y)
8596 {
8597   ClutterVertex v1;
8598   ClutterVertex v2;
8599
8600   v1.x = v1.y = v1.z = 0;
8601   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8602
8603   if (x)
8604     *x = v2.x;
8605
8606   if (y)
8607     *y = v2.y;
8608 }
8609
8610 /**
8611  * clutter_actor_get_transformed_size:
8612  * @self: A #ClutterActor
8613  * @width: (out) (allow-none): return location for the width, or %NULL
8614  * @height: (out) (allow-none): return location for the height, or %NULL
8615  *
8616  * Gets the absolute size of an actor in pixels, taking into account the
8617  * scaling factors.
8618  *
8619  * If the actor has a valid allocation, the allocated size will be used.
8620  * If the actor has not a valid allocation then the preferred size will
8621  * be transformed and returned.
8622  *
8623  * If you want the transformed allocation, see
8624  * clutter_actor_get_abs_allocation_vertices() instead.
8625  *
8626  * <note>When the actor (or one of its ancestors) is rotated around the
8627  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8628  * as a generic quadrangle; in that case this function returns the size
8629  * of the smallest rectangle that encapsulates the entire quad. Please
8630  * note that in this case no assumptions can be made about the relative
8631  * position of this envelope to the absolute position of the actor, as
8632  * returned by clutter_actor_get_transformed_position(); if you need this
8633  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8634  * to get the coords of the actual quadrangle.</note>
8635  *
8636  * Since: 0.8
8637  */
8638 void
8639 clutter_actor_get_transformed_size (ClutterActor *self,
8640                                     gfloat       *width,
8641                                     gfloat       *height)
8642 {
8643   ClutterActorPrivate *priv;
8644   ClutterVertex v[4];
8645   gfloat x_min, x_max, y_min, y_max;
8646   gint i;
8647
8648   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8649
8650   priv = self->priv;
8651
8652   /* if the actor hasn't been allocated yet, get the preferred
8653    * size and transform that
8654    */
8655   if (priv->needs_allocation)
8656     {
8657       gfloat natural_width, natural_height;
8658       ClutterActorBox box;
8659
8660       /* Make a fake allocation to transform.
8661        *
8662        * NB: _clutter_actor_transform_and_project_box expects a box in
8663        * the actor's coordinate space... */
8664
8665       box.x1 = 0;
8666       box.y1 = 0;
8667
8668       natural_width = natural_height = 0;
8669       clutter_actor_get_preferred_size (self, NULL, NULL,
8670                                         &natural_width,
8671                                         &natural_height);
8672
8673       box.x2 = natural_width;
8674       box.y2 = natural_height;
8675
8676       _clutter_actor_transform_and_project_box (self, &box, v);
8677     }
8678   else
8679     clutter_actor_get_abs_allocation_vertices (self, v);
8680
8681   x_min = x_max = v[0].x;
8682   y_min = y_max = v[0].y;
8683
8684   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8685     {
8686       if (v[i].x < x_min)
8687         x_min = v[i].x;
8688
8689       if (v[i].x > x_max)
8690         x_max = v[i].x;
8691
8692       if (v[i].y < y_min)
8693         y_min = v[i].y;
8694
8695       if (v[i].y > y_max)
8696         y_max = v[i].y;
8697     }
8698
8699   if (width)
8700     *width  = x_max - x_min;
8701
8702   if (height)
8703     *height = y_max - y_min;
8704 }
8705
8706 /**
8707  * clutter_actor_get_width:
8708  * @self: A #ClutterActor
8709  *
8710  * Retrieves the width of a #ClutterActor.
8711  *
8712  * If the actor has a valid allocation, this function will return the
8713  * width of the allocated area given to the actor.
8714  *
8715  * If the actor does not have a valid allocation, this function will
8716  * return the actor's natural width, that is the preferred width of
8717  * the actor.
8718  *
8719  * If you care whether you get the preferred width or the width that
8720  * has been assigned to the actor, you should probably call a different
8721  * function like clutter_actor_get_allocation_box() to retrieve the
8722  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8723  * preferred width.
8724  *
8725  * If an actor has a fixed width, for instance a width that has been
8726  * assigned using clutter_actor_set_width(), the width returned will
8727  * be the same value.
8728  *
8729  * Return value: the width of the actor, in pixels
8730  */
8731 gfloat
8732 clutter_actor_get_width (ClutterActor *self)
8733 {
8734   ClutterActorPrivate *priv;
8735
8736   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8737
8738   priv = self->priv;
8739
8740   if (priv->needs_allocation)
8741     {
8742       gfloat natural_width = 0;
8743
8744       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8745         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8746       else
8747         {
8748           gfloat natural_height = 0;
8749
8750           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8751           clutter_actor_get_preferred_width (self, natural_height,
8752                                              NULL,
8753                                              &natural_width);
8754         }
8755
8756       return natural_width;
8757     }
8758   else
8759     return priv->allocation.x2 - priv->allocation.x1;
8760 }
8761
8762 /**
8763  * clutter_actor_get_height:
8764  * @self: A #ClutterActor
8765  *
8766  * Retrieves the height of a #ClutterActor.
8767  *
8768  * If the actor has a valid allocation, this function will return the
8769  * height of the allocated area given to the actor.
8770  *
8771  * If the actor does not have a valid allocation, this function will
8772  * return the actor's natural height, that is the preferred height of
8773  * the actor.
8774  *
8775  * If you care whether you get the preferred height or the height that
8776  * has been assigned to the actor, you should probably call a different
8777  * function like clutter_actor_get_allocation_box() to retrieve the
8778  * allocated size or clutter_actor_get_preferred_height() to retrieve the
8779  * preferred height.
8780  *
8781  * If an actor has a fixed height, for instance a height that has been
8782  * assigned using clutter_actor_set_height(), the height returned will
8783  * be the same value.
8784  *
8785  * Return value: the height of the actor, in pixels
8786  */
8787 gfloat
8788 clutter_actor_get_height (ClutterActor *self)
8789 {
8790   ClutterActorPrivate *priv;
8791
8792   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8793
8794   priv = self->priv;
8795
8796   if (priv->needs_allocation)
8797     {
8798       gfloat natural_height = 0;
8799
8800       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8801         {
8802           gfloat natural_width = 0;
8803
8804           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8805           clutter_actor_get_preferred_height (self, natural_width,
8806                                               NULL, &natural_height);
8807         }
8808       else
8809         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8810
8811       return natural_height;
8812     }
8813   else
8814     return priv->allocation.y2 - priv->allocation.y1;
8815 }
8816
8817 /**
8818  * clutter_actor_set_width:
8819  * @self: A #ClutterActor
8820  * @width: Requested new width for the actor, in pixels, or -1
8821  *
8822  * Forces a width on an actor, causing the actor's preferred width
8823  * and height (if any) to be ignored.
8824  *
8825  * If @width is -1 the actor will use its preferred width request
8826  * instead of overriding it, i.e. you can "unset" the width with -1.
8827  *
8828  * This function sets both the minimum and natural size of the actor.
8829  *
8830  * since: 0.2
8831  */
8832 void
8833 clutter_actor_set_width (ClutterActor *self,
8834                          gfloat        width)
8835 {
8836   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8837
8838   g_object_freeze_notify (G_OBJECT (self));
8839
8840   clutter_actor_set_width_internal (self, width);
8841
8842   g_object_thaw_notify (G_OBJECT (self));
8843 }
8844
8845 /**
8846  * clutter_actor_set_height:
8847  * @self: A #ClutterActor
8848  * @height: Requested new height for the actor, in pixels, or -1
8849  *
8850  * Forces a height on an actor, causing the actor's preferred width
8851  * and height (if any) to be ignored.
8852  *
8853  * If @height is -1 the actor will use its preferred height instead of
8854  * overriding it, i.e. you can "unset" the height with -1.
8855  *
8856  * This function sets both the minimum and natural size of the actor.
8857  *
8858  * since: 0.2
8859  */
8860 void
8861 clutter_actor_set_height (ClutterActor *self,
8862                           gfloat        height)
8863 {
8864   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8865
8866   g_object_freeze_notify (G_OBJECT (self));
8867
8868   clutter_actor_set_height_internal (self, height);
8869
8870   g_object_thaw_notify (G_OBJECT (self));
8871 }
8872
8873 /**
8874  * clutter_actor_set_x:
8875  * @self: a #ClutterActor
8876  * @x: the actor's position on the X axis
8877  *
8878  * Sets the actor's X coordinate, relative to its parent, in pixels.
8879  *
8880  * Overrides any layout manager and forces a fixed position for
8881  * the actor.
8882  *
8883  * Since: 0.6
8884  */
8885 void
8886 clutter_actor_set_x (ClutterActor *self,
8887                      gfloat        x)
8888 {
8889   ClutterActorBox old = { 0, };
8890   ClutterActorPrivate *priv;
8891   ClutterLayoutInfo *info;
8892
8893   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8894
8895   priv = self->priv;
8896
8897   info = _clutter_actor_get_layout_info (self);
8898
8899   if (priv->position_set && info->fixed_x == x)
8900     return;
8901
8902   clutter_actor_store_old_geometry (self, &old);
8903
8904   info->fixed_x = x;
8905   clutter_actor_set_fixed_position_set (self, TRUE);
8906
8907   clutter_actor_notify_if_geometry_changed (self, &old);
8908
8909   clutter_actor_queue_relayout (self);
8910 }
8911
8912 /**
8913  * clutter_actor_set_y:
8914  * @self: a #ClutterActor
8915  * @y: the actor's position on the Y axis
8916  *
8917  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
8918  *
8919  * Overrides any layout manager and forces a fixed position for
8920  * the actor.
8921  *
8922  * Since: 0.6
8923  */
8924 void
8925 clutter_actor_set_y (ClutterActor *self,
8926                      gfloat        y)
8927 {
8928   ClutterActorBox old = { 0, };
8929   ClutterActorPrivate *priv;
8930   ClutterLayoutInfo *info;
8931
8932   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8933
8934   priv = self->priv;
8935
8936   info = _clutter_actor_get_layout_info (self);
8937
8938   if (priv->position_set && info->fixed_y == y)
8939     return;
8940
8941   clutter_actor_store_old_geometry (self, &old);
8942
8943   info->fixed_y = y;
8944   clutter_actor_set_fixed_position_set (self, TRUE);
8945
8946   clutter_actor_notify_if_geometry_changed (self, &old);
8947
8948   clutter_actor_queue_relayout (self);
8949 }
8950
8951 /**
8952  * clutter_actor_get_x:
8953  * @self: A #ClutterActor
8954  *
8955  * Retrieves the X coordinate of a #ClutterActor.
8956  *
8957  * This function tries to "do what you mean", by returning the
8958  * correct value depending on the actor's state.
8959  *
8960  * If the actor has a valid allocation, this function will return
8961  * the X coordinate of the origin of the allocation box.
8962  *
8963  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
8964  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8965  * function will return that coordinate.
8966  *
8967  * If both the allocation and a fixed position are missing, this function
8968  * will return 0.
8969  *
8970  * Return value: the X coordinate, in pixels, ignoring any
8971  *   transformation (i.e. scaling, rotation)
8972  */
8973 gfloat
8974 clutter_actor_get_x (ClutterActor *self)
8975 {
8976   ClutterActorPrivate *priv;
8977
8978   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8979
8980   priv = self->priv;
8981
8982   if (priv->needs_allocation)
8983     {
8984       if (priv->position_set)
8985         {
8986           const ClutterLayoutInfo *info;
8987
8988           info = _clutter_actor_get_layout_info_or_defaults (self);
8989
8990           return info->fixed_x;
8991         }
8992       else
8993         return 0;
8994     }
8995   else
8996     return priv->allocation.x1;
8997 }
8998
8999 /**
9000  * clutter_actor_get_y:
9001  * @self: A #ClutterActor
9002  *
9003  * Retrieves the Y coordinate of a #ClutterActor.
9004  *
9005  * This function tries to "do what you mean", by returning the
9006  * correct value depending on the actor's state.
9007  *
9008  * If the actor has a valid allocation, this function will return
9009  * the Y coordinate of the origin of the allocation box.
9010  *
9011  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9012  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9013  * function will return that coordinate.
9014  *
9015  * If both the allocation and a fixed position are missing, this function
9016  * will return 0.
9017  *
9018  * Return value: the Y coordinate, in pixels, ignoring any
9019  *   transformation (i.e. scaling, rotation)
9020  */
9021 gfloat
9022 clutter_actor_get_y (ClutterActor *self)
9023 {
9024   ClutterActorPrivate *priv;
9025
9026   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9027
9028   priv = self->priv;
9029
9030   if (priv->needs_allocation)
9031     {
9032       if (priv->position_set)
9033         {
9034           const ClutterLayoutInfo *info;
9035
9036           info = _clutter_actor_get_layout_info_or_defaults (self);
9037
9038           return info->fixed_y;
9039         }
9040       else
9041         return 0;
9042     }
9043   else
9044     return priv->allocation.y1;
9045 }
9046
9047 /**
9048  * clutter_actor_set_scale:
9049  * @self: A #ClutterActor
9050  * @scale_x: double factor to scale actor by horizontally.
9051  * @scale_y: double factor to scale actor by vertically.
9052  *
9053  * Scales an actor with the given factors. The scaling is relative to
9054  * the scale center and the anchor point. The scale center is
9055  * unchanged by this function and defaults to 0,0.
9056  *
9057  * Since: 0.2
9058  */
9059 void
9060 clutter_actor_set_scale (ClutterActor *self,
9061                          gdouble       scale_x,
9062                          gdouble       scale_y)
9063 {
9064   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9065
9066   g_object_freeze_notify (G_OBJECT (self));
9067
9068   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9069   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9070
9071   g_object_thaw_notify (G_OBJECT (self));
9072 }
9073
9074 /**
9075  * clutter_actor_set_scale_full:
9076  * @self: A #ClutterActor
9077  * @scale_x: double factor to scale actor by horizontally.
9078  * @scale_y: double factor to scale actor by vertically.
9079  * @center_x: X coordinate of the center of the scale.
9080  * @center_y: Y coordinate of the center of the scale
9081  *
9082  * Scales an actor with the given factors around the given center
9083  * point. The center point is specified in pixels relative to the
9084  * anchor point (usually the top left corner of the actor).
9085  *
9086  * Since: 1.0
9087  */
9088 void
9089 clutter_actor_set_scale_full (ClutterActor *self,
9090                               gdouble       scale_x,
9091                               gdouble       scale_y,
9092                               gfloat        center_x,
9093                               gfloat        center_y)
9094 {
9095   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9096
9097   g_object_freeze_notify (G_OBJECT (self));
9098
9099   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9100   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9101   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9102   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9103
9104   g_object_thaw_notify (G_OBJECT (self));
9105 }
9106
9107 /**
9108  * clutter_actor_set_scale_with_gravity:
9109  * @self: A #ClutterActor
9110  * @scale_x: double factor to scale actor by horizontally.
9111  * @scale_y: double factor to scale actor by vertically.
9112  * @gravity: the location of the scale center expressed as a compass
9113  * direction.
9114  *
9115  * Scales an actor with the given factors around the given
9116  * center point. The center point is specified as one of the compass
9117  * directions in #ClutterGravity. For example, setting it to north
9118  * will cause the top of the actor to remain unchanged and the rest of
9119  * the actor to expand left, right and downwards.
9120  *
9121  * Since: 1.0
9122  */
9123 void
9124 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9125                                       gdouble         scale_x,
9126                                       gdouble         scale_y,
9127                                       ClutterGravity  gravity)
9128 {
9129   ClutterTransformInfo *info;
9130   GObject *obj;
9131
9132   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9133
9134   obj = G_OBJECT (self);
9135
9136   g_object_freeze_notify (obj);
9137
9138   info = _clutter_actor_get_transform_info (self);
9139   info->scale_x = scale_x;
9140   info->scale_y = scale_y;
9141
9142   if (gravity == CLUTTER_GRAVITY_NONE)
9143     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9144   else
9145     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9146
9147   self->priv->transform_valid = FALSE;
9148
9149   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9150   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9151   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9152   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9153   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9154
9155   clutter_actor_queue_redraw (self);
9156
9157   g_object_thaw_notify (obj);
9158 }
9159
9160 /**
9161  * clutter_actor_get_scale:
9162  * @self: A #ClutterActor
9163  * @scale_x: (out) (allow-none): Location to store horizonal
9164  *   scale factor, or %NULL.
9165  * @scale_y: (out) (allow-none): Location to store vertical
9166  *   scale factor, or %NULL.
9167  *
9168  * Retrieves an actors scale factors.
9169  *
9170  * Since: 0.2
9171  */
9172 void
9173 clutter_actor_get_scale (ClutterActor *self,
9174                          gdouble      *scale_x,
9175                          gdouble      *scale_y)
9176 {
9177   const ClutterTransformInfo *info;
9178
9179   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9180
9181   info = _clutter_actor_get_transform_info_or_defaults (self);
9182
9183   if (scale_x)
9184     *scale_x = info->scale_x;
9185
9186   if (scale_y)
9187     *scale_y = info->scale_y;
9188 }
9189
9190 /**
9191  * clutter_actor_get_scale_center:
9192  * @self: A #ClutterActor
9193  * @center_x: (out) (allow-none): Location to store the X position
9194  *   of the scale center, or %NULL.
9195  * @center_y: (out) (allow-none): Location to store the Y position
9196  *   of the scale center, or %NULL.
9197  *
9198  * Retrieves the scale center coordinate in pixels relative to the top
9199  * left corner of the actor. If the scale center was specified using a
9200  * #ClutterGravity this will calculate the pixel offset using the
9201  * current size of the actor.
9202  *
9203  * Since: 1.0
9204  */
9205 void
9206 clutter_actor_get_scale_center (ClutterActor *self,
9207                                 gfloat       *center_x,
9208                                 gfloat       *center_y)
9209 {
9210   const ClutterTransformInfo *info;
9211
9212   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9213
9214   info = _clutter_actor_get_transform_info_or_defaults (self);
9215
9216   clutter_anchor_coord_get_units (self, &info->scale_center,
9217                                   center_x,
9218                                   center_y,
9219                                   NULL);
9220 }
9221
9222 /**
9223  * clutter_actor_get_scale_gravity:
9224  * @self: A #ClutterActor
9225  *
9226  * Retrieves the scale center as a compass direction. If the scale
9227  * center was specified in pixels or units this will return
9228  * %CLUTTER_GRAVITY_NONE.
9229  *
9230  * Return value: the scale gravity
9231  *
9232  * Since: 1.0
9233  */
9234 ClutterGravity
9235 clutter_actor_get_scale_gravity (ClutterActor *self)
9236 {
9237   const ClutterTransformInfo *info;
9238
9239   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9240
9241   info = _clutter_actor_get_transform_info_or_defaults (self);
9242
9243   return clutter_anchor_coord_get_gravity (&info->scale_center);
9244 }
9245
9246 /**
9247  * clutter_actor_set_opacity:
9248  * @self: A #ClutterActor
9249  * @opacity: New opacity value for the actor.
9250  *
9251  * Sets the actor's opacity, with zero being completely transparent and
9252  * 255 (0xff) being fully opaque.
9253  */
9254 void
9255 clutter_actor_set_opacity (ClutterActor *self,
9256                            guint8        opacity)
9257 {
9258   ClutterActorPrivate *priv;
9259
9260   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9261
9262   priv = self->priv;
9263
9264   if (priv->opacity != opacity)
9265     {
9266       priv->opacity = opacity;
9267
9268       /* Queue a redraw from the flatten effect so that it can use
9269          its cached image if available instead of having to redraw the
9270          actual actor. If it doesn't end up using the FBO then the
9271          effect is still able to continue the paint anyway. If there
9272          is no flatten effect yet then this is equivalent to queueing
9273          a full redraw */
9274       _clutter_actor_queue_redraw_full (self,
9275                                         0, /* flags */
9276                                         NULL, /* clip */
9277                                         priv->flatten_effect);
9278
9279       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9280     }
9281 }
9282
9283 /*
9284  * clutter_actor_get_paint_opacity_internal:
9285  * @self: a #ClutterActor
9286  *
9287  * Retrieves the absolute opacity of the actor, as it appears on the stage
9288  *
9289  * This function does not do type checks
9290  *
9291  * Return value: the absolute opacity of the actor
9292  */
9293 static guint8
9294 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9295 {
9296   ClutterActorPrivate *priv = self->priv;
9297   ClutterActor *parent;
9298
9299   /* override the top-level opacity to always be 255; even in
9300    * case of ClutterStage:use-alpha being TRUE we want the rest
9301    * of the scene to be painted
9302    */
9303   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9304     return 255;
9305
9306   if (priv->opacity_override >= 0)
9307     return priv->opacity_override;
9308
9309   parent = priv->parent;
9310
9311   /* Factor in the actual actors opacity with parents */
9312   if (parent != NULL)
9313     {
9314       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9315
9316       if (opacity != 0xff)
9317         return (opacity * priv->opacity) / 0xff;
9318     }
9319
9320   return priv->opacity;
9321
9322 }
9323
9324 /**
9325  * clutter_actor_get_paint_opacity:
9326  * @self: A #ClutterActor
9327  *
9328  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9329  *
9330  * This function traverses the hierarchy chain and composites the opacity of
9331  * the actor with that of its parents.
9332  *
9333  * This function is intended for subclasses to use in the paint virtual
9334  * function, to paint themselves with the correct opacity.
9335  *
9336  * Return value: The actor opacity value.
9337  *
9338  * Since: 0.8
9339  */
9340 guint8
9341 clutter_actor_get_paint_opacity (ClutterActor *self)
9342 {
9343   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9344
9345   return clutter_actor_get_paint_opacity_internal (self);
9346 }
9347
9348 /**
9349  * clutter_actor_get_opacity:
9350  * @self: a #ClutterActor
9351  *
9352  * Retrieves the opacity value of an actor, as set by
9353  * clutter_actor_set_opacity().
9354  *
9355  * For retrieving the absolute opacity of the actor inside a paint
9356  * virtual function, see clutter_actor_get_paint_opacity().
9357  *
9358  * Return value: the opacity of the actor
9359  */
9360 guint8
9361 clutter_actor_get_opacity (ClutterActor *self)
9362 {
9363   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9364
9365   return self->priv->opacity;
9366 }
9367
9368 /**
9369  * clutter_actor_set_offscreen_redirect:
9370  * @self: A #ClutterActor
9371  * @redirect: New offscreen redirect flags for the actor.
9372  *
9373  * Defines the circumstances where the actor should be redirected into
9374  * an offscreen image. The offscreen image is used to flatten the
9375  * actor into a single image while painting for two main reasons.
9376  * Firstly, when the actor is painted a second time without any of its
9377  * contents changing it can simply repaint the cached image without
9378  * descending further down the actor hierarchy. Secondly, it will make
9379  * the opacity look correct even if there are overlapping primitives
9380  * in the actor.
9381  *
9382  * Caching the actor could in some cases be a performance win and in
9383  * some cases be a performance lose so it is important to determine
9384  * which value is right for an actor before modifying this value. For
9385  * example, there is never any reason to flatten an actor that is just
9386  * a single texture (such as a #ClutterTexture) because it is
9387  * effectively already cached in an image so the offscreen would be
9388  * redundant. Also if the actor contains primitives that are far apart
9389  * with a large transparent area in the middle (such as a large
9390  * CluterGroup with a small actor in the top left and a small actor in
9391  * the bottom right) then the cached image will contain the entire
9392  * image of the large area and the paint will waste time blending all
9393  * of the transparent pixels in the middle.
9394  *
9395  * The default method of implementing opacity on a container simply
9396  * forwards on the opacity to all of the children. If the children are
9397  * overlapping then it will appear as if they are two separate glassy
9398  * objects and there will be a break in the color where they
9399  * overlap. By redirecting to an offscreen buffer it will be as if the
9400  * two opaque objects are combined into one and then made transparent
9401  * which is usually what is expected.
9402  *
9403  * The image below demonstrates the difference between redirecting and
9404  * not. The image shows two Clutter groups, each containing a red and
9405  * a green rectangle which overlap. The opacity on the group is set to
9406  * 128 (which is 50%). When the offscreen redirect is not used, the
9407  * red rectangle can be seen through the blue rectangle as if the two
9408  * rectangles were separately transparent. When the redirect is used
9409  * the group as a whole is transparent instead so the red rectangle is
9410  * not visible where they overlap.
9411  *
9412  * <figure id="offscreen-redirect">
9413  *   <title>Sample of using an offscreen redirect for transparency</title>
9414  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9415  * </figure>
9416  *
9417  * The default value for this property is 0, so we effectively will
9418  * never redirect an actor offscreen by default. This means that there
9419  * are times that transparent actors may look glassy as described
9420  * above. The reason this is the default is because there is a
9421  * performance trade off between quality and performance here. In many
9422  * cases the default form of glassy opacity looks good enough, but if
9423  * it's not you will need to set the
9424  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9425  * redirection for opacity.
9426  *
9427  * Custom actors that don't contain any overlapping primitives are
9428  * recommended to override the has_overlaps() virtual to return %FALSE
9429  * for maximum efficiency.
9430  *
9431  * Since: 1.8
9432  */
9433 void
9434 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9435                                       ClutterOffscreenRedirect redirect)
9436 {
9437   ClutterActorPrivate *priv;
9438
9439   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9440
9441   priv = self->priv;
9442
9443   if (priv->offscreen_redirect != redirect)
9444     {
9445       priv->offscreen_redirect = redirect;
9446
9447       /* Queue a redraw from the effect so that it can use its cached
9448          image if available instead of having to redraw the actual
9449          actor. If it doesn't end up using the FBO then the effect is
9450          still able to continue the paint anyway. If there is no
9451          effect then this is equivalent to queuing a full redraw */
9452       _clutter_actor_queue_redraw_full (self,
9453                                         0, /* flags */
9454                                         NULL, /* clip */
9455                                         priv->flatten_effect);
9456
9457       g_object_notify_by_pspec (G_OBJECT (self),
9458                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9459     }
9460 }
9461
9462 /**
9463  * clutter_actor_get_offscreen_redirect:
9464  * @self: a #ClutterActor
9465  *
9466  * Retrieves whether to redirect the actor to an offscreen buffer, as
9467  * set by clutter_actor_set_offscreen_redirect().
9468  *
9469  * Return value: the value of the offscreen-redirect property of the actor
9470  *
9471  * Since: 1.8
9472  */
9473 ClutterOffscreenRedirect
9474 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9475 {
9476   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9477
9478   return self->priv->offscreen_redirect;
9479 }
9480
9481 /**
9482  * clutter_actor_set_name:
9483  * @self: A #ClutterActor
9484  * @name: Textual tag to apply to actor
9485  *
9486  * Sets the given name to @self. The name can be used to identify
9487  * a #ClutterActor.
9488  */
9489 void
9490 clutter_actor_set_name (ClutterActor *self,
9491                         const gchar  *name)
9492 {
9493   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9494
9495   g_free (self->priv->name);
9496   self->priv->name = g_strdup (name);
9497
9498   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9499 }
9500
9501 /**
9502  * clutter_actor_get_name:
9503  * @self: A #ClutterActor
9504  *
9505  * Retrieves the name of @self.
9506  *
9507  * Return value: the name of the actor, or %NULL. The returned string is
9508  *   owned by the actor and should not be modified or freed.
9509  */
9510 const gchar *
9511 clutter_actor_get_name (ClutterActor *self)
9512 {
9513   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9514
9515   return self->priv->name;
9516 }
9517
9518 /**
9519  * clutter_actor_get_gid:
9520  * @self: A #ClutterActor
9521  *
9522  * Retrieves the unique id for @self.
9523  *
9524  * Return value: Globally unique value for this object instance.
9525  *
9526  * Since: 0.6
9527  *
9528  * Deprecated: 1.8: The id is not used any longer.
9529  */
9530 guint32
9531 clutter_actor_get_gid (ClutterActor *self)
9532 {
9533   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9534
9535   return self->priv->id;
9536 }
9537
9538 /**
9539  * clutter_actor_set_depth:
9540  * @self: a #ClutterActor
9541  * @depth: Z co-ord
9542  *
9543  * Sets the Z coordinate of @self to @depth.
9544  *
9545  * The unit used by @depth is dependant on the perspective setup. See
9546  * also clutter_stage_set_perspective().
9547  */
9548 void
9549 clutter_actor_set_depth (ClutterActor *self,
9550                          gfloat        depth)
9551 {
9552   ClutterActorPrivate *priv;
9553
9554   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9555
9556   priv = self->priv;
9557
9558   if (priv->z != depth)
9559     {
9560       /* Sets Z value - XXX 2.0: should we invert? */
9561       priv->z = depth;
9562
9563       priv->transform_valid = FALSE;
9564
9565       /* FIXME - remove this crap; sadly, there are still containers
9566        * in Clutter that depend on this utter brain damage
9567        */
9568       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9569
9570       clutter_actor_queue_redraw (self);
9571
9572       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9573     }
9574 }
9575
9576 /**
9577  * clutter_actor_get_depth:
9578  * @self: a #ClutterActor
9579  *
9580  * Retrieves the depth of @self.
9581  *
9582  * Return value: the depth of the actor
9583  */
9584 gfloat
9585 clutter_actor_get_depth (ClutterActor *self)
9586 {
9587   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
9588
9589   return self->priv->z;
9590 }
9591
9592 /**
9593  * clutter_actor_set_rotation:
9594  * @self: a #ClutterActor
9595  * @axis: the axis of rotation
9596  * @angle: the angle of rotation
9597  * @x: X coordinate of the rotation center
9598  * @y: Y coordinate of the rotation center
9599  * @z: Z coordinate of the rotation center
9600  *
9601  * Sets the rotation angle of @self around the given axis.
9602  *
9603  * The rotation center coordinates used depend on the value of @axis:
9604  * <itemizedlist>
9605  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
9606  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
9607  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
9608  * </itemizedlist>
9609  *
9610  * The rotation coordinates are relative to the anchor point of the
9611  * actor, set using clutter_actor_set_anchor_point(). If no anchor
9612  * point is set, the upper left corner is assumed as the origin.
9613  *
9614  * Since: 0.8
9615  */
9616 void
9617 clutter_actor_set_rotation (ClutterActor      *self,
9618                             ClutterRotateAxis  axis,
9619                             gdouble            angle,
9620                             gfloat             x,
9621                             gfloat             y,
9622                             gfloat             z)
9623 {
9624   ClutterVertex v;
9625
9626   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9627
9628   v.x = x;
9629   v.y = y;
9630   v.z = z;
9631
9632   g_object_freeze_notify (G_OBJECT (self));
9633
9634   clutter_actor_set_rotation_angle_internal (self, axis, angle);
9635   clutter_actor_set_rotation_center_internal (self, axis, &v);
9636
9637   g_object_thaw_notify (G_OBJECT (self));
9638 }
9639
9640 /**
9641  * clutter_actor_set_z_rotation_from_gravity:
9642  * @self: a #ClutterActor
9643  * @angle: the angle of rotation
9644  * @gravity: the center point of the rotation
9645  *
9646  * Sets the rotation angle of @self around the Z axis using the center
9647  * point specified as a compass point. For example to rotate such that
9648  * the center of the actor remains static you can use
9649  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
9650  * will move accordingly.
9651  *
9652  * Since: 1.0
9653  */
9654 void
9655 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
9656                                            gdouble         angle,
9657                                            ClutterGravity  gravity)
9658 {
9659   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9660
9661   if (gravity == CLUTTER_GRAVITY_NONE)
9662     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
9663   else
9664     {
9665       GObject *obj = G_OBJECT (self);
9666       ClutterTransformInfo *info;
9667
9668       info = _clutter_actor_get_transform_info (self);
9669
9670       g_object_freeze_notify (obj);
9671
9672       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
9673
9674       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
9675       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
9676       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
9677
9678       g_object_thaw_notify (obj);
9679     }
9680 }
9681
9682 /**
9683  * clutter_actor_get_rotation:
9684  * @self: a #ClutterActor
9685  * @axis: the axis of rotation
9686  * @x: (out): return value for the X coordinate of the center of rotation
9687  * @y: (out): return value for the Y coordinate of the center of rotation
9688  * @z: (out): return value for the Z coordinate of the center of rotation
9689  *
9690  * Retrieves the angle and center of rotation on the given axis,
9691  * set using clutter_actor_set_rotation().
9692  *
9693  * Return value: the angle of rotation
9694  *
9695  * Since: 0.8
9696  */
9697 gdouble
9698 clutter_actor_get_rotation (ClutterActor      *self,
9699                             ClutterRotateAxis  axis,
9700                             gfloat            *x,
9701                             gfloat            *y,
9702                             gfloat            *z)
9703 {
9704   const ClutterTransformInfo *info;
9705   const AnchorCoord *anchor_coord;
9706   gdouble retval = 0;
9707
9708   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9709
9710   info = _clutter_actor_get_transform_info_or_defaults (self);
9711
9712   switch (axis)
9713     {
9714     case CLUTTER_X_AXIS:
9715       anchor_coord = &info->rx_center;
9716       retval = info->rx_angle;
9717       break;
9718
9719     case CLUTTER_Y_AXIS:
9720       anchor_coord = &info->ry_center;
9721       retval = info->ry_angle;
9722       break;
9723
9724     case CLUTTER_Z_AXIS:
9725       anchor_coord = &info->rz_center;
9726       retval = info->rz_angle;
9727       break;
9728
9729     default:
9730       anchor_coord = NULL;
9731       retval = 0.0;
9732       break;
9733     }
9734
9735   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
9736
9737   return retval;
9738 }
9739
9740 /**
9741  * clutter_actor_get_z_rotation_gravity:
9742  * @self: A #ClutterActor
9743  *
9744  * Retrieves the center for the rotation around the Z axis as a
9745  * compass direction. If the center was specified in pixels or units
9746  * this will return %CLUTTER_GRAVITY_NONE.
9747  *
9748  * Return value: the Z rotation center
9749  *
9750  * Since: 1.0
9751  */
9752 ClutterGravity
9753 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
9754 {
9755   const ClutterTransformInfo *info;
9756
9757   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9758
9759   info = _clutter_actor_get_transform_info_or_defaults (self);
9760
9761   return clutter_anchor_coord_get_gravity (&info->rz_center);
9762 }
9763
9764 /**
9765  * clutter_actor_set_clip:
9766  * @self: A #ClutterActor
9767  * @xoff: X offset of the clip rectangle
9768  * @yoff: Y offset of the clip rectangle
9769  * @width: Width of the clip rectangle
9770  * @height: Height of the clip rectangle
9771  *
9772  * Sets clip area for @self. The clip area is always computed from the
9773  * upper left corner of the actor, even if the anchor point is set
9774  * otherwise.
9775  *
9776  * Since: 0.6
9777  */
9778 void
9779 clutter_actor_set_clip (ClutterActor *self,
9780                         gfloat        xoff,
9781                         gfloat        yoff,
9782                         gfloat        width,
9783                         gfloat        height)
9784 {
9785   ClutterActorPrivate *priv;
9786
9787   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9788
9789   priv = self->priv;
9790
9791   if (priv->has_clip &&
9792       priv->clip.x == xoff &&
9793       priv->clip.y == yoff &&
9794       priv->clip.width == width &&
9795       priv->clip.height == height)
9796     return;
9797
9798   priv->clip.x = xoff;
9799   priv->clip.y = yoff;
9800   priv->clip.width = width;
9801   priv->clip.height = height;
9802
9803   priv->has_clip = TRUE;
9804
9805   clutter_actor_queue_redraw (self);
9806
9807   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9808   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
9809 }
9810
9811 /**
9812  * clutter_actor_remove_clip:
9813  * @self: A #ClutterActor
9814  *
9815  * Removes clip area from @self.
9816  */
9817 void
9818 clutter_actor_remove_clip (ClutterActor *self)
9819 {
9820   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9821
9822   if (!self->priv->has_clip)
9823     return;
9824
9825   self->priv->has_clip = FALSE;
9826
9827   clutter_actor_queue_redraw (self);
9828
9829   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9830 }
9831
9832 /**
9833  * clutter_actor_has_clip:
9834  * @self: a #ClutterActor
9835  *
9836  * Determines whether the actor has a clip area set or not.
9837  *
9838  * Return value: %TRUE if the actor has a clip area set.
9839  *
9840  * Since: 0.1.1
9841  */
9842 gboolean
9843 clutter_actor_has_clip (ClutterActor *self)
9844 {
9845   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9846
9847   return self->priv->has_clip;
9848 }
9849
9850 /**
9851  * clutter_actor_get_clip:
9852  * @self: a #ClutterActor
9853  * @xoff: (out) (allow-none): return location for the X offset of
9854  *   the clip rectangle, or %NULL
9855  * @yoff: (out) (allow-none): return location for the Y offset of
9856  *   the clip rectangle, or %NULL
9857  * @width: (out) (allow-none): return location for the width of
9858  *   the clip rectangle, or %NULL
9859  * @height: (out) (allow-none): return location for the height of
9860  *   the clip rectangle, or %NULL
9861  *
9862  * Gets the clip area for @self, if any is set
9863  *
9864  * Since: 0.6
9865  */
9866 void
9867 clutter_actor_get_clip (ClutterActor *self,
9868                         gfloat       *xoff,
9869                         gfloat       *yoff,
9870                         gfloat       *width,
9871                         gfloat       *height)
9872 {
9873   ClutterActorPrivate *priv;
9874
9875   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9876
9877   priv = self->priv;
9878
9879   if (!priv->has_clip)
9880     return;
9881
9882   if (xoff != NULL)
9883     *xoff = priv->clip.x;
9884
9885   if (yoff != NULL)
9886     *yoff = priv->clip.y;
9887
9888   if (width != NULL)
9889     *width = priv->clip.width;
9890
9891   if (height != NULL)
9892     *height = priv->clip.height;
9893 }
9894
9895 /**
9896  * clutter_actor_get_children:
9897  * @self: a #ClutterActor
9898  *
9899  * Retrieves the list of children of @self.
9900  *
9901  * Return value: (transfer container) (element-type ClutterActor): A newly
9902  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
9903  *   done.
9904  *
9905  * Since: 1.10
9906  */
9907 GList *
9908 clutter_actor_get_children (ClutterActor *self)
9909 {
9910   ClutterActor *iter;
9911   GList *res;
9912
9913   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9914
9915   /* we walk the list backward so that we can use prepend(),
9916    * which is O(1)
9917    */
9918   for (iter = self->priv->last_child, res = NULL;
9919        iter != NULL;
9920        iter = iter->priv->prev_sibling)
9921     {
9922       res = g_list_prepend (res, iter);
9923     }
9924
9925   return res;
9926 }
9927
9928 /*< private >
9929  * insert_child_at_depth:
9930  * @self: a #ClutterActor
9931  * @child: a #ClutterActor
9932  *
9933  * Inserts @child inside the list of children held by @self, using
9934  * the depth as the insertion criteria.
9935  *
9936  * This sadly makes the insertion not O(1), but we can keep the
9937  * list sorted so that the painters algorithm we use for painting
9938  * the children will work correctly.
9939  */
9940 static void
9941 insert_child_at_depth (ClutterActor *self,
9942                        ClutterActor *child,
9943                        gpointer      dummy G_GNUC_UNUSED)
9944 {
9945   ClutterActor *iter;
9946
9947   child->priv->parent = self;
9948
9949   /* special-case the first child */
9950   if (self->priv->n_children == 0)
9951     {
9952       self->priv->first_child = child;
9953       self->priv->last_child = child;
9954
9955       child->priv->next_sibling = NULL;
9956       child->priv->prev_sibling = NULL;
9957
9958       return;
9959     }
9960
9961   /* Find the right place to insert the child so that it will still be
9962      sorted and the child will be after all of the actors at the same
9963      dept */
9964   for (iter = self->priv->first_child;
9965        iter != NULL;
9966        iter = iter->priv->next_sibling)
9967     {
9968       if (iter->priv->z > child->priv->z)
9969         break;
9970     }
9971
9972   if (iter != NULL)
9973     {
9974       ClutterActor *tmp = iter->priv->prev_sibling;
9975
9976       if (tmp != NULL)
9977         tmp->priv->next_sibling = child;
9978
9979       /* Insert the node before the found one */
9980       child->priv->prev_sibling = iter->priv->prev_sibling;
9981       child->priv->next_sibling = iter;
9982       iter->priv->prev_sibling = child;
9983     }
9984   else
9985     {
9986       ClutterActor *tmp = self->priv->last_child;
9987
9988       if (tmp != NULL)
9989         tmp->priv->next_sibling = child;
9990
9991       /* insert the node at the end of the list */
9992       child->priv->prev_sibling = self->priv->last_child;
9993       child->priv->next_sibling = NULL;
9994     }
9995
9996   if (child->priv->prev_sibling == NULL)
9997     self->priv->first_child = child;
9998
9999   if (child->priv->next_sibling == NULL)
10000     self->priv->last_child = child;
10001 }
10002
10003 static void
10004 insert_child_at_index (ClutterActor *self,
10005                        ClutterActor *child,
10006                        gpointer      data_)
10007 {
10008   gint index_ = GPOINTER_TO_INT (data_);
10009
10010   child->priv->parent = self;
10011
10012   if (index_ == 0)
10013     {
10014       ClutterActor *tmp = self->priv->first_child;
10015
10016       if (tmp != NULL)
10017         tmp->priv->prev_sibling = child;
10018
10019       child->priv->prev_sibling = NULL;
10020       child->priv->next_sibling = tmp;
10021     }
10022   else if (index_ < 0 || index_ >= self->priv->n_children)
10023     {
10024       ClutterActor *tmp = self->priv->last_child;
10025
10026       if (tmp != NULL)
10027         tmp->priv->next_sibling = child;
10028
10029       child->priv->prev_sibling = tmp;
10030       child->priv->next_sibling = NULL;
10031     }
10032   else
10033     {
10034       ClutterActor *iter;
10035       int i;
10036
10037       for (iter = self->priv->first_child, i = 0;
10038            iter != NULL;
10039            iter = iter->priv->next_sibling, i += 1)
10040         {
10041           if (index_ == i)
10042             {
10043               ClutterActor *tmp = iter->priv->prev_sibling;
10044
10045               child->priv->prev_sibling = tmp;
10046               child->priv->next_sibling = iter;
10047
10048               iter->priv->prev_sibling = child;
10049
10050               if (tmp != NULL)
10051                 tmp->priv->next_sibling = child;
10052
10053               break;
10054             }
10055         }
10056     }
10057
10058   if (child->priv->prev_sibling == NULL)
10059     self->priv->first_child = child;
10060
10061   if (child->priv->next_sibling == NULL)
10062     self->priv->last_child = child;
10063 }
10064
10065 static void
10066 insert_child_above (ClutterActor *self,
10067                     ClutterActor *child,
10068                     gpointer      data)
10069 {
10070   ClutterActor *sibling = data;
10071
10072   child->priv->parent = self;
10073
10074   if (sibling == NULL)
10075     sibling = self->priv->last_child;
10076
10077   child->priv->prev_sibling = sibling;
10078
10079   if (sibling != NULL)
10080     {
10081       ClutterActor *tmp = sibling->priv->next_sibling;
10082
10083       child->priv->next_sibling = tmp;
10084
10085       if (tmp != NULL)
10086         tmp->priv->prev_sibling = child;
10087
10088       sibling->priv->next_sibling = child;
10089     }
10090   else
10091     child->priv->next_sibling = NULL;
10092
10093   if (child->priv->prev_sibling == NULL)
10094     self->priv->first_child = child;
10095
10096   if (child->priv->next_sibling == NULL)
10097     self->priv->last_child = child;
10098 }
10099
10100 static void
10101 insert_child_below (ClutterActor *self,
10102                     ClutterActor *child,
10103                     gpointer      data)
10104 {
10105   ClutterActor *sibling = data;
10106
10107   child->priv->parent = self;
10108
10109   if (sibling == NULL)
10110     sibling = self->priv->first_child;
10111
10112   child->priv->next_sibling = sibling;
10113
10114   if (sibling != NULL)
10115     {
10116       ClutterActor *tmp = sibling->priv->prev_sibling;
10117
10118       child->priv->prev_sibling = tmp;
10119
10120       if (tmp != NULL)
10121         tmp->priv->next_sibling = child;
10122
10123       sibling->priv->prev_sibling = child;
10124     }
10125   else
10126     child->priv->prev_sibling = NULL;
10127
10128   if (child->priv->prev_sibling == NULL)
10129     self->priv->first_child = child;
10130
10131   if (child->priv->next_sibling == NULL)
10132     self->priv->last_child = child;
10133 }
10134
10135 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10136                                            ClutterActor *child,
10137                                            gpointer      data);
10138
10139 typedef enum {
10140   ADD_CHILD_CREATE_META       = 1 << 0,
10141   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10142   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10143   ADD_CHILD_CHECK_STATE       = 1 << 3,
10144   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10145
10146   /* default flags for public API */
10147   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10148                                ADD_CHILD_EMIT_PARENT_SET |
10149                                ADD_CHILD_EMIT_ACTOR_ADDED |
10150                                ADD_CHILD_CHECK_STATE |
10151                                ADD_CHILD_NOTIFY_FIRST_LAST,
10152
10153   /* flags for legacy/deprecated API */
10154   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10155                                ADD_CHILD_CHECK_STATE |
10156                                ADD_CHILD_NOTIFY_FIRST_LAST
10157 } ClutterActorAddChildFlags;
10158
10159 /*< private >
10160  * clutter_actor_add_child_internal:
10161  * @self: a #ClutterActor
10162  * @child: a #ClutterActor
10163  * @flags: control flags for actions
10164  * @add_func: delegate function
10165  * @data: (closure): data to pass to @add_func
10166  *
10167  * Adds @child to the list of children of @self.
10168  *
10169  * The actual insertion inside the list is delegated to @add_func: this
10170  * function will just set up the state, perform basic checks, and emit
10171  * signals.
10172  *
10173  * The @flags argument is used to perform additional operations.
10174  */
10175 static inline void
10176 clutter_actor_add_child_internal (ClutterActor              *self,
10177                                   ClutterActor              *child,
10178                                   ClutterActorAddChildFlags  flags,
10179                                   ClutterActorAddChildFunc   add_func,
10180                                   gpointer                   data)
10181 {
10182   ClutterTextDirection text_dir;
10183   gboolean create_meta;
10184   gboolean emit_parent_set, emit_actor_added;
10185   gboolean check_state;
10186   gboolean notify_first_last;
10187   ClutterActor *old_first_child, *old_last_child;
10188
10189   if (child->priv->parent != NULL)
10190     {
10191       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10192                  "use clutter_actor_remove_child() first.",
10193                  _clutter_actor_get_debug_name (child),
10194                  _clutter_actor_get_debug_name (child->priv->parent));
10195       return;
10196     }
10197
10198   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10199     {
10200       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10201                  "a child of another actor.",
10202                  _clutter_actor_get_debug_name (child));
10203       return;
10204     }
10205
10206 #if 0
10207   /* XXX - this check disallows calling methods that change the stacking
10208    * order within the destruction sequence, by triggering a critical
10209    * warning first, and leaving the actor in an undefined state, which
10210    * then ends up being caught by an assertion.
10211    *
10212    * the reproducible sequence is:
10213    *
10214    *   - actor gets destroyed;
10215    *   - another actor, linked to the first, will try to change the
10216    *     stacking order of the first actor;
10217    *   - changing the stacking order is a composite operation composed
10218    *     by the following steps:
10219    *     1. ref() the child;
10220    *     2. remove_child_internal(), which removes the reference;
10221    *     3. add_child_internal(), which adds a reference;
10222    *   - the state of the actor is not changed between (2) and (3), as
10223    *     it could be an expensive recomputation;
10224    *   - if (3) bails out, then the actor is in an undefined state, but
10225    *     still alive;
10226    *   - the destruction sequence terminates, but the actor is unparented
10227    *     while its state indicates being parented instead.
10228    *   - assertion failure.
10229    *
10230    * the obvious fix would be to decompose each set_child_*_sibling()
10231    * method into proper remove_child()/add_child(), with state validation;
10232    * this may cause excessive work, though, and trigger a cascade of other
10233    * bugs in code that assumes that a change in the stacking order is an
10234    * atomic operation.
10235    *
10236    * another potential fix is to just remove this check here, and let
10237    * code doing stacking order changes inside the destruction sequence
10238    * of an actor continue doing the work.
10239    *
10240    * the third fix is to silently bail out early from every
10241    * set_child_*_sibling() and set_child_at_index() method, and avoid
10242    * doing work.
10243    *
10244    * I have a preference for the second solution, since it involves the
10245    * least amount of work, and the least amount of code duplication.
10246    *
10247    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10248    */
10249   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10250     {
10251       g_warning ("The actor '%s' is currently being destroyed, and "
10252                  "cannot be added as a child of another actor.",
10253                  _clutter_actor_get_debug_name (child));
10254       return;
10255     }
10256 #endif
10257
10258   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10259   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10260   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10261   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10262   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10263
10264   old_first_child = self->priv->first_child;
10265   old_last_child = self->priv->last_child;
10266
10267   g_object_freeze_notify (G_OBJECT (self));
10268
10269   if (create_meta)
10270     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10271
10272   g_object_ref_sink (child);
10273   child->priv->parent = NULL;
10274   child->priv->next_sibling = NULL;
10275   child->priv->prev_sibling = NULL;
10276
10277   /* delegate the actual insertion */
10278   add_func (self, child, data);
10279
10280   g_assert (child->priv->parent == self);
10281
10282   self->priv->n_children += 1;
10283
10284   self->priv->age += 1;
10285
10286   /* if push_internal() has been called then we automatically set
10287    * the flag on the actor
10288    */
10289   if (self->priv->internal_child)
10290     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10291
10292   /* clutter_actor_reparent() will emit ::parent-set for us */
10293   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10294     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10295
10296   if (check_state)
10297     {
10298       /* If parent is mapped or realized, we need to also be mapped or
10299        * realized once we're inside the parent.
10300        */
10301       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10302
10303       /* propagate the parent's text direction to the child */
10304       text_dir = clutter_actor_get_text_direction (self);
10305       clutter_actor_set_text_direction (child, text_dir);
10306     }
10307
10308   if (child->priv->show_on_set_parent)
10309     clutter_actor_show (child);
10310
10311   if (CLUTTER_ACTOR_IS_MAPPED (child))
10312     clutter_actor_queue_redraw (child);
10313
10314   /* maintain the invariant that if an actor needs layout,
10315    * its parents do as well
10316    */
10317   if (child->priv->needs_width_request ||
10318       child->priv->needs_height_request ||
10319       child->priv->needs_allocation)
10320     {
10321       /* we work around the short-circuiting we do
10322        * in clutter_actor_queue_relayout() since we
10323        * want to force a relayout
10324        */
10325       child->priv->needs_width_request = TRUE;
10326       child->priv->needs_height_request = TRUE;
10327       child->priv->needs_allocation = TRUE;
10328
10329       clutter_actor_queue_relayout (child->priv->parent);
10330     }
10331
10332   if (emit_actor_added)
10333     g_signal_emit_by_name (self, "actor-added", child);
10334
10335   if (notify_first_last)
10336     {
10337       if (old_first_child != self->priv->first_child)
10338         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10339
10340       if (old_last_child != self->priv->last_child)
10341         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10342     }
10343
10344   g_object_thaw_notify (G_OBJECT (self));
10345 }
10346
10347 /**
10348  * clutter_actor_add_child:
10349  * @self: a #ClutterActor
10350  * @child: a #ClutterActor
10351  *
10352  * Adds @child to the children of @self.
10353  *
10354  * This function will acquire a reference on @child that will only
10355  * be released when calling clutter_actor_remove_child().
10356  *
10357  * This function will take into consideration the #ClutterActor:depth
10358  * of @child, and will keep the list of children sorted.
10359  *
10360  * This function will emit the #ClutterContainer::actor-added signal
10361  * on @self.
10362  *
10363  * Since: 1.10
10364  */
10365 void
10366 clutter_actor_add_child (ClutterActor *self,
10367                          ClutterActor *child)
10368 {
10369   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10370   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10371   g_return_if_fail (self != child);
10372   g_return_if_fail (child->priv->parent == NULL);
10373
10374   clutter_actor_add_child_internal (self, child,
10375                                     ADD_CHILD_DEFAULT_FLAGS,
10376                                     insert_child_at_depth,
10377                                     NULL);
10378 }
10379
10380 /**
10381  * clutter_actor_insert_child_at_index:
10382  * @self: a #ClutterActor
10383  * @child: a #ClutterActor
10384  * @index_: the index
10385  *
10386  * Inserts @child into the list of children of @self, using the
10387  * given @index_. If @index_ is greater than the number of children
10388  * in @self, or is less than 0, then the new child is added at the end.
10389  *
10390  * This function will acquire a reference on @child that will only
10391  * be released when calling clutter_actor_remove_child().
10392  *
10393  * This function will not take into consideration the #ClutterActor:depth
10394  * of @child.
10395  *
10396  * This function will emit the #ClutterContainer::actor-added signal
10397  * on @self.
10398  *
10399  * Since: 1.10
10400  */
10401 void
10402 clutter_actor_insert_child_at_index (ClutterActor *self,
10403                                      ClutterActor *child,
10404                                      gint          index_)
10405 {
10406   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10407   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10408   g_return_if_fail (self != child);
10409   g_return_if_fail (child->priv->parent == NULL);
10410
10411   clutter_actor_add_child_internal (self, child,
10412                                     ADD_CHILD_DEFAULT_FLAGS,
10413                                     insert_child_at_index,
10414                                     GINT_TO_POINTER (index_));
10415 }
10416
10417 /**
10418  * clutter_actor_insert_child_above:
10419  * @self: a #ClutterActor
10420  * @child: a #ClutterActor
10421  * @sibling: (allow-none): a child of @self, or %NULL
10422  *
10423  * Inserts @child into the list of children of @self, above another
10424  * child of @self or, if @sibling is %NULL, above all the children
10425  * of @self.
10426  *
10427  * This function will acquire a reference on @child that will only
10428  * be released when calling clutter_actor_remove_child().
10429  *
10430  * This function will not take into consideration the #ClutterActor:depth
10431  * of @child.
10432  *
10433  * This function will emit the #ClutterContainer::actor-added signal
10434  * on @self.
10435  *
10436  * Since: 1.10
10437  */
10438 void
10439 clutter_actor_insert_child_above (ClutterActor *self,
10440                                   ClutterActor *child,
10441                                   ClutterActor *sibling)
10442 {
10443   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10444   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10445   g_return_if_fail (self != child);
10446   g_return_if_fail (child != sibling);
10447   g_return_if_fail (child->priv->parent == NULL);
10448   g_return_if_fail (sibling == NULL ||
10449                     (CLUTTER_IS_ACTOR (sibling) &&
10450                      sibling->priv->parent == self));
10451
10452   clutter_actor_add_child_internal (self, child,
10453                                     ADD_CHILD_DEFAULT_FLAGS,
10454                                     insert_child_above,
10455                                     sibling);
10456 }
10457
10458 /**
10459  * clutter_actor_insert_child_below:
10460  * @self: a #ClutterActor
10461  * @child: a #ClutterActor
10462  * @sibling: (allow-none): a child of @self, or %NULL
10463  *
10464  * Inserts @child into the list of children of @self, below another
10465  * child of @self or, if @sibling is %NULL, below all the children
10466  * of @self.
10467  *
10468  * This function will acquire a reference on @child that will only
10469  * be released when calling clutter_actor_remove_child().
10470  *
10471  * This function will not take into consideration the #ClutterActor:depth
10472  * of @child.
10473  *
10474  * This function will emit the #ClutterContainer::actor-added signal
10475  * on @self.
10476  *
10477  * Since: 1.10
10478  */
10479 void
10480 clutter_actor_insert_child_below (ClutterActor *self,
10481                                   ClutterActor *child,
10482                                   ClutterActor *sibling)
10483 {
10484   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10485   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10486   g_return_if_fail (self != child);
10487   g_return_if_fail (child != sibling);
10488   g_return_if_fail (child->priv->parent == NULL);
10489   g_return_if_fail (sibling == NULL ||
10490                     (CLUTTER_IS_ACTOR (sibling) &&
10491                      sibling->priv->parent == self));
10492
10493   clutter_actor_add_child_internal (self, child,
10494                                     ADD_CHILD_DEFAULT_FLAGS,
10495                                     insert_child_below,
10496                                     sibling);
10497 }
10498
10499 /**
10500  * clutter_actor_set_parent:
10501  * @self: A #ClutterActor
10502  * @parent: A new #ClutterActor parent
10503  *
10504  * Sets the parent of @self to @parent.
10505  *
10506  * This function will result in @parent acquiring a reference on @self,
10507  * eventually by sinking its floating reference first. The reference
10508  * will be released by clutter_actor_unparent().
10509  *
10510  * This function should only be called by legacy #ClutterActor<!-- -->s
10511  * implementing the #ClutterContainer interface.
10512  *
10513  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10514  */
10515 void
10516 clutter_actor_set_parent (ClutterActor *self,
10517                           ClutterActor *parent)
10518 {
10519   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10520   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10521   g_return_if_fail (self != parent);
10522   g_return_if_fail (self->priv->parent == NULL);
10523
10524   /* as this function will be called inside ClutterContainer::add
10525    * implementations or when building up a composite actor, we have
10526    * to preserve the old behaviour, and not create child meta or
10527    * emit the ::actor-added signal, to avoid recursion or double
10528    * emissions
10529    */
10530   clutter_actor_add_child_internal (parent, self,
10531                                     ADD_CHILD_LEGACY_FLAGS,
10532                                     insert_child_at_depth,
10533                                     NULL);
10534 }
10535
10536 /**
10537  * clutter_actor_get_parent:
10538  * @self: A #ClutterActor
10539  *
10540  * Retrieves the parent of @self.
10541  *
10542  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10543  *  if no parent is set
10544  */
10545 ClutterActor *
10546 clutter_actor_get_parent (ClutterActor *self)
10547 {
10548   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10549
10550   return self->priv->parent;
10551 }
10552
10553 /**
10554  * clutter_actor_get_paint_visibility:
10555  * @self: A #ClutterActor
10556  *
10557  * Retrieves the 'paint' visibility of an actor recursively checking for non
10558  * visible parents.
10559  *
10560  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10561  *
10562  * Return Value: %TRUE if the actor is visibile and will be painted.
10563  *
10564  * Since: 0.8.4
10565  */
10566 gboolean
10567 clutter_actor_get_paint_visibility (ClutterActor *actor)
10568 {
10569   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10570
10571   return CLUTTER_ACTOR_IS_MAPPED (actor);
10572 }
10573
10574 /**
10575  * clutter_actor_remove_child:
10576  * @self: a #ClutterActor
10577  * @child: a #ClutterActor
10578  *
10579  * Removes @child from the children of @self.
10580  *
10581  * This function will release the reference added by
10582  * clutter_actor_add_child(), so if you want to keep using @child
10583  * you will have to acquire a referenced on it before calling this
10584  * function.
10585  *
10586  * This function will emit the #ClutterContainer::actor-removed
10587  * signal on @self.
10588  *
10589  * Since: 1.10
10590  */
10591 void
10592 clutter_actor_remove_child (ClutterActor *self,
10593                             ClutterActor *child)
10594 {
10595   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10596   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10597   g_return_if_fail (self != child);
10598   g_return_if_fail (child->priv->parent != NULL);
10599   g_return_if_fail (child->priv->parent == self);
10600
10601   clutter_actor_remove_child_internal (self, child,
10602                                        REMOVE_CHILD_DEFAULT_FLAGS);
10603 }
10604
10605 /**
10606  * clutter_actor_remove_all_children:
10607  * @self: a #ClutterActor
10608  *
10609  * Removes all children of @self.
10610  *
10611  * This function releases the reference added by inserting a child actor
10612  * in the list of children of @self.
10613  *
10614  * If the reference count of a child drops to zero, the child will be
10615  * destroyed. If you want to ensure the destruction of all the children
10616  * of @self, use clutter_actor_destroy_all_children().
10617  *
10618  * Since: 1.10
10619  */
10620 void
10621 clutter_actor_remove_all_children (ClutterActor *self)
10622 {
10623   ClutterActorIter iter;
10624
10625   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10626
10627   if (self->priv->n_children == 0)
10628     return;
10629
10630   g_object_freeze_notify (G_OBJECT (self));
10631
10632   clutter_actor_iter_init (&iter, self);
10633   while (clutter_actor_iter_next (&iter, NULL))
10634     clutter_actor_iter_remove (&iter);
10635
10636   g_object_thaw_notify (G_OBJECT (self));
10637
10638   /* sanity check */
10639   g_assert (self->priv->first_child == NULL);
10640   g_assert (self->priv->last_child == NULL);
10641   g_assert (self->priv->n_children == 0);
10642 }
10643
10644 /**
10645  * clutter_actor_destroy_all_children:
10646  * @self: a #ClutterActor
10647  *
10648  * Destroys all children of @self.
10649  *
10650  * This function releases the reference added by inserting a child
10651  * actor in the list of children of @self, and ensures that the
10652  * #ClutterActor::destroy signal is emitted on each child of the
10653  * actor.
10654  *
10655  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
10656  * when its reference count drops to 0; the default handler of the
10657  * #ClutterActor::destroy signal will destroy all the children of an
10658  * actor. This function ensures that all children are destroyed, instead
10659  * of just removed from @self, unlike clutter_actor_remove_all_children()
10660  * which will merely release the reference and remove each child.
10661  *
10662  * Unless you acquired an additional reference on each child of @self
10663  * prior to calling clutter_actor_remove_all_children() and want to reuse
10664  * the actors, you should use clutter_actor_destroy_all_children() in
10665  * order to make sure that children are destroyed and signal handlers
10666  * are disconnected even in cases where circular references prevent this
10667  * from automatically happening through reference counting alone.
10668  *
10669  * Since: 1.10
10670  */
10671 void
10672 clutter_actor_destroy_all_children (ClutterActor *self)
10673 {
10674   ClutterActorIter iter;
10675
10676   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10677
10678   if (self->priv->n_children == 0)
10679     return;
10680
10681   g_object_freeze_notify (G_OBJECT (self));
10682
10683   clutter_actor_iter_init (&iter, self);
10684   while (clutter_actor_iter_next (&iter, NULL))
10685     clutter_actor_iter_destroy (&iter);
10686
10687   g_object_thaw_notify (G_OBJECT (self));
10688
10689   /* sanity check */
10690   g_assert (self->priv->first_child == NULL);
10691   g_assert (self->priv->last_child == NULL);
10692   g_assert (self->priv->n_children == 0);
10693 }
10694
10695 typedef struct _InsertBetweenData {
10696   ClutterActor *prev_sibling;
10697   ClutterActor *next_sibling;
10698 } InsertBetweenData;
10699
10700 static void
10701 insert_child_between (ClutterActor *self,
10702                       ClutterActor *child,
10703                       gpointer      data_)
10704 {
10705   InsertBetweenData *data = data_;
10706   ClutterActor *prev_sibling = data->prev_sibling;
10707   ClutterActor *next_sibling = data->next_sibling;
10708
10709   child->priv->parent = self;
10710   child->priv->prev_sibling = prev_sibling;
10711   child->priv->next_sibling = next_sibling;
10712
10713   if (prev_sibling != NULL)
10714     prev_sibling->priv->next_sibling = child;
10715
10716   if (next_sibling != NULL)
10717     next_sibling->priv->prev_sibling = child;
10718
10719   if (child->priv->prev_sibling == NULL)
10720     self->priv->first_child = child;
10721
10722   if (child->priv->next_sibling == NULL)
10723     self->priv->last_child = child;
10724 }
10725
10726 /**
10727  * clutter_actor_replace_child:
10728  * @self: a #ClutterActor
10729  * @old_child: the child of @self to replace
10730  * @new_child: the #ClutterActor to replace @old_child
10731  *
10732  * Replaces @old_child with @new_child in the list of children of @self.
10733  *
10734  * Since: 1.10
10735  */
10736 void
10737 clutter_actor_replace_child (ClutterActor *self,
10738                              ClutterActor *old_child,
10739                              ClutterActor *new_child)
10740 {
10741   ClutterActor *prev_sibling, *next_sibling;
10742   InsertBetweenData clos;
10743
10744   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10745   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
10746   g_return_if_fail (old_child->priv->parent == self);
10747   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
10748   g_return_if_fail (old_child != new_child);
10749   g_return_if_fail (new_child != self);
10750   g_return_if_fail (new_child->priv->parent == NULL);
10751
10752   prev_sibling = old_child->priv->prev_sibling;
10753   next_sibling = old_child->priv->next_sibling;
10754   clutter_actor_remove_child_internal (self, old_child,
10755                                        REMOVE_CHILD_DEFAULT_FLAGS);
10756
10757   clos.prev_sibling = prev_sibling;
10758   clos.next_sibling = next_sibling;
10759   clutter_actor_add_child_internal (self, new_child,
10760                                     ADD_CHILD_DEFAULT_FLAGS,
10761                                     insert_child_between,
10762                                     &clos);
10763 }
10764
10765 /**
10766  * clutter_actor_unparent:
10767  * @self: a #ClutterActor
10768  *
10769  * Removes the parent of @self.
10770  *
10771  * This will cause the parent of @self to release the reference
10772  * acquired when calling clutter_actor_set_parent(), so if you
10773  * want to keep @self you will have to acquire a reference of
10774  * your own, through g_object_ref().
10775  *
10776  * This function should only be called by legacy #ClutterActor<!-- -->s
10777  * implementing the #ClutterContainer interface.
10778  *
10779  * Since: 0.1.1
10780  *
10781  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
10782  */
10783 void
10784 clutter_actor_unparent (ClutterActor *self)
10785 {
10786   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10787
10788   if (self->priv->parent == NULL)
10789     return;
10790
10791   clutter_actor_remove_child_internal (self->priv->parent, self,
10792                                        REMOVE_CHILD_LEGACY_FLAGS);
10793 }
10794
10795 /**
10796  * clutter_actor_reparent:
10797  * @self: a #ClutterActor
10798  * @new_parent: the new #ClutterActor parent
10799  *
10800  * Resets the parent actor of @self.
10801  *
10802  * This function is logically equivalent to calling clutter_actor_unparent()
10803  * and clutter_actor_set_parent(), but more efficiently implemented, as it
10804  * ensures the child is not finalized when unparented, and emits the
10805  * #ClutterActor::parent-set signal only once.
10806  *
10807  * In reality, calling this function is less useful than it sounds, as some
10808  * application code may rely on changes in the intermediate state between
10809  * removal and addition of the actor from its old parent to the @new_parent.
10810  * Thus, it is strongly encouraged to avoid using this function in application
10811  * code.
10812  *
10813  * Since: 0.2
10814  *
10815  * Deprecated: 1.10: Use clutter_actor_remove_child() and
10816  *   clutter_actor_add_child() instead; remember to take a reference on
10817  *   the actor being removed before calling clutter_actor_remove_child()
10818  *   to avoid the reference count dropping to zero and the actor being
10819  *   destroyed.
10820  */
10821 void
10822 clutter_actor_reparent (ClutterActor *self,
10823                         ClutterActor *new_parent)
10824 {
10825   ClutterActorPrivate *priv;
10826
10827   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10828   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
10829   g_return_if_fail (self != new_parent);
10830
10831   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10832     {
10833       g_warning ("Cannot set a parent on a toplevel actor");
10834       return;
10835     }
10836
10837   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
10838     {
10839       g_warning ("Cannot set a parent currently being destroyed");
10840       return;
10841     }
10842
10843   priv = self->priv;
10844
10845   if (priv->parent != new_parent)
10846     {
10847       ClutterActor *old_parent;
10848
10849       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10850
10851       old_parent = priv->parent;
10852
10853       g_object_ref (self);
10854
10855       if (old_parent != NULL)
10856         {
10857          /* go through the Container implementation if this is a regular
10858           * child and not an internal one
10859           */
10860          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10861            {
10862              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
10863
10864              /* this will have to call unparent() */
10865              clutter_container_remove_actor (parent, self);
10866            }
10867          else
10868            clutter_actor_remove_child_internal (old_parent, self,
10869                                                 REMOVE_CHILD_LEGACY_FLAGS);
10870         }
10871
10872       /* Note, will call set_parent() */
10873       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10874         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
10875       else
10876         clutter_actor_add_child_internal (new_parent, self,
10877                                           ADD_CHILD_LEGACY_FLAGS,
10878                                           insert_child_at_depth,
10879                                           NULL);
10880
10881       /* we emit the ::parent-set signal once */
10882       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
10883
10884       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10885
10886       /* the IN_REPARENT flag suspends state updates */
10887       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
10888
10889       g_object_unref (self);
10890    }
10891 }
10892
10893 /**
10894  * clutter_actor_contains:
10895  * @self: A #ClutterActor
10896  * @descendant: A #ClutterActor, possibly contained in @self
10897  *
10898  * Determines if @descendant is contained inside @self (either as an
10899  * immediate child, or as a deeper descendant). If @self and
10900  * @descendant point to the same actor then it will also return %TRUE.
10901  *
10902  * Return value: whether @descendent is contained within @self
10903  *
10904  * Since: 1.4
10905  */
10906 gboolean
10907 clutter_actor_contains (ClutterActor *self,
10908                         ClutterActor *descendant)
10909 {
10910   ClutterActor *actor;
10911
10912   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10913   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
10914
10915   for (actor = descendant; actor; actor = actor->priv->parent)
10916     if (actor == self)
10917       return TRUE;
10918
10919   return FALSE;
10920 }
10921
10922 /**
10923  * clutter_actor_set_child_above_sibling:
10924  * @self: a #ClutterActor
10925  * @child: a #ClutterActor child of @self
10926  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10927  *
10928  * Sets @child to be above @sibling in the list of children of @self.
10929  *
10930  * If @sibling is %NULL, @child will be the new last child of @self.
10931  *
10932  * This function is logically equivalent to removing @child and using
10933  * clutter_actor_insert_child_above(), but it will not emit signals
10934  * or change state on @child.
10935  *
10936  * Since: 1.10
10937  */
10938 void
10939 clutter_actor_set_child_above_sibling (ClutterActor *self,
10940                                        ClutterActor *child,
10941                                        ClutterActor *sibling)
10942 {
10943   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10944   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10945   g_return_if_fail (child->priv->parent == self);
10946   g_return_if_fail (child != sibling);
10947   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10948
10949   if (sibling != NULL)
10950     g_return_if_fail (sibling->priv->parent == self);
10951
10952   /* we don't want to change the state of child, or emit signals, or
10953    * regenerate ChildMeta instances here, but we still want to follow
10954    * the correct sequence of steps encoded in remove_child() and
10955    * add_child(), so that correctness is ensured, and we only go
10956    * through one known code path.
10957    */
10958   g_object_ref (child);
10959   clutter_actor_remove_child_internal (self, child, 0);
10960   clutter_actor_add_child_internal (self, child,
10961                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10962                                     insert_child_above,
10963                                     sibling);
10964
10965   clutter_actor_queue_relayout (self);
10966 }
10967
10968 /**
10969  * clutter_actor_set_child_below_sibling:
10970  * @self: a #ClutterActor
10971  * @child: a #ClutterActor child of @self
10972  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10973  *
10974  * Sets @child to be below @sibling in the list of children of @self.
10975  *
10976  * If @sibling is %NULL, @child will be the new first child of @self.
10977  *
10978  * This function is logically equivalent to removing @self and using
10979  * clutter_actor_insert_child_below(), but it will not emit signals
10980  * or change state on @child.
10981  *
10982  * Since: 1.10
10983  */
10984 void
10985 clutter_actor_set_child_below_sibling (ClutterActor *self,
10986                                        ClutterActor *child,
10987                                        ClutterActor *sibling)
10988 {
10989   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10990   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10991   g_return_if_fail (child->priv->parent == self);
10992   g_return_if_fail (child != sibling);
10993   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10994
10995   if (sibling != NULL)
10996     g_return_if_fail (sibling->priv->parent == self);
10997
10998   /* see the comment in set_child_above_sibling() */
10999   g_object_ref (child);
11000   clutter_actor_remove_child_internal (self, child, 0);
11001   clutter_actor_add_child_internal (self, child,
11002                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11003                                     insert_child_below,
11004                                     sibling);
11005
11006   clutter_actor_queue_relayout (self);
11007 }
11008
11009 /**
11010  * clutter_actor_set_child_at_index:
11011  * @self: a #ClutterActor
11012  * @child: a #ClutterActor child of @self
11013  * @index_: the new index for @child
11014  *
11015  * Changes the index of @child in the list of children of @self.
11016  *
11017  * This function is logically equivalent to removing @child and
11018  * calling clutter_actor_insert_child_at_index(), but it will not
11019  * emit signals or change state on @child.
11020  *
11021  * Since: 1.10
11022  */
11023 void
11024 clutter_actor_set_child_at_index (ClutterActor *self,
11025                                   ClutterActor *child,
11026                                   gint          index_)
11027 {
11028   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11029   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11030   g_return_if_fail (child->priv->parent == self);
11031   g_return_if_fail (index_ <= self->priv->n_children);
11032
11033   g_object_ref (child);
11034   clutter_actor_remove_child_internal (self, child, 0);
11035   clutter_actor_add_child_internal (self, child,
11036                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11037                                     insert_child_at_index,
11038                                     GINT_TO_POINTER (index_));
11039
11040   clutter_actor_queue_relayout (self);
11041 }
11042
11043 /**
11044  * clutter_actor_raise:
11045  * @self: A #ClutterActor
11046  * @below: (allow-none): A #ClutterActor to raise above.
11047  *
11048  * Puts @self above @below.
11049  *
11050  * Both actors must have the same parent, and the parent must implement
11051  * the #ClutterContainer interface
11052  *
11053  * This function calls clutter_container_raise_child() internally.
11054  *
11055  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11056  */
11057 void
11058 clutter_actor_raise (ClutterActor *self,
11059                      ClutterActor *below)
11060 {
11061   ClutterActor *parent;
11062
11063   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11064
11065   parent = clutter_actor_get_parent (self);
11066   if (parent == NULL)
11067     {
11068       g_warning ("%s: Actor '%s' is not inside a container",
11069                  G_STRFUNC,
11070                  _clutter_actor_get_debug_name (self));
11071       return;
11072     }
11073
11074   if (below != NULL)
11075     {
11076       if (parent != clutter_actor_get_parent (below))
11077         {
11078           g_warning ("%s Actor '%s' is not in the same container as "
11079                      "actor '%s'",
11080                      G_STRFUNC,
11081                      _clutter_actor_get_debug_name (self),
11082                      _clutter_actor_get_debug_name (below));
11083           return;
11084         }
11085     }
11086
11087   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11088 }
11089
11090 /**
11091  * clutter_actor_lower:
11092  * @self: A #ClutterActor
11093  * @above: (allow-none): A #ClutterActor to lower below
11094  *
11095  * Puts @self below @above.
11096  *
11097  * Both actors must have the same parent, and the parent must implement
11098  * the #ClutterContainer interface.
11099  *
11100  * This function calls clutter_container_lower_child() internally.
11101  *
11102  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11103  */
11104 void
11105 clutter_actor_lower (ClutterActor *self,
11106                      ClutterActor *above)
11107 {
11108   ClutterActor *parent;
11109
11110   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11111
11112   parent = clutter_actor_get_parent (self);
11113   if (parent == NULL)
11114     {
11115       g_warning ("%s: Actor of type %s is not inside a container",
11116                  G_STRFUNC,
11117                  _clutter_actor_get_debug_name (self));
11118       return;
11119     }
11120
11121   if (above)
11122     {
11123       if (parent != clutter_actor_get_parent (above))
11124         {
11125           g_warning ("%s: Actor '%s' is not in the same container as "
11126                      "actor '%s'",
11127                      G_STRFUNC,
11128                      _clutter_actor_get_debug_name (self),
11129                      _clutter_actor_get_debug_name (above));
11130           return;
11131         }
11132     }
11133
11134   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11135 }
11136
11137 /**
11138  * clutter_actor_raise_top:
11139  * @self: A #ClutterActor
11140  *
11141  * Raises @self to the top.
11142  *
11143  * This function calls clutter_actor_raise() internally.
11144  *
11145  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11146  *   a %NULL sibling, instead.
11147  */
11148 void
11149 clutter_actor_raise_top (ClutterActor *self)
11150 {
11151   clutter_actor_raise (self, NULL);
11152 }
11153
11154 /**
11155  * clutter_actor_lower_bottom:
11156  * @self: A #ClutterActor
11157  *
11158  * Lowers @self to the bottom.
11159  *
11160  * This function calls clutter_actor_lower() internally.
11161  *
11162  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11163  *   a %NULL sibling, instead.
11164  */
11165 void
11166 clutter_actor_lower_bottom (ClutterActor *self)
11167 {
11168   clutter_actor_lower (self, NULL);
11169 }
11170
11171 /*
11172  * Event handling
11173  */
11174
11175 /**
11176  * clutter_actor_event:
11177  * @actor: a #ClutterActor
11178  * @event: a #ClutterEvent
11179  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11180  *
11181  * This function is used to emit an event on the main stage.
11182  * You should rarely need to use this function, except for
11183  * synthetising events.
11184  *
11185  * Return value: the return value from the signal emission: %TRUE
11186  *   if the actor handled the event, or %FALSE if the event was
11187  *   not handled
11188  *
11189  * Since: 0.6
11190  */
11191 gboolean
11192 clutter_actor_event (ClutterActor *actor,
11193                      ClutterEvent *event,
11194                      gboolean      capture)
11195 {
11196   gboolean retval = FALSE;
11197   gint signal_num = -1;
11198
11199   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11200   g_return_val_if_fail (event != NULL, FALSE);
11201
11202   g_object_ref (actor);
11203
11204   if (capture)
11205     {
11206       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11207                      event,
11208                      &retval);
11209       goto out;
11210     }
11211
11212   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11213
11214   if (!retval)
11215     {
11216       switch (event->type)
11217         {
11218         case CLUTTER_NOTHING:
11219           break;
11220         case CLUTTER_BUTTON_PRESS:
11221           signal_num = BUTTON_PRESS_EVENT;
11222           break;
11223         case CLUTTER_BUTTON_RELEASE:
11224           signal_num = BUTTON_RELEASE_EVENT;
11225           break;
11226         case CLUTTER_SCROLL:
11227           signal_num = SCROLL_EVENT;
11228           break;
11229         case CLUTTER_KEY_PRESS:
11230           signal_num = KEY_PRESS_EVENT;
11231           break;
11232         case CLUTTER_KEY_RELEASE:
11233           signal_num = KEY_RELEASE_EVENT;
11234           break;
11235         case CLUTTER_MOTION:
11236           signal_num = MOTION_EVENT;
11237           break;
11238         case CLUTTER_ENTER:
11239           signal_num = ENTER_EVENT;
11240           break;
11241         case CLUTTER_LEAVE:
11242           signal_num = LEAVE_EVENT;
11243           break;
11244         case CLUTTER_DELETE:
11245         case CLUTTER_DESTROY_NOTIFY:
11246         case CLUTTER_CLIENT_MESSAGE:
11247         default:
11248           signal_num = -1;
11249           break;
11250         }
11251
11252       if (signal_num != -1)
11253         g_signal_emit (actor, actor_signals[signal_num], 0,
11254                        event, &retval);
11255     }
11256
11257 out:
11258   g_object_unref (actor);
11259
11260   return retval;
11261 }
11262
11263 /**
11264  * clutter_actor_set_reactive:
11265  * @actor: a #ClutterActor
11266  * @reactive: whether the actor should be reactive to events
11267  *
11268  * Sets @actor as reactive. Reactive actors will receive events.
11269  *
11270  * Since: 0.6
11271  */
11272 void
11273 clutter_actor_set_reactive (ClutterActor *actor,
11274                             gboolean      reactive)
11275 {
11276   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11277
11278   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11279     return;
11280
11281   if (reactive)
11282     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11283   else
11284     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11285
11286   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11287 }
11288
11289 /**
11290  * clutter_actor_get_reactive:
11291  * @actor: a #ClutterActor
11292  *
11293  * Checks whether @actor is marked as reactive.
11294  *
11295  * Return value: %TRUE if the actor is reactive
11296  *
11297  * Since: 0.6
11298  */
11299 gboolean
11300 clutter_actor_get_reactive (ClutterActor *actor)
11301 {
11302   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11303
11304   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11305 }
11306
11307 /**
11308  * clutter_actor_get_anchor_point:
11309  * @self: a #ClutterActor
11310  * @anchor_x: (out): return location for the X coordinate of the anchor point
11311  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11312  *
11313  * Gets the current anchor point of the @actor in pixels.
11314  *
11315  * Since: 0.6
11316  */
11317 void
11318 clutter_actor_get_anchor_point (ClutterActor *self,
11319                                 gfloat       *anchor_x,
11320                                 gfloat       *anchor_y)
11321 {
11322   const ClutterTransformInfo *info;
11323
11324   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11325
11326   info = _clutter_actor_get_transform_info_or_defaults (self);
11327   clutter_anchor_coord_get_units (self, &info->anchor,
11328                                   anchor_x,
11329                                   anchor_y,
11330                                   NULL);
11331 }
11332
11333 /**
11334  * clutter_actor_set_anchor_point:
11335  * @self: a #ClutterActor
11336  * @anchor_x: X coordinate of the anchor point
11337  * @anchor_y: Y coordinate of the anchor point
11338  *
11339  * Sets an anchor point for @self. The anchor point is a point in the
11340  * coordinate space of an actor to which the actor position within its
11341  * parent is relative; the default is (0, 0), i.e. the top-left corner
11342  * of the actor.
11343  *
11344  * Since: 0.6
11345  */
11346 void
11347 clutter_actor_set_anchor_point (ClutterActor *self,
11348                                 gfloat        anchor_x,
11349                                 gfloat        anchor_y)
11350 {
11351   ClutterTransformInfo *info;
11352   ClutterActorPrivate *priv;
11353   gboolean changed = FALSE;
11354   gfloat old_anchor_x, old_anchor_y;
11355   GObject *obj;
11356
11357   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11358
11359   obj = G_OBJECT (self);
11360   priv = self->priv;
11361   info = _clutter_actor_get_transform_info (self);
11362
11363   g_object_freeze_notify (obj);
11364
11365   clutter_anchor_coord_get_units (self, &info->anchor,
11366                                   &old_anchor_x,
11367                                   &old_anchor_y,
11368                                   NULL);
11369
11370   if (info->anchor.is_fractional)
11371     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11372
11373   if (old_anchor_x != anchor_x)
11374     {
11375       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11376       changed = TRUE;
11377     }
11378
11379   if (old_anchor_y != anchor_y)
11380     {
11381       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11382       changed = TRUE;
11383     }
11384
11385   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11386
11387   if (changed)
11388     {
11389       priv->transform_valid = FALSE;
11390       clutter_actor_queue_redraw (self);
11391     }
11392
11393   g_object_thaw_notify (obj);
11394 }
11395
11396 /**
11397  * clutter_actor_get_anchor_point_gravity:
11398  * @self: a #ClutterActor
11399  *
11400  * Retrieves the anchor position expressed as a #ClutterGravity. If
11401  * the anchor point was specified using pixels or units this will
11402  * return %CLUTTER_GRAVITY_NONE.
11403  *
11404  * Return value: the #ClutterGravity used by the anchor point
11405  *
11406  * Since: 1.0
11407  */
11408 ClutterGravity
11409 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11410 {
11411   const ClutterTransformInfo *info;
11412
11413   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11414
11415   info = _clutter_actor_get_transform_info_or_defaults (self);
11416
11417   return clutter_anchor_coord_get_gravity (&info->anchor);
11418 }
11419
11420 /**
11421  * clutter_actor_move_anchor_point:
11422  * @self: a #ClutterActor
11423  * @anchor_x: X coordinate of the anchor point
11424  * @anchor_y: Y coordinate of the anchor point
11425  *
11426  * Sets an anchor point for the actor, and adjusts the actor postion so that
11427  * the relative position of the actor toward its parent remains the same.
11428  *
11429  * Since: 0.6
11430  */
11431 void
11432 clutter_actor_move_anchor_point (ClutterActor *self,
11433                                  gfloat        anchor_x,
11434                                  gfloat        anchor_y)
11435 {
11436   gfloat old_anchor_x, old_anchor_y;
11437   const ClutterTransformInfo *info;
11438
11439   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11440
11441   info = _clutter_actor_get_transform_info (self);
11442   clutter_anchor_coord_get_units (self, &info->anchor,
11443                                   &old_anchor_x,
11444                                   &old_anchor_y,
11445                                   NULL);
11446
11447   g_object_freeze_notify (G_OBJECT (self));
11448
11449   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11450
11451   if (self->priv->position_set)
11452     clutter_actor_move_by (self,
11453                            anchor_x - old_anchor_x,
11454                            anchor_y - old_anchor_y);
11455
11456   g_object_thaw_notify (G_OBJECT (self));
11457 }
11458
11459 /**
11460  * clutter_actor_move_anchor_point_from_gravity:
11461  * @self: a #ClutterActor
11462  * @gravity: #ClutterGravity.
11463  *
11464  * Sets an anchor point on the actor based on the given gravity, adjusting the
11465  * actor postion so that its relative position within its parent remains
11466  * unchanged.
11467  *
11468  * Since version 1.0 the anchor point will be stored as a gravity so
11469  * that if the actor changes size then the anchor point will move. For
11470  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11471  * and later double the size of the actor, the anchor point will move
11472  * to the bottom right.
11473  *
11474  * Since: 0.6
11475  */
11476 void
11477 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11478                                               ClutterGravity  gravity)
11479 {
11480   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11481   const ClutterTransformInfo *info;
11482   ClutterActorPrivate *priv;
11483
11484   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11485
11486   priv = self->priv;
11487   info = _clutter_actor_get_transform_info (self);
11488
11489   g_object_freeze_notify (G_OBJECT (self));
11490
11491   clutter_anchor_coord_get_units (self, &info->anchor,
11492                                   &old_anchor_x,
11493                                   &old_anchor_y,
11494                                   NULL);
11495   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11496   clutter_anchor_coord_get_units (self, &info->anchor,
11497                                   &new_anchor_x,
11498                                   &new_anchor_y,
11499                                   NULL);
11500
11501   if (priv->position_set)
11502     clutter_actor_move_by (self,
11503                            new_anchor_x - old_anchor_x,
11504                            new_anchor_y - old_anchor_y);
11505
11506   g_object_thaw_notify (G_OBJECT (self));
11507 }
11508
11509 /**
11510  * clutter_actor_set_anchor_point_from_gravity:
11511  * @self: a #ClutterActor
11512  * @gravity: #ClutterGravity.
11513  *
11514  * Sets an anchor point on the actor, based on the given gravity (this is a
11515  * convenience function wrapping clutter_actor_set_anchor_point()).
11516  *
11517  * Since version 1.0 the anchor point will be stored as a gravity so
11518  * that if the actor changes size then the anchor point will move. For
11519  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11520  * and later double the size of the actor, the anchor point will move
11521  * to the bottom right.
11522  *
11523  * Since: 0.6
11524  */
11525 void
11526 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11527                                              ClutterGravity  gravity)
11528 {
11529   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11530
11531   if (gravity == CLUTTER_GRAVITY_NONE)
11532     clutter_actor_set_anchor_point (self, 0, 0);
11533   else
11534     {
11535       GObject *obj = G_OBJECT (self);
11536       ClutterTransformInfo *info;
11537
11538       g_object_freeze_notify (obj);
11539
11540       info = _clutter_actor_get_transform_info (self);
11541       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11542
11543       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11544       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11545       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11546
11547       self->priv->transform_valid = FALSE;
11548
11549       clutter_actor_queue_redraw (self);
11550
11551       g_object_thaw_notify (obj);
11552     }
11553 }
11554
11555 static void
11556 clutter_container_iface_init (ClutterContainerIface *iface)
11557 {
11558   /* we don't override anything, as ClutterContainer already has a default
11559    * implementation that we can use, and which calls into our own API.
11560    */
11561 }
11562
11563 typedef enum
11564 {
11565   PARSE_X,
11566   PARSE_Y,
11567   PARSE_WIDTH,
11568   PARSE_HEIGHT,
11569   PARSE_ANCHOR_X,
11570   PARSE_ANCHOR_Y
11571 } ParseDimension;
11572
11573 static gfloat
11574 parse_units (ClutterActor   *self,
11575              ParseDimension  dimension,
11576              JsonNode       *node)
11577 {
11578   GValue value = { 0, };
11579   gfloat retval = 0;
11580
11581   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11582     return 0;
11583
11584   json_node_get_value (node, &value);
11585
11586   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11587     {
11588       retval = (gfloat) g_value_get_int64 (&value);
11589     }
11590   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
11591     {
11592       retval = g_value_get_double (&value);
11593     }
11594   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
11595     {
11596       ClutterUnits units;
11597       gboolean res;
11598
11599       res = clutter_units_from_string (&units, g_value_get_string (&value));
11600       if (res)
11601         retval = clutter_units_to_pixels (&units);
11602       else
11603         {
11604           g_warning ("Invalid value '%s': integers, strings or floating point "
11605                      "values can be used for the x, y, width and height "
11606                      "properties. Valid modifiers for strings are 'px', 'mm', "
11607                      "'pt' and 'em'.",
11608                      g_value_get_string (&value));
11609           retval = 0;
11610         }
11611     }
11612   else
11613     {
11614       g_warning ("Invalid value of type '%s': integers, strings of floating "
11615                  "point values can be used for the x, y, width, height "
11616                  "anchor-x and anchor-y properties.",
11617                  g_type_name (G_VALUE_TYPE (&value)));
11618     }
11619
11620   g_value_unset (&value);
11621
11622   return retval;
11623 }
11624
11625 typedef struct {
11626   ClutterRotateAxis axis;
11627
11628   gdouble angle;
11629
11630   gfloat center_x;
11631   gfloat center_y;
11632   gfloat center_z;
11633 } RotationInfo;
11634
11635 static inline gboolean
11636 parse_rotation_array (ClutterActor *actor,
11637                       JsonArray    *array,
11638                       RotationInfo *info)
11639 {
11640   JsonNode *element;
11641
11642   if (json_array_get_length (array) != 2)
11643     return FALSE;
11644
11645   /* angle */
11646   element = json_array_get_element (array, 0);
11647   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
11648     info->angle = json_node_get_double (element);
11649   else
11650     return FALSE;
11651
11652   /* center */
11653   element = json_array_get_element (array, 1);
11654   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
11655     {
11656       JsonArray *center = json_node_get_array (element);
11657
11658       if (json_array_get_length (center) != 2)
11659         return FALSE;
11660
11661       switch (info->axis)
11662         {
11663         case CLUTTER_X_AXIS:
11664           info->center_y = parse_units (actor, PARSE_Y,
11665                                         json_array_get_element (center, 0));
11666           info->center_z = parse_units (actor, PARSE_Y,
11667                                         json_array_get_element (center, 1));
11668           return TRUE;
11669
11670         case CLUTTER_Y_AXIS:
11671           info->center_x = parse_units (actor, PARSE_X,
11672                                         json_array_get_element (center, 0));
11673           info->center_z = parse_units (actor, PARSE_X,
11674                                         json_array_get_element (center, 1));
11675           return TRUE;
11676
11677         case CLUTTER_Z_AXIS:
11678           info->center_x = parse_units (actor, PARSE_X,
11679                                         json_array_get_element (center, 0));
11680           info->center_y = parse_units (actor, PARSE_Y,
11681                                         json_array_get_element (center, 1));
11682           return TRUE;
11683         }
11684     }
11685
11686   return FALSE;
11687 }
11688
11689 static gboolean
11690 parse_rotation (ClutterActor *actor,
11691                 JsonNode     *node,
11692                 RotationInfo *info)
11693 {
11694   JsonArray *array;
11695   guint len, i;
11696   gboolean retval = FALSE;
11697
11698   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
11699     {
11700       g_warning ("Invalid node of type '%s' found, expecting an array",
11701                  json_node_type_name (node));
11702       return FALSE;
11703     }
11704
11705   array = json_node_get_array (node);
11706   len = json_array_get_length (array);
11707
11708   for (i = 0; i < len; i++)
11709     {
11710       JsonNode *element = json_array_get_element (array, i);
11711       JsonObject *object;
11712       JsonNode *member;
11713
11714       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
11715         {
11716           g_warning ("Invalid node of type '%s' found, expecting an object",
11717                      json_node_type_name (element));
11718           return FALSE;
11719         }
11720
11721       object = json_node_get_object (element);
11722
11723       if (json_object_has_member (object, "x-axis"))
11724         {
11725           member = json_object_get_member (object, "x-axis");
11726
11727           info->axis = CLUTTER_X_AXIS;
11728
11729           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11730             {
11731               info->angle = json_node_get_double (member);
11732               retval = TRUE;
11733             }
11734           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11735             retval = parse_rotation_array (actor,
11736                                            json_node_get_array (member),
11737                                            info);
11738           else
11739             retval = FALSE;
11740         }
11741       else if (json_object_has_member (object, "y-axis"))
11742         {
11743           member = json_object_get_member (object, "y-axis");
11744
11745           info->axis = CLUTTER_Y_AXIS;
11746
11747           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11748             {
11749               info->angle = json_node_get_double (member);
11750               retval = TRUE;
11751             }
11752           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11753             retval = parse_rotation_array (actor,
11754                                            json_node_get_array (member),
11755                                            info);
11756           else
11757             retval = FALSE;
11758         }
11759       else if (json_object_has_member (object, "z-axis"))
11760         {
11761           member = json_object_get_member (object, "z-axis");
11762
11763           info->axis = CLUTTER_Z_AXIS;
11764
11765           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11766             {
11767               info->angle = json_node_get_double (member);
11768               retval = TRUE;
11769             }
11770           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11771             retval = parse_rotation_array (actor,
11772                                            json_node_get_array (member),
11773                                            info);
11774           else
11775             retval = FALSE;
11776         }
11777     }
11778
11779   return retval;
11780 }
11781
11782 static GSList *
11783 parse_actor_metas (ClutterScript *script,
11784                    ClutterActor  *actor,
11785                    JsonNode      *node)
11786 {
11787   GList *elements, *l;
11788   GSList *retval = NULL;
11789
11790   if (!JSON_NODE_HOLDS_ARRAY (node))
11791     return NULL;
11792
11793   elements = json_array_get_elements (json_node_get_array (node));
11794
11795   for (l = elements; l != NULL; l = l->next)
11796     {
11797       JsonNode *element = l->data;
11798       const gchar *id_ = _clutter_script_get_id_from_node (element);
11799       GObject *meta;
11800
11801       if (id_ == NULL || *id_ == '\0')
11802         continue;
11803
11804       meta = clutter_script_get_object (script, id_);
11805       if (meta == NULL)
11806         continue;
11807
11808       retval = g_slist_prepend (retval, meta);
11809     }
11810
11811   g_list_free (elements);
11812
11813   return g_slist_reverse (retval);
11814 }
11815
11816 static GSList *
11817 parse_behaviours (ClutterScript *script,
11818                   ClutterActor  *actor,
11819                   JsonNode      *node)
11820 {
11821   GList *elements, *l;
11822   GSList *retval = NULL;
11823
11824   if (!JSON_NODE_HOLDS_ARRAY (node))
11825     return NULL;
11826
11827   elements = json_array_get_elements (json_node_get_array (node));
11828
11829   for (l = elements; l != NULL; l = l->next)
11830     {
11831       JsonNode *element = l->data;
11832       const gchar *id_ = _clutter_script_get_id_from_node (element);
11833       GObject *behaviour;
11834
11835       if (id_ == NULL || *id_ == '\0')
11836         continue;
11837
11838       behaviour = clutter_script_get_object (script, id_);
11839       if (behaviour == NULL)
11840         continue;
11841
11842       retval = g_slist_prepend (retval, behaviour);
11843     }
11844
11845   g_list_free (elements);
11846
11847   return g_slist_reverse (retval);
11848 }
11849
11850 static gboolean
11851 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
11852                                  ClutterScript     *script,
11853                                  GValue            *value,
11854                                  const gchar       *name,
11855                                  JsonNode          *node)
11856 {
11857   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11858   gboolean retval = FALSE;
11859
11860   if ((name[0] == 'x' && name[1] == '\0') ||
11861       (name[0] == 'y' && name[1] == '\0') ||
11862       (strcmp (name, "width") == 0) ||
11863       (strcmp (name, "height") == 0) ||
11864       (strcmp (name, "anchor_x") == 0) ||
11865       (strcmp (name, "anchor_y") == 0))
11866     {
11867       ParseDimension dimension;
11868       gfloat units;
11869
11870       if (name[0] == 'x')
11871         dimension = PARSE_X;
11872       else if (name[0] == 'y')
11873         dimension = PARSE_Y;
11874       else if (name[0] == 'w')
11875         dimension = PARSE_WIDTH;
11876       else if (name[0] == 'h')
11877         dimension = PARSE_HEIGHT;
11878       else if (name[0] == 'a' && name[7] == 'x')
11879         dimension = PARSE_ANCHOR_X;
11880       else if (name[0] == 'a' && name[7] == 'y')
11881         dimension = PARSE_ANCHOR_Y;
11882       else
11883         return FALSE;
11884
11885       units = parse_units (actor, dimension, node);
11886
11887       /* convert back to pixels: all properties are pixel-based */
11888       g_value_init (value, G_TYPE_FLOAT);
11889       g_value_set_float (value, units);
11890
11891       retval = TRUE;
11892     }
11893   else if (strcmp (name, "rotation") == 0)
11894     {
11895       RotationInfo *info;
11896
11897       info = g_slice_new0 (RotationInfo);
11898       retval = parse_rotation (actor, node, info);
11899
11900       if (retval)
11901         {
11902           g_value_init (value, G_TYPE_POINTER);
11903           g_value_set_pointer (value, info);
11904         }
11905       else
11906         g_slice_free (RotationInfo, info);
11907     }
11908   else if (strcmp (name, "behaviours") == 0)
11909     {
11910       GSList *l;
11911
11912 #ifdef CLUTTER_ENABLE_DEBUG
11913       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
11914         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
11915                                      "and it should not be used in newly "
11916                                      "written ClutterScript definitions.");
11917 #endif
11918
11919       l = parse_behaviours (script, actor, node);
11920
11921       g_value_init (value, G_TYPE_POINTER);
11922       g_value_set_pointer (value, l);
11923
11924       retval = TRUE;
11925     }
11926   else if (strcmp (name, "actions") == 0 ||
11927            strcmp (name, "constraints") == 0 ||
11928            strcmp (name, "effects") == 0)
11929     {
11930       GSList *l;
11931
11932       l = parse_actor_metas (script, actor, node);
11933
11934       g_value_init (value, G_TYPE_POINTER);
11935       g_value_set_pointer (value, l);
11936
11937       retval = TRUE;
11938     }
11939
11940   return retval;
11941 }
11942
11943 static void
11944 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
11945                                    ClutterScript     *script,
11946                                    const gchar       *name,
11947                                    const GValue      *value)
11948 {
11949   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11950
11951 #ifdef CLUTTER_ENABLE_DEBUG
11952   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
11953     {
11954       gchar *tmp = g_strdup_value_contents (value);
11955
11956       CLUTTER_NOTE (SCRIPT,
11957                     "in ClutterActor::set_custom_property('%s') = %s",
11958                     name,
11959                     tmp);
11960
11961       g_free (tmp);
11962     }
11963 #endif /* CLUTTER_ENABLE_DEBUG */
11964
11965   if (strcmp (name, "rotation") == 0)
11966     {
11967       RotationInfo *info;
11968
11969       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11970         return;
11971
11972       info = g_value_get_pointer (value);
11973
11974       clutter_actor_set_rotation (actor,
11975                                   info->axis, info->angle,
11976                                   info->center_x,
11977                                   info->center_y,
11978                                   info->center_z);
11979
11980       g_slice_free (RotationInfo, info);
11981
11982       return;
11983     }
11984
11985   if (strcmp (name, "behaviours") == 0)
11986     {
11987       GSList *behaviours, *l;
11988
11989       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11990         return;
11991
11992       behaviours = g_value_get_pointer (value);
11993       for (l = behaviours; l != NULL; l = l->next)
11994         {
11995           ClutterBehaviour *behaviour = l->data;
11996
11997           clutter_behaviour_apply (behaviour, actor);
11998         }
11999
12000       g_slist_free (behaviours);
12001
12002       return;
12003     }
12004
12005   if (strcmp (name, "actions") == 0 ||
12006       strcmp (name, "constraints") == 0 ||
12007       strcmp (name, "effects") == 0)
12008     {
12009       GSList *metas, *l;
12010
12011       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12012         return;
12013
12014       metas = g_value_get_pointer (value);
12015       for (l = metas; l != NULL; l = l->next)
12016         {
12017           if (name[0] == 'a')
12018             clutter_actor_add_action (actor, l->data);
12019
12020           if (name[0] == 'c')
12021             clutter_actor_add_constraint (actor, l->data);
12022
12023           if (name[0] == 'e')
12024             clutter_actor_add_effect (actor, l->data);
12025         }
12026
12027       g_slist_free (metas);
12028
12029       return;
12030     }
12031
12032   g_object_set_property (G_OBJECT (scriptable), name, value);
12033 }
12034
12035 static void
12036 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12037 {
12038   iface->parse_custom_node = clutter_actor_parse_custom_node;
12039   iface->set_custom_property = clutter_actor_set_custom_property;
12040 }
12041
12042 static ClutterActorMeta *
12043 get_meta_from_animation_property (ClutterActor  *actor,
12044                                   const gchar   *name,
12045                                   gchar        **name_p)
12046 {
12047   ClutterActorPrivate *priv = actor->priv;
12048   ClutterActorMeta *meta = NULL;
12049   gchar **tokens;
12050
12051   /* if this is not a special property, fall through */
12052   if (name[0] != '@')
12053     return NULL;
12054
12055   /* detect the properties named using the following spec:
12056    *
12057    *   @<section>.<meta-name>.<property-name>
12058    *
12059    * where <section> can be one of the following:
12060    *
12061    *   - actions
12062    *   - constraints
12063    *   - effects
12064    *
12065    * and <meta-name> is the name set on a specific ActorMeta
12066    */
12067
12068   tokens = g_strsplit (name + 1, ".", -1);
12069   if (tokens == NULL || g_strv_length (tokens) != 3)
12070     {
12071       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12072                     name + 1);
12073       g_strfreev (tokens);
12074       return NULL;
12075     }
12076
12077   if (strcmp (tokens[0], "actions") == 0)
12078     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12079
12080   if (strcmp (tokens[0], "constraints") == 0)
12081     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12082
12083   if (strcmp (tokens[0], "effects") == 0)
12084     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12085
12086   if (name_p != NULL)
12087     *name_p = g_strdup (tokens[2]);
12088
12089   CLUTTER_NOTE (ANIMATION,
12090                 "Looking for property '%s' of object '%s' in section '%s'",
12091                 tokens[2],
12092                 tokens[1],
12093                 tokens[0]);
12094
12095   g_strfreev (tokens);
12096
12097   return meta;
12098 }
12099
12100 static GParamSpec *
12101 clutter_actor_find_property (ClutterAnimatable *animatable,
12102                              const gchar       *property_name)
12103 {
12104   ClutterActorMeta *meta = NULL;
12105   GObjectClass *klass = NULL;
12106   GParamSpec *pspec = NULL;
12107   gchar *p_name = NULL;
12108
12109   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12110                                            property_name,
12111                                            &p_name);
12112
12113   if (meta != NULL)
12114     {
12115       klass = G_OBJECT_GET_CLASS (meta);
12116
12117       pspec = g_object_class_find_property (klass, p_name);
12118     }
12119   else
12120     {
12121       klass = G_OBJECT_GET_CLASS (animatable);
12122
12123       pspec = g_object_class_find_property (klass, property_name);
12124     }
12125
12126   g_free (p_name);
12127
12128   return pspec;
12129 }
12130
12131 static void
12132 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12133                                  const gchar       *property_name,
12134                                  GValue            *initial)
12135 {
12136   ClutterActorMeta *meta = NULL;
12137   gchar *p_name = NULL;
12138
12139   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12140                                            property_name,
12141                                            &p_name);
12142
12143   if (meta != NULL)
12144     g_object_get_property (G_OBJECT (meta), p_name, initial);
12145   else
12146     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12147
12148   g_free (p_name);
12149 }
12150
12151 static void
12152 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12153                                const gchar       *property_name,
12154                                const GValue      *final)
12155 {
12156   ClutterActorMeta *meta = NULL;
12157   gchar *p_name = NULL;
12158
12159   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12160                                            property_name,
12161                                            &p_name);
12162   if (meta != NULL)
12163     g_object_set_property (G_OBJECT (meta), p_name, final);
12164   else
12165     g_object_set_property (G_OBJECT (animatable), property_name, final);
12166
12167   g_free (p_name);
12168 }
12169
12170 static void
12171 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12172 {
12173   iface->find_property = clutter_actor_find_property;
12174   iface->get_initial_state = clutter_actor_get_initial_state;
12175   iface->set_final_state = clutter_actor_set_final_state;
12176 }
12177
12178 /**
12179  * clutter_actor_transform_stage_point:
12180  * @self: A #ClutterActor
12181  * @x: (in): x screen coordinate of the point to unproject
12182  * @y: (in): y screen coordinate of the point to unproject
12183  * @x_out: (out): return location for the unprojected x coordinance
12184  * @y_out: (out): return location for the unprojected y coordinance
12185  *
12186  * This function translates screen coordinates (@x, @y) to
12187  * coordinates relative to the actor. For example, it can be used to translate
12188  * screen events from global screen coordinates into actor-local coordinates.
12189  *
12190  * The conversion can fail, notably if the transform stack results in the
12191  * actor being projected on the screen as a mere line.
12192  *
12193  * The conversion should not be expected to be pixel-perfect due to the
12194  * nature of the operation. In general the error grows when the skewing
12195  * of the actor rectangle on screen increases.
12196  *
12197  * <note><para>This function can be computationally intensive.</para></note>
12198  *
12199  * <note><para>This function only works when the allocation is up-to-date,
12200  * i.e. inside of paint().</para></note>
12201  *
12202  * Return value: %TRUE if conversion was successful.
12203  *
12204  * Since: 0.6
12205  */
12206 gboolean
12207 clutter_actor_transform_stage_point (ClutterActor *self,
12208                                      gfloat        x,
12209                                      gfloat        y,
12210                                      gfloat       *x_out,
12211                                      gfloat       *y_out)
12212 {
12213   ClutterVertex v[4];
12214   float ST[3][3];
12215   float RQ[3][3];
12216   int du, dv, xi, yi;
12217   float px, py;
12218   float xf, yf, wf, det;
12219   ClutterActorPrivate *priv;
12220
12221   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12222
12223   priv = self->priv;
12224
12225   /* This implementation is based on the quad -> quad projection algorithm
12226    * described by Paul Heckbert in:
12227    *
12228    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12229    *
12230    * and the sample implementation at:
12231    *
12232    *   http://www.cs.cmu.edu/~ph/src/texfund/
12233    *
12234    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12235    * quad to rectangle only, which significantly simplifies things; the
12236    * function calls have been unrolled, and most of the math is done in fixed
12237    * point.
12238    */
12239
12240   clutter_actor_get_abs_allocation_vertices (self, v);
12241
12242   /* Keeping these as ints simplifies the multiplication (no significant
12243    * loss of precision here).
12244    */
12245   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12246   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12247
12248   if (!du || !dv)
12249     return FALSE;
12250
12251 #define UX2FP(x)        (x)
12252 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12253
12254   /* First, find mapping from unit uv square to xy quadrilateral; this
12255    * equivalent to the pmap_square_quad() functions in the sample
12256    * implementation, which we can simplify, since our target is always
12257    * a rectangle.
12258    */
12259   px = v[0].x - v[1].x + v[3].x - v[2].x;
12260   py = v[0].y - v[1].y + v[3].y - v[2].y;
12261
12262   if (!px && !py)
12263     {
12264       /* affine transform */
12265       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12266       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12267       RQ[2][0] = UX2FP (v[0].x);
12268       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12269       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12270       RQ[2][1] = UX2FP (v[0].y);
12271       RQ[0][2] = 0;
12272       RQ[1][2] = 0;
12273       RQ[2][2] = 1.0;
12274     }
12275   else
12276     {
12277       /* projective transform */
12278       double dx1, dx2, dy1, dy2, del;
12279
12280       dx1 = UX2FP (v[1].x - v[3].x);
12281       dx2 = UX2FP (v[2].x - v[3].x);
12282       dy1 = UX2FP (v[1].y - v[3].y);
12283       dy2 = UX2FP (v[2].y - v[3].y);
12284
12285       del = DET2FP (dx1, dx2, dy1, dy2);
12286       if (!del)
12287         return FALSE;
12288
12289       /*
12290        * The division here needs to be done in floating point for
12291        * precisions reasons.
12292        */
12293       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12294       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12295       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12296       RQ[2][2] = 1.0;
12297       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12298       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12299       RQ[2][0] = UX2FP (v[0].x);
12300       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12301       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12302       RQ[2][1] = UX2FP (v[0].y);
12303     }
12304
12305   /*
12306    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12307    * square. Since our rectangle is based at 0,0 we only need to scale.
12308    */
12309   RQ[0][0] /= du;
12310   RQ[1][0] /= dv;
12311   RQ[0][1] /= du;
12312   RQ[1][1] /= dv;
12313   RQ[0][2] /= du;
12314   RQ[1][2] /= dv;
12315
12316   /*
12317    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12318    * inverse of that.
12319    */
12320   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12321   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12322   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12323   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12324   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12325   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12326   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12327   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12328   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12329
12330   /*
12331    * Check the resulting matrix is OK.
12332    */
12333   det = (RQ[0][0] * ST[0][0])
12334       + (RQ[0][1] * ST[0][1])
12335       + (RQ[0][2] * ST[0][2]);
12336   if (!det)
12337     return FALSE;
12338
12339   /*
12340    * Now transform our point with the ST matrix; the notional w
12341    * coordinate is 1, hence the last part is simply added.
12342    */
12343   xi = (int) x;
12344   yi = (int) y;
12345
12346   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12347   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12348   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12349
12350   if (x_out)
12351     *x_out = xf / wf;
12352
12353   if (y_out)
12354     *y_out = yf / wf;
12355
12356 #undef UX2FP
12357 #undef DET2FP
12358
12359   return TRUE;
12360 }
12361
12362 /*
12363  * ClutterGeometry
12364  */
12365
12366 static ClutterGeometry*
12367 clutter_geometry_copy (const ClutterGeometry *geometry)
12368 {
12369   return g_slice_dup (ClutterGeometry, geometry);
12370 }
12371
12372 static void
12373 clutter_geometry_free (ClutterGeometry *geometry)
12374 {
12375   if (G_LIKELY (geometry != NULL))
12376     g_slice_free (ClutterGeometry, geometry);
12377 }
12378
12379 /**
12380  * clutter_geometry_union:
12381  * @geometry_a: a #ClutterGeometry
12382  * @geometry_b: another #ClutterGeometry
12383  * @result: (out): location to store the result
12384  *
12385  * Find the union of two rectangles represented as #ClutterGeometry.
12386  *
12387  * Since: 1.4
12388  */
12389 void
12390 clutter_geometry_union (const ClutterGeometry *geometry_a,
12391                         const ClutterGeometry *geometry_b,
12392                         ClutterGeometry       *result)
12393 {
12394   /* We don't try to handle rectangles that can't be represented
12395    * as a signed integer box */
12396   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12397   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12398   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12399                   geometry_b->x + (gint)geometry_b->width);
12400   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12401                   geometry_b->y + (gint)geometry_b->height);
12402   result->x = x_1;
12403   result->y = y_1;
12404   result->width = x_2 - x_1;
12405   result->height = y_2 - y_1;
12406 }
12407
12408 /**
12409  * clutter_geometry_intersects:
12410  * @geometry0: The first geometry to test
12411  * @geometry1: The second geometry to test
12412  *
12413  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12414  * they do else %FALSE.
12415  *
12416  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12417  * %FALSE.
12418  *
12419  * Since: 1.4
12420  */
12421 gboolean
12422 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12423                              const ClutterGeometry *geometry1)
12424 {
12425   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12426       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12427       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12428       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12429     return FALSE;
12430   else
12431     return TRUE;
12432 }
12433
12434 static gboolean
12435 clutter_geometry_progress (const GValue *a,
12436                            const GValue *b,
12437                            gdouble       progress,
12438                            GValue       *retval)
12439 {
12440   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12441   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12442   ClutterGeometry res = { 0, };
12443   gint a_width = a_geom->width;
12444   gint b_width = b_geom->width;
12445   gint a_height = a_geom->height;
12446   gint b_height = b_geom->height;
12447
12448   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12449   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12450
12451   res.width = a_width + (b_width - a_width) * progress;
12452   res.height = a_height + (b_height - a_height) * progress;
12453
12454   g_value_set_boxed (retval, &res);
12455
12456   return TRUE;
12457 }
12458
12459 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12460                                clutter_geometry_copy,
12461                                clutter_geometry_free,
12462                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12463
12464 /*
12465  * ClutterVertices
12466  */
12467
12468 /**
12469  * clutter_vertex_new:
12470  * @x: X coordinate
12471  * @y: Y coordinate
12472  * @z: Z coordinate
12473  *
12474  * Creates a new #ClutterVertex for the point in 3D space
12475  * identified by the 3 coordinates @x, @y, @z
12476  *
12477  * Return value: the newly allocate #ClutterVertex. Use
12478  *   clutter_vertex_free() to free the resources
12479  *
12480  * Since: 1.0
12481  */
12482 ClutterVertex *
12483 clutter_vertex_new (gfloat x,
12484                     gfloat y,
12485                     gfloat z)
12486 {
12487   ClutterVertex *vertex;
12488
12489   vertex = g_slice_new (ClutterVertex);
12490   vertex->x = x;
12491   vertex->y = y;
12492   vertex->z = z;
12493
12494   return vertex;
12495 }
12496
12497 /**
12498  * clutter_vertex_copy:
12499  * @vertex: a #ClutterVertex
12500  *
12501  * Copies @vertex
12502  *
12503  * Return value: a newly allocated copy of #ClutterVertex. Use
12504  *   clutter_vertex_free() to free the allocated resources
12505  *
12506  * Since: 1.0
12507  */
12508 ClutterVertex *
12509 clutter_vertex_copy (const ClutterVertex *vertex)
12510 {
12511   if (G_LIKELY (vertex != NULL))
12512     return g_slice_dup (ClutterVertex, vertex);
12513
12514   return NULL;
12515 }
12516
12517 /**
12518  * clutter_vertex_free:
12519  * @vertex: a #ClutterVertex
12520  *
12521  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
12522  *
12523  * Since: 1.0
12524  */
12525 void
12526 clutter_vertex_free (ClutterVertex *vertex)
12527 {
12528   if (G_UNLIKELY (vertex != NULL))
12529     g_slice_free (ClutterVertex, vertex);
12530 }
12531
12532 /**
12533  * clutter_vertex_equal:
12534  * @vertex_a: a #ClutterVertex
12535  * @vertex_b: a #ClutterVertex
12536  *
12537  * Compares @vertex_a and @vertex_b for equality
12538  *
12539  * Return value: %TRUE if the passed #ClutterVertex are equal
12540  *
12541  * Since: 1.0
12542  */
12543 gboolean
12544 clutter_vertex_equal (const ClutterVertex *vertex_a,
12545                       const ClutterVertex *vertex_b)
12546 {
12547   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
12548
12549   if (vertex_a == vertex_b)
12550     return TRUE;
12551
12552   return vertex_a->x == vertex_b->x &&
12553          vertex_a->y == vertex_b->y &&
12554          vertex_a->z == vertex_b->z;
12555 }
12556
12557 static gboolean
12558 clutter_vertex_progress (const GValue *a,
12559                          const GValue *b,
12560                          gdouble       progress,
12561                          GValue       *retval)
12562 {
12563   const ClutterVertex *av = g_value_get_boxed (a);
12564   const ClutterVertex *bv = g_value_get_boxed (b);
12565   ClutterVertex res = { 0, };
12566
12567   res.x = av->x + (bv->x - av->x) * progress;
12568   res.y = av->y + (bv->y - av->y) * progress;
12569   res.z = av->z + (bv->z - av->z) * progress;
12570
12571   g_value_set_boxed (retval, &res);
12572
12573   return TRUE;
12574 }
12575
12576 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
12577                                clutter_vertex_copy,
12578                                clutter_vertex_free,
12579                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
12580
12581 /**
12582  * clutter_actor_is_rotated:
12583  * @self: a #ClutterActor
12584  *
12585  * Checks whether any rotation is applied to the actor.
12586  *
12587  * Return value: %TRUE if the actor is rotated.
12588  *
12589  * Since: 0.6
12590  */
12591 gboolean
12592 clutter_actor_is_rotated (ClutterActor *self)
12593 {
12594   const ClutterTransformInfo *info;
12595
12596   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12597
12598   info = _clutter_actor_get_transform_info_or_defaults (self);
12599
12600   if (info->rx_angle || info->ry_angle || info->rz_angle)
12601     return TRUE;
12602
12603   return FALSE;
12604 }
12605
12606 /**
12607  * clutter_actor_is_scaled:
12608  * @self: a #ClutterActor
12609  *
12610  * Checks whether the actor is scaled in either dimension.
12611  *
12612  * Return value: %TRUE if the actor is scaled.
12613  *
12614  * Since: 0.6
12615  */
12616 gboolean
12617 clutter_actor_is_scaled (ClutterActor *self)
12618 {
12619   const ClutterTransformInfo *info;
12620
12621   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12622
12623   info = _clutter_actor_get_transform_info_or_defaults (self);
12624
12625   if (info->scale_x != 1.0 || info->scale_y != 1.0)
12626     return TRUE;
12627
12628   return FALSE;
12629 }
12630
12631 ClutterActor *
12632 _clutter_actor_get_stage_internal (ClutterActor *actor)
12633 {
12634   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
12635     actor = actor->priv->parent;
12636
12637   return actor;
12638 }
12639
12640 /**
12641  * clutter_actor_get_stage:
12642  * @actor: a #ClutterActor
12643  *
12644  * Retrieves the #ClutterStage where @actor is contained.
12645  *
12646  * Return value: (transfer none) (type Clutter.Stage): the stage
12647  *   containing the actor, or %NULL
12648  *
12649  * Since: 0.8
12650  */
12651 ClutterActor *
12652 clutter_actor_get_stage (ClutterActor *actor)
12653 {
12654   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
12655
12656   return _clutter_actor_get_stage_internal (actor);
12657 }
12658
12659 /**
12660  * clutter_actor_allocate_available_size:
12661  * @self: a #ClutterActor
12662  * @x: the actor's X coordinate
12663  * @y: the actor's Y coordinate
12664  * @available_width: the maximum available width, or -1 to use the
12665  *   actor's natural width
12666  * @available_height: the maximum available height, or -1 to use the
12667  *   actor's natural height
12668  * @flags: flags controlling the allocation
12669  *
12670  * Allocates @self taking into account the #ClutterActor<!-- -->'s
12671  * preferred size, but limiting it to the maximum available width
12672  * and height provided.
12673  *
12674  * This function will do the right thing when dealing with the
12675  * actor's request mode.
12676  *
12677  * The implementation of this function is equivalent to:
12678  *
12679  * |[
12680  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12681  *     {
12682  *       clutter_actor_get_preferred_width (self, available_height,
12683  *                                          &amp;min_width,
12684  *                                          &amp;natural_width);
12685  *       width = CLAMP (natural_width, min_width, available_width);
12686  *
12687  *       clutter_actor_get_preferred_height (self, width,
12688  *                                           &amp;min_height,
12689  *                                           &amp;natural_height);
12690  *       height = CLAMP (natural_height, min_height, available_height);
12691  *     }
12692  *   else
12693  *     {
12694  *       clutter_actor_get_preferred_height (self, available_width,
12695  *                                           &amp;min_height,
12696  *                                           &amp;natural_height);
12697  *       height = CLAMP (natural_height, min_height, available_height);
12698  *
12699  *       clutter_actor_get_preferred_width (self, height,
12700  *                                          &amp;min_width,
12701  *                                          &amp;natural_width);
12702  *       width = CLAMP (natural_width, min_width, available_width);
12703  *     }
12704  *
12705  *   box.x1 = x; box.y1 = y;
12706  *   box.x2 = box.x1 + available_width;
12707  *   box.y2 = box.y1 + available_height;
12708  *   clutter_actor_allocate (self, &amp;box, flags);
12709  * ]|
12710  *
12711  * This function can be used by fluid layout managers to allocate
12712  * an actor's preferred size without making it bigger than the area
12713  * available for the container.
12714  *
12715  * Since: 1.0
12716  */
12717 void
12718 clutter_actor_allocate_available_size (ClutterActor           *self,
12719                                        gfloat                  x,
12720                                        gfloat                  y,
12721                                        gfloat                  available_width,
12722                                        gfloat                  available_height,
12723                                        ClutterAllocationFlags  flags)
12724 {
12725   ClutterActorPrivate *priv;
12726   gfloat width, height;
12727   gfloat min_width, min_height;
12728   gfloat natural_width, natural_height;
12729   ClutterActorBox box;
12730
12731   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12732
12733   priv = self->priv;
12734
12735   width = height = 0.0;
12736
12737   switch (priv->request_mode)
12738     {
12739     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
12740       clutter_actor_get_preferred_width (self, available_height,
12741                                          &min_width,
12742                                          &natural_width);
12743       width  = CLAMP (natural_width, min_width, available_width);
12744
12745       clutter_actor_get_preferred_height (self, width,
12746                                           &min_height,
12747                                           &natural_height);
12748       height = CLAMP (natural_height, min_height, available_height);
12749       break;
12750
12751     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
12752       clutter_actor_get_preferred_height (self, available_width,
12753                                           &min_height,
12754                                           &natural_height);
12755       height = CLAMP (natural_height, min_height, available_height);
12756
12757       clutter_actor_get_preferred_width (self, height,
12758                                          &min_width,
12759                                          &natural_width);
12760       width  = CLAMP (natural_width, min_width, available_width);
12761       break;
12762     }
12763
12764
12765   box.x1 = x;
12766   box.y1 = y;
12767   box.x2 = box.x1 + width;
12768   box.y2 = box.y1 + height;
12769   clutter_actor_allocate (self, &box, flags);
12770 }
12771
12772 /**
12773  * clutter_actor_allocate_preferred_size:
12774  * @self: a #ClutterActor
12775  * @flags: flags controlling the allocation
12776  *
12777  * Allocates the natural size of @self.
12778  *
12779  * This function is a utility call for #ClutterActor implementations
12780  * that allocates the actor's preferred natural size. It can be used
12781  * by fixed layout managers (like #ClutterGroup or so called
12782  * 'composite actors') inside the ClutterActor::allocate
12783  * implementation to give each child exactly how much space it
12784  * requires.
12785  *
12786  * This function is not meant to be used by applications. It is also
12787  * not meant to be used outside the implementation of the
12788  * ClutterActor::allocate virtual function.
12789  *
12790  * Since: 0.8
12791  */
12792 void
12793 clutter_actor_allocate_preferred_size (ClutterActor           *self,
12794                                        ClutterAllocationFlags  flags)
12795 {
12796   gfloat actor_x, actor_y;
12797   gfloat natural_width, natural_height;
12798   ClutterActorBox actor_box;
12799
12800   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12801
12802   actor_x = clutter_actor_get_x (self);
12803   actor_y = clutter_actor_get_y (self);
12804
12805   clutter_actor_get_preferred_size (self,
12806                                     NULL, NULL,
12807                                     &natural_width,
12808                                     &natural_height);
12809
12810   actor_box.x1 = actor_x;
12811   actor_box.y1 = actor_y;
12812   actor_box.x2 = actor_box.x1 + natural_width;
12813   actor_box.y2 = actor_box.y1 + natural_height;
12814
12815   clutter_actor_allocate (self, &actor_box, flags);
12816 }
12817
12818 /**
12819  * clutter_actor_allocate_align_fill:
12820  * @self: a #ClutterActor
12821  * @box: a #ClutterActorBox, containing the available width and height
12822  * @x_align: the horizontal alignment, between 0 and 1
12823  * @y_align: the vertical alignment, between 0 and 1
12824  * @x_fill: whether the actor should fill horizontally
12825  * @y_fill: whether the actor should fill vertically
12826  * @flags: allocation flags to be passed to clutter_actor_allocate()
12827  *
12828  * Allocates @self by taking into consideration the available allocation
12829  * area; an alignment factor on either axis; and whether the actor should
12830  * fill the allocation on either axis.
12831  *
12832  * The @box should contain the available allocation width and height;
12833  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
12834  * allocation will be offset by their value.
12835  *
12836  * This function takes into consideration the geometry request specified by
12837  * the #ClutterActor:request-mode property, and the text direction.
12838  *
12839  * This function is useful for fluid layout managers, like #ClutterBinLayout
12840  * or #ClutterTableLayout
12841  *
12842  * Since: 1.4
12843  */
12844 void
12845 clutter_actor_allocate_align_fill (ClutterActor           *self,
12846                                    const ClutterActorBox  *box,
12847                                    gdouble                 x_align,
12848                                    gdouble                 y_align,
12849                                    gboolean                x_fill,
12850                                    gboolean                y_fill,
12851                                    ClutterAllocationFlags  flags)
12852 {
12853   ClutterActorPrivate *priv;
12854   ClutterActorBox allocation = { 0, };
12855   gfloat x_offset, y_offset;
12856   gfloat available_width, available_height;
12857   gfloat child_width, child_height;
12858
12859   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12860   g_return_if_fail (box != NULL);
12861   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
12862   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
12863
12864   priv = self->priv;
12865
12866   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
12867   clutter_actor_box_get_size (box, &available_width, &available_height);
12868
12869   if (available_width < 0)
12870     available_width = 0;
12871
12872   if (available_height < 0)
12873     available_height = 0;
12874
12875   if (x_fill)
12876     {
12877       allocation.x1 = x_offset;
12878       allocation.x2 = allocation.x1 + available_width;
12879     }
12880
12881   if (y_fill)
12882     {
12883       allocation.y1 = y_offset;
12884       allocation.y2 = allocation.y1 + available_height;
12885     }
12886
12887   /* if we are filling horizontally and vertically then we're done */
12888   if (x_fill && y_fill)
12889     goto out;
12890
12891   child_width = child_height = 0.0f;
12892
12893   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12894     {
12895       gfloat min_width, natural_width;
12896       gfloat min_height, natural_height;
12897
12898       clutter_actor_get_preferred_width (self, available_height,
12899                                          &min_width,
12900                                          &natural_width);
12901
12902       child_width = CLAMP (natural_width, min_width, available_width);
12903
12904       if (!y_fill)
12905         {
12906           clutter_actor_get_preferred_height (self, child_width,
12907                                               &min_height,
12908                                               &natural_height);
12909
12910           child_height = CLAMP (natural_height, min_height, available_height);
12911         }
12912     }
12913   else
12914     {
12915       gfloat min_width, natural_width;
12916       gfloat min_height, natural_height;
12917
12918       clutter_actor_get_preferred_height (self, available_width,
12919                                           &min_height,
12920                                           &natural_height);
12921
12922       child_height = CLAMP (natural_height, min_height, available_height);
12923
12924       if (!x_fill)
12925         {
12926           clutter_actor_get_preferred_width (self, child_height,
12927                                              &min_width,
12928                                              &natural_width);
12929
12930           child_width = CLAMP (natural_width, min_width, available_width);
12931         }
12932     }
12933
12934   /* invert the horizontal alignment for RTL languages */
12935   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
12936     x_align = 1.0 - x_align;
12937
12938   if (!x_fill)
12939     {
12940       allocation.x1 = x_offset
12941                     + ((available_width - child_width) * x_align);
12942       allocation.x2 = allocation.x1 + child_width;
12943     }
12944
12945   if (!y_fill)
12946     {
12947       allocation.y1 = y_offset
12948                     + ((available_height - child_height) * y_align);
12949       allocation.y2 = allocation.y1 + child_height;
12950     }
12951
12952 out:
12953   clutter_actor_box_clamp_to_pixel (&allocation);
12954   clutter_actor_allocate (self, &allocation, flags);
12955 }
12956
12957 /**
12958  * clutter_actor_grab_key_focus:
12959  * @self: a #ClutterActor
12960  *
12961  * Sets the key focus of the #ClutterStage including @self
12962  * to this #ClutterActor.
12963  *
12964  * Since: 1.0
12965  */
12966 void
12967 clutter_actor_grab_key_focus (ClutterActor *self)
12968 {
12969   ClutterActor *stage;
12970
12971   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12972
12973   stage = _clutter_actor_get_stage_internal (self);
12974   if (stage != NULL)
12975     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
12976 }
12977
12978 /**
12979  * clutter_actor_get_pango_context:
12980  * @self: a #ClutterActor
12981  *
12982  * Retrieves the #PangoContext for @self. The actor's #PangoContext
12983  * is already configured using the appropriate font map, resolution
12984  * and font options.
12985  *
12986  * Unlike clutter_actor_create_pango_context(), this context is owend
12987  * by the #ClutterActor and it will be updated each time the options
12988  * stored by the #ClutterBackend change.
12989  *
12990  * You can use the returned #PangoContext to create a #PangoLayout
12991  * and render text using cogl_pango_render_layout() to reuse the
12992  * glyphs cache also used by Clutter.
12993  *
12994  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
12995  *   The returned #PangoContext is owned by the actor and should not be
12996  *   unreferenced by the application code
12997  *
12998  * Since: 1.0
12999  */
13000 PangoContext *
13001 clutter_actor_get_pango_context (ClutterActor *self)
13002 {
13003   ClutterActorPrivate *priv;
13004
13005   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13006
13007   priv = self->priv;
13008
13009   if (priv->pango_context != NULL)
13010     return priv->pango_context;
13011
13012   priv->pango_context = _clutter_context_get_pango_context ();
13013   g_object_ref (priv->pango_context);
13014
13015   return priv->pango_context;
13016 }
13017
13018 /**
13019  * clutter_actor_create_pango_context:
13020  * @self: a #ClutterActor
13021  *
13022  * Creates a #PangoContext for the given actor. The #PangoContext
13023  * is already configured using the appropriate font map, resolution
13024  * and font options.
13025  *
13026  * See also clutter_actor_get_pango_context().
13027  *
13028  * Return value: (transfer full): the newly created #PangoContext.
13029  *   Use g_object_unref() on the returned value to deallocate its
13030  *   resources
13031  *
13032  * Since: 1.0
13033  */
13034 PangoContext *
13035 clutter_actor_create_pango_context (ClutterActor *self)
13036 {
13037   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13038
13039   return _clutter_context_create_pango_context ();
13040 }
13041
13042 /**
13043  * clutter_actor_create_pango_layout:
13044  * @self: a #ClutterActor
13045  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13046  *
13047  * Creates a new #PangoLayout from the same #PangoContext used
13048  * by the #ClutterActor. The #PangoLayout is already configured
13049  * with the font map, resolution and font options, and the
13050  * given @text.
13051  *
13052  * If you want to keep around a #PangoLayout created by this
13053  * function you will have to connect to the #ClutterBackend::font-changed
13054  * and #ClutterBackend::resolution-changed signals, and call
13055  * pango_layout_context_changed() in response to them.
13056  *
13057  * Return value: (transfer full): the newly created #PangoLayout.
13058  *   Use g_object_unref() when done
13059  *
13060  * Since: 1.0
13061  */
13062 PangoLayout *
13063 clutter_actor_create_pango_layout (ClutterActor *self,
13064                                    const gchar  *text)
13065 {
13066   PangoContext *context;
13067   PangoLayout *layout;
13068
13069   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13070
13071   context = clutter_actor_get_pango_context (self);
13072   layout = pango_layout_new (context);
13073
13074   if (text)
13075     pango_layout_set_text (layout, text, -1);
13076
13077   return layout;
13078 }
13079
13080 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13081  * ClutterOffscreenEffect.
13082  */
13083 void
13084 _clutter_actor_set_opacity_override (ClutterActor *self,
13085                                      gint          opacity)
13086 {
13087   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13088
13089   self->priv->opacity_override = opacity;
13090 }
13091
13092 gint
13093 _clutter_actor_get_opacity_override (ClutterActor *self)
13094 {
13095   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13096
13097   return self->priv->opacity_override;
13098 }
13099
13100 /* Allows you to disable applying the actors model view transform during
13101  * a paint. Used by ClutterClone. */
13102 void
13103 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13104                                                 gboolean      enable)
13105 {
13106   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13107
13108   self->priv->enable_model_view_transform = enable;
13109 }
13110
13111 void
13112 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13113                                           gboolean      enable)
13114 {
13115   ClutterActorPrivate *priv;
13116
13117   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13118
13119   priv = self->priv;
13120
13121   priv->enable_paint_unmapped = enable;
13122
13123   if (priv->enable_paint_unmapped)
13124     {
13125       /* Make sure that the parents of the widget are realized first;
13126        * otherwise checks in clutter_actor_update_map_state() will
13127        * fail.
13128        */
13129       clutter_actor_realize (self);
13130
13131       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13132     }
13133   else
13134     {
13135       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13136     }
13137 }
13138
13139 static void
13140 clutter_anchor_coord_get_units (ClutterActor      *self,
13141                                 const AnchorCoord *coord,
13142                                 gfloat            *x,
13143                                 gfloat            *y,
13144                                 gfloat            *z)
13145 {
13146   if (coord->is_fractional)
13147     {
13148       gfloat actor_width, actor_height;
13149
13150       clutter_actor_get_size (self, &actor_width, &actor_height);
13151
13152       if (x)
13153         *x = actor_width * coord->v.fraction.x;
13154
13155       if (y)
13156         *y = actor_height * coord->v.fraction.y;
13157
13158       if (z)
13159         *z = 0;
13160     }
13161   else
13162     {
13163       if (x)
13164         *x = coord->v.units.x;
13165
13166       if (y)
13167         *y = coord->v.units.y;
13168
13169       if (z)
13170         *z = coord->v.units.z;
13171     }
13172 }
13173
13174 static void
13175 clutter_anchor_coord_set_units (AnchorCoord *coord,
13176                                 gfloat       x,
13177                                 gfloat       y,
13178                                 gfloat       z)
13179 {
13180   coord->is_fractional = FALSE;
13181   coord->v.units.x = x;
13182   coord->v.units.y = y;
13183   coord->v.units.z = z;
13184 }
13185
13186 static ClutterGravity
13187 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13188 {
13189   if (coord->is_fractional)
13190     {
13191       if (coord->v.fraction.x == 0.0)
13192         {
13193           if (coord->v.fraction.y == 0.0)
13194             return CLUTTER_GRAVITY_NORTH_WEST;
13195           else if (coord->v.fraction.y == 0.5)
13196             return CLUTTER_GRAVITY_WEST;
13197           else if (coord->v.fraction.y == 1.0)
13198             return CLUTTER_GRAVITY_SOUTH_WEST;
13199           else
13200             return CLUTTER_GRAVITY_NONE;
13201         }
13202       else if (coord->v.fraction.x == 0.5)
13203         {
13204           if (coord->v.fraction.y == 0.0)
13205             return CLUTTER_GRAVITY_NORTH;
13206           else if (coord->v.fraction.y == 0.5)
13207             return CLUTTER_GRAVITY_CENTER;
13208           else if (coord->v.fraction.y == 1.0)
13209             return CLUTTER_GRAVITY_SOUTH;
13210           else
13211             return CLUTTER_GRAVITY_NONE;
13212         }
13213       else if (coord->v.fraction.x == 1.0)
13214         {
13215           if (coord->v.fraction.y == 0.0)
13216             return CLUTTER_GRAVITY_NORTH_EAST;
13217           else if (coord->v.fraction.y == 0.5)
13218             return CLUTTER_GRAVITY_EAST;
13219           else if (coord->v.fraction.y == 1.0)
13220             return CLUTTER_GRAVITY_SOUTH_EAST;
13221           else
13222             return CLUTTER_GRAVITY_NONE;
13223         }
13224       else
13225         return CLUTTER_GRAVITY_NONE;
13226     }
13227   else
13228     return CLUTTER_GRAVITY_NONE;
13229 }
13230
13231 static void
13232 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13233                                   ClutterGravity  gravity)
13234 {
13235   switch (gravity)
13236     {
13237     case CLUTTER_GRAVITY_NORTH:
13238       coord->v.fraction.x = 0.5;
13239       coord->v.fraction.y = 0.0;
13240       break;
13241
13242     case CLUTTER_GRAVITY_NORTH_EAST:
13243       coord->v.fraction.x = 1.0;
13244       coord->v.fraction.y = 0.0;
13245       break;
13246
13247     case CLUTTER_GRAVITY_EAST:
13248       coord->v.fraction.x = 1.0;
13249       coord->v.fraction.y = 0.5;
13250       break;
13251
13252     case CLUTTER_GRAVITY_SOUTH_EAST:
13253       coord->v.fraction.x = 1.0;
13254       coord->v.fraction.y = 1.0;
13255       break;
13256
13257     case CLUTTER_GRAVITY_SOUTH:
13258       coord->v.fraction.x = 0.5;
13259       coord->v.fraction.y = 1.0;
13260       break;
13261
13262     case CLUTTER_GRAVITY_SOUTH_WEST:
13263       coord->v.fraction.x = 0.0;
13264       coord->v.fraction.y = 1.0;
13265       break;
13266
13267     case CLUTTER_GRAVITY_WEST:
13268       coord->v.fraction.x = 0.0;
13269       coord->v.fraction.y = 0.5;
13270       break;
13271
13272     case CLUTTER_GRAVITY_NORTH_WEST:
13273       coord->v.fraction.x = 0.0;
13274       coord->v.fraction.y = 0.0;
13275       break;
13276
13277     case CLUTTER_GRAVITY_CENTER:
13278       coord->v.fraction.x = 0.5;
13279       coord->v.fraction.y = 0.5;
13280       break;
13281
13282     default:
13283       coord->v.fraction.x = 0.0;
13284       coord->v.fraction.y = 0.0;
13285       break;
13286     }
13287
13288   coord->is_fractional = TRUE;
13289 }
13290
13291 static gboolean
13292 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13293 {
13294   if (coord->is_fractional)
13295     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13296   else
13297     return (coord->v.units.x == 0.0
13298             && coord->v.units.y == 0.0
13299             && coord->v.units.z == 0.0);
13300 }
13301
13302 /**
13303  * clutter_actor_get_flags:
13304  * @self: a #ClutterActor
13305  *
13306  * Retrieves the flags set on @self
13307  *
13308  * Return value: a bitwise or of #ClutterActorFlags or 0
13309  *
13310  * Since: 1.0
13311  */
13312 ClutterActorFlags
13313 clutter_actor_get_flags (ClutterActor *self)
13314 {
13315   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13316
13317   return self->flags;
13318 }
13319
13320 /**
13321  * clutter_actor_set_flags:
13322  * @self: a #ClutterActor
13323  * @flags: the flags to set
13324  *
13325  * Sets @flags on @self
13326  *
13327  * This function will emit notifications for the changed properties
13328  *
13329  * Since: 1.0
13330  */
13331 void
13332 clutter_actor_set_flags (ClutterActor      *self,
13333                          ClutterActorFlags  flags)
13334 {
13335   ClutterActorFlags old_flags;
13336   GObject *obj;
13337   gboolean was_reactive_set, reactive_set;
13338   gboolean was_realized_set, realized_set;
13339   gboolean was_mapped_set, mapped_set;
13340   gboolean was_visible_set, visible_set;
13341
13342   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13343
13344   if (self->flags == flags)
13345     return;
13346
13347   obj = G_OBJECT (self);
13348   g_object_ref (obj);
13349   g_object_freeze_notify (obj);
13350
13351   old_flags = self->flags;
13352
13353   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13354   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13355   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13356   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13357
13358   self->flags |= flags;
13359
13360   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13361   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13362   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13363   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13364
13365   if (reactive_set != was_reactive_set)
13366     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13367
13368   if (realized_set != was_realized_set)
13369     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13370
13371   if (mapped_set != was_mapped_set)
13372     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13373
13374   if (visible_set != was_visible_set)
13375     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13376
13377   g_object_thaw_notify (obj);
13378   g_object_unref (obj);
13379 }
13380
13381 /**
13382  * clutter_actor_unset_flags:
13383  * @self: a #ClutterActor
13384  * @flags: the flags to unset
13385  *
13386  * Unsets @flags on @self
13387  *
13388  * This function will emit notifications for the changed properties
13389  *
13390  * Since: 1.0
13391  */
13392 void
13393 clutter_actor_unset_flags (ClutterActor      *self,
13394                            ClutterActorFlags  flags)
13395 {
13396   ClutterActorFlags old_flags;
13397   GObject *obj;
13398   gboolean was_reactive_set, reactive_set;
13399   gboolean was_realized_set, realized_set;
13400   gboolean was_mapped_set, mapped_set;
13401   gboolean was_visible_set, visible_set;
13402
13403   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13404
13405   obj = G_OBJECT (self);
13406   g_object_freeze_notify (obj);
13407
13408   old_flags = self->flags;
13409
13410   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13411   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13412   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13413   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13414
13415   self->flags &= ~flags;
13416
13417   if (self->flags == old_flags)
13418     return;
13419
13420   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13421   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13422   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13423   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13424
13425   if (reactive_set != was_reactive_set)
13426     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13427
13428   if (realized_set != was_realized_set)
13429     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13430
13431   if (mapped_set != was_mapped_set)
13432     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13433
13434   if (visible_set != was_visible_set)
13435     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13436
13437   g_object_thaw_notify (obj);
13438 }
13439
13440 /**
13441  * clutter_actor_get_transformation_matrix:
13442  * @self: a #ClutterActor
13443  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13444  *
13445  * Retrieves the transformations applied to @self relative to its
13446  * parent.
13447  *
13448  * Since: 1.0
13449  */
13450 void
13451 clutter_actor_get_transformation_matrix (ClutterActor *self,
13452                                          CoglMatrix   *matrix)
13453 {
13454   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13455
13456   cogl_matrix_init_identity (matrix);
13457
13458   _clutter_actor_apply_modelview_transform (self, matrix);
13459 }
13460
13461 void
13462 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13463                                    gboolean      is_in_clone_paint)
13464 {
13465   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13466   self->priv->in_clone_paint = is_in_clone_paint;
13467 }
13468
13469 /**
13470  * clutter_actor_is_in_clone_paint:
13471  * @self: a #ClutterActor
13472  *
13473  * Checks whether @self is being currently painted by a #ClutterClone
13474  *
13475  * This function is useful only inside the ::paint virtual function
13476  * implementations or within handlers for the #ClutterActor::paint
13477  * signal
13478  *
13479  * This function should not be used by applications
13480  *
13481  * Return value: %TRUE if the #ClutterActor is currently being painted
13482  *   by a #ClutterClone, and %FALSE otherwise
13483  *
13484  * Since: 1.0
13485  */
13486 gboolean
13487 clutter_actor_is_in_clone_paint (ClutterActor *self)
13488 {
13489   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13490
13491   return self->priv->in_clone_paint;
13492 }
13493
13494 static gboolean
13495 set_direction_recursive (ClutterActor *actor,
13496                          gpointer      user_data)
13497 {
13498   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
13499
13500   clutter_actor_set_text_direction (actor, text_dir);
13501
13502   return TRUE;
13503 }
13504
13505 /**
13506  * clutter_actor_set_text_direction:
13507  * @self: a #ClutterActor
13508  * @text_dir: the text direction for @self
13509  *
13510  * Sets the #ClutterTextDirection for an actor
13511  *
13512  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
13513  *
13514  * If @self implements #ClutterContainer then this function will recurse
13515  * inside all the children of @self (including the internal ones).
13516  *
13517  * Composite actors not implementing #ClutterContainer, or actors requiring
13518  * special handling when the text direction changes, should connect to
13519  * the #GObject::notify signal for the #ClutterActor:text-direction property
13520  *
13521  * Since: 1.2
13522  */
13523 void
13524 clutter_actor_set_text_direction (ClutterActor         *self,
13525                                   ClutterTextDirection  text_dir)
13526 {
13527   ClutterActorPrivate *priv;
13528
13529   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13530   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
13531
13532   priv = self->priv;
13533
13534   if (priv->text_direction != text_dir)
13535     {
13536       priv->text_direction = text_dir;
13537
13538       /* we need to emit the notify::text-direction first, so that
13539        * the sub-classes can catch that and do specific handling of
13540        * the text direction; see clutter_text_direction_changed_cb()
13541        * inside clutter-text.c
13542        */
13543       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
13544
13545       _clutter_actor_foreach_child (self, set_direction_recursive,
13546                                     GINT_TO_POINTER (text_dir));
13547
13548       clutter_actor_queue_relayout (self);
13549     }
13550 }
13551
13552 void
13553 _clutter_actor_set_has_pointer (ClutterActor *self,
13554                                 gboolean      has_pointer)
13555 {
13556   ClutterActorPrivate *priv = self->priv;
13557
13558   if (priv->has_pointer != has_pointer)
13559     {
13560       priv->has_pointer = has_pointer;
13561
13562       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
13563     }
13564 }
13565
13566 /**
13567  * clutter_actor_get_text_direction:
13568  * @self: a #ClutterActor
13569  *
13570  * Retrieves the value set using clutter_actor_set_text_direction()
13571  *
13572  * If no text direction has been previously set, the default text
13573  * direction, as returned by clutter_get_default_text_direction(), will
13574  * be returned instead
13575  *
13576  * Return value: the #ClutterTextDirection for the actor
13577  *
13578  * Since: 1.2
13579  */
13580 ClutterTextDirection
13581 clutter_actor_get_text_direction (ClutterActor *self)
13582 {
13583   ClutterActorPrivate *priv;
13584
13585   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
13586                         CLUTTER_TEXT_DIRECTION_LTR);
13587
13588   priv = self->priv;
13589
13590   /* if no direction has been set yet use the default */
13591   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
13592     priv->text_direction = clutter_get_default_text_direction ();
13593
13594   return priv->text_direction;
13595 }
13596
13597 /**
13598  * clutter_actor_push_internal:
13599  * @self: a #ClutterActor
13600  *
13601  * Should be used by actors implementing the #ClutterContainer and with
13602  * internal children added through clutter_actor_set_parent(), for instance:
13603  *
13604  * |[
13605  *   static void
13606  *   my_actor_init (MyActor *self)
13607  *   {
13608  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
13609  *
13610  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
13611  *
13612  *     /&ast; calling clutter_actor_set_parent() now will result in
13613  *      &ast; the internal flag being set on a child of MyActor
13614  *      &ast;/
13615  *
13616  *     /&ast; internal child - a background texture &ast;/
13617  *     self->priv->background_tex = clutter_texture_new ();
13618  *     clutter_actor_set_parent (self->priv->background_tex,
13619  *                               CLUTTER_ACTOR (self));
13620  *
13621  *     /&ast; internal child - a label &ast;/
13622  *     self->priv->label = clutter_text_new ();
13623  *     clutter_actor_set_parent (self->priv->label,
13624  *                               CLUTTER_ACTOR (self));
13625  *
13626  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
13627  *
13628  *     /&ast; calling clutter_actor_set_parent() now will not result in
13629  *      &ast; the internal flag being set on a child of MyActor
13630  *      &ast;/
13631  *   }
13632  * ]|
13633  *
13634  * This function will be used by Clutter to toggle an "internal child"
13635  * flag whenever clutter_actor_set_parent() is called; internal children
13636  * are handled differently by Clutter, specifically when destroying their
13637  * parent.
13638  *
13639  * Call clutter_actor_pop_internal() when you finished adding internal
13640  * children.
13641  *
13642  * Nested calls to clutter_actor_push_internal() are allowed, but each
13643  * one must by followed by a clutter_actor_pop_internal() call.
13644  *
13645  * Since: 1.2
13646  *
13647  * Deprecated: 1.10: All children of an actor are accessible through
13648  *   the #ClutterActor API, and #ClutterActor implements the
13649  *   #ClutterContainer interface, so this function is only useful
13650  *   for legacy containers overriding the default implementation.
13651  */
13652 void
13653 clutter_actor_push_internal (ClutterActor *self)
13654 {
13655   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13656
13657   self->priv->internal_child += 1;
13658 }
13659
13660 /**
13661  * clutter_actor_pop_internal:
13662  * @self: a #ClutterActor
13663  *
13664  * Disables the effects of clutter_actor_push_internal().
13665  *
13666  * Since: 1.2
13667  *
13668  * Deprecated: 1.10: All children of an actor are accessible through
13669  *   the #ClutterActor API. This function is only useful for legacy
13670  *   containers overriding the default implementation of the
13671  *   #ClutterContainer interface.
13672  */
13673 void
13674 clutter_actor_pop_internal (ClutterActor *self)
13675 {
13676   ClutterActorPrivate *priv;
13677
13678   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13679
13680   priv = self->priv;
13681
13682   if (priv->internal_child == 0)
13683     {
13684       g_warning ("Mismatched %s: you need to call "
13685                  "clutter_actor_push_composite() at least once before "
13686                  "calling this function", G_STRFUNC);
13687       return;
13688     }
13689
13690   priv->internal_child -= 1;
13691 }
13692
13693 /**
13694  * clutter_actor_has_pointer:
13695  * @self: a #ClutterActor
13696  *
13697  * Checks whether an actor contains the pointer of a
13698  * #ClutterInputDevice
13699  *
13700  * Return value: %TRUE if the actor contains the pointer, and
13701  *   %FALSE otherwise
13702  *
13703  * Since: 1.2
13704  */
13705 gboolean
13706 clutter_actor_has_pointer (ClutterActor *self)
13707 {
13708   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13709
13710   return self->priv->has_pointer;
13711 }
13712
13713 /* XXX: This is a workaround for not being able to break the ABI of
13714  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
13715  * clutter_actor_queue_clipped_redraw() for details.
13716  */
13717 ClutterPaintVolume *
13718 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
13719 {
13720   return g_object_get_data (G_OBJECT (self),
13721                             "-clutter-actor-queue-redraw-clip");
13722 }
13723
13724 void
13725 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
13726                                       ClutterPaintVolume *clip)
13727 {
13728   g_object_set_data (G_OBJECT (self),
13729                      "-clutter-actor-queue-redraw-clip",
13730                      clip);
13731 }
13732
13733 /**
13734  * clutter_actor_has_allocation:
13735  * @self: a #ClutterActor
13736  *
13737  * Checks if the actor has an up-to-date allocation assigned to
13738  * it. This means that the actor should have an allocation: it's
13739  * visible and has a parent. It also means that there is no
13740  * outstanding relayout request in progress for the actor or its
13741  * children (There might be other outstanding layout requests in
13742  * progress that will cause the actor to get a new allocation
13743  * when the stage is laid out, however).
13744  *
13745  * If this function returns %FALSE, then the actor will normally
13746  * be allocated before it is next drawn on the screen.
13747  *
13748  * Return value: %TRUE if the actor has an up-to-date allocation
13749  *
13750  * Since: 1.4
13751  */
13752 gboolean
13753 clutter_actor_has_allocation (ClutterActor *self)
13754 {
13755   ClutterActorPrivate *priv;
13756
13757   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13758
13759   priv = self->priv;
13760
13761   return priv->parent != NULL &&
13762          CLUTTER_ACTOR_IS_VISIBLE (self) &&
13763          !priv->needs_allocation;
13764 }
13765
13766 /**
13767  * clutter_actor_add_action:
13768  * @self: a #ClutterActor
13769  * @action: a #ClutterAction
13770  *
13771  * Adds @action to the list of actions applied to @self
13772  *
13773  * A #ClutterAction can only belong to one actor at a time
13774  *
13775  * The #ClutterActor will hold a reference on @action until either
13776  * clutter_actor_remove_action() or clutter_actor_clear_actions()
13777  * is called
13778  *
13779  * Since: 1.4
13780  */
13781 void
13782 clutter_actor_add_action (ClutterActor  *self,
13783                           ClutterAction *action)
13784 {
13785   ClutterActorPrivate *priv;
13786
13787   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13788   g_return_if_fail (CLUTTER_IS_ACTION (action));
13789
13790   priv = self->priv;
13791
13792   if (priv->actions == NULL)
13793     {
13794       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13795       priv->actions->actor = self;
13796     }
13797
13798   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
13799
13800   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13801 }
13802
13803 /**
13804  * clutter_actor_add_action_with_name:
13805  * @self: a #ClutterActor
13806  * @name: the name to set on the action
13807  * @action: a #ClutterAction
13808  *
13809  * A convenience function for setting the name of a #ClutterAction
13810  * while adding it to the list of actions applied to @self
13811  *
13812  * This function is the logical equivalent of:
13813  *
13814  * |[
13815  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13816  *   clutter_actor_add_action (self, action);
13817  * ]|
13818  *
13819  * Since: 1.4
13820  */
13821 void
13822 clutter_actor_add_action_with_name (ClutterActor  *self,
13823                                     const gchar   *name,
13824                                     ClutterAction *action)
13825 {
13826   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13827   g_return_if_fail (name != NULL);
13828   g_return_if_fail (CLUTTER_IS_ACTION (action));
13829
13830   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13831   clutter_actor_add_action (self, action);
13832 }
13833
13834 /**
13835  * clutter_actor_remove_action:
13836  * @self: a #ClutterActor
13837  * @action: a #ClutterAction
13838  *
13839  * Removes @action from the list of actions applied to @self
13840  *
13841  * The reference held by @self on the #ClutterAction will be released
13842  *
13843  * Since: 1.4
13844  */
13845 void
13846 clutter_actor_remove_action (ClutterActor  *self,
13847                              ClutterAction *action)
13848 {
13849   ClutterActorPrivate *priv;
13850
13851   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13852   g_return_if_fail (CLUTTER_IS_ACTION (action));
13853
13854   priv = self->priv;
13855
13856   if (priv->actions == NULL)
13857     return;
13858
13859   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
13860
13861   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13862 }
13863
13864 /**
13865  * clutter_actor_remove_action_by_name:
13866  * @self: a #ClutterActor
13867  * @name: the name of the action to remove
13868  *
13869  * Removes the #ClutterAction with the given name from the list
13870  * of actions applied to @self
13871  *
13872  * Since: 1.4
13873  */
13874 void
13875 clutter_actor_remove_action_by_name (ClutterActor *self,
13876                                      const gchar  *name)
13877 {
13878   ClutterActorPrivate *priv;
13879   ClutterActorMeta *meta;
13880
13881   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13882   g_return_if_fail (name != NULL);
13883
13884   priv = self->priv;
13885
13886   if (priv->actions == NULL)
13887     return;
13888
13889   meta = _clutter_meta_group_get_meta (priv->actions, name);
13890   if (meta == NULL)
13891     return;
13892
13893   _clutter_meta_group_remove_meta (priv->actions, meta);
13894
13895   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13896 }
13897
13898 /**
13899  * clutter_actor_get_actions:
13900  * @self: a #ClutterActor
13901  *
13902  * Retrieves the list of actions applied to @self
13903  *
13904  * Return value: (transfer container) (element-type Clutter.Action): a copy
13905  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
13906  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13907  *   allocated by the returned #GList
13908  *
13909  * Since: 1.4
13910  */
13911 GList *
13912 clutter_actor_get_actions (ClutterActor *self)
13913 {
13914   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13915
13916   if (self->priv->actions == NULL)
13917     return NULL;
13918
13919   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
13920 }
13921
13922 /**
13923  * clutter_actor_get_action:
13924  * @self: a #ClutterActor
13925  * @name: the name of the action to retrieve
13926  *
13927  * Retrieves the #ClutterAction with the given name in the list
13928  * of actions applied to @self
13929  *
13930  * Return value: (transfer none): a #ClutterAction for the given
13931  *   name, or %NULL. The returned #ClutterAction is owned by the
13932  *   actor and it should not be unreferenced directly
13933  *
13934  * Since: 1.4
13935  */
13936 ClutterAction *
13937 clutter_actor_get_action (ClutterActor *self,
13938                           const gchar  *name)
13939 {
13940   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13941   g_return_val_if_fail (name != NULL, NULL);
13942
13943   if (self->priv->actions == NULL)
13944     return NULL;
13945
13946   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
13947 }
13948
13949 /**
13950  * clutter_actor_clear_actions:
13951  * @self: a #ClutterActor
13952  *
13953  * Clears the list of actions applied to @self
13954  *
13955  * Since: 1.4
13956  */
13957 void
13958 clutter_actor_clear_actions (ClutterActor *self)
13959 {
13960   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13961
13962   if (self->priv->actions == NULL)
13963     return;
13964
13965   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
13966 }
13967
13968 /**
13969  * clutter_actor_add_constraint:
13970  * @self: a #ClutterActor
13971  * @constraint: a #ClutterConstraint
13972  *
13973  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
13974  * to @self
13975  *
13976  * The #ClutterActor will hold a reference on the @constraint until
13977  * either clutter_actor_remove_constraint() or
13978  * clutter_actor_clear_constraints() is called.
13979  *
13980  * Since: 1.4
13981  */
13982 void
13983 clutter_actor_add_constraint (ClutterActor      *self,
13984                               ClutterConstraint *constraint)
13985 {
13986   ClutterActorPrivate *priv;
13987
13988   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13989   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13990
13991   priv = self->priv;
13992
13993   if (priv->constraints == NULL)
13994     {
13995       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13996       priv->constraints->actor = self;
13997     }
13998
13999   _clutter_meta_group_add_meta (priv->constraints,
14000                                 CLUTTER_ACTOR_META (constraint));
14001   clutter_actor_queue_relayout (self);
14002
14003   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14004 }
14005
14006 /**
14007  * clutter_actor_add_constraint_with_name:
14008  * @self: a #ClutterActor
14009  * @name: the name to set on the constraint
14010  * @constraint: a #ClutterConstraint
14011  *
14012  * A convenience function for setting the name of a #ClutterConstraint
14013  * while adding it to the list of constraints applied to @self
14014  *
14015  * This function is the logical equivalent of:
14016  *
14017  * |[
14018  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14019  *   clutter_actor_add_constraint (self, constraint);
14020  * ]|
14021  *
14022  * Since: 1.4
14023  */
14024 void
14025 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14026                                         const gchar       *name,
14027                                         ClutterConstraint *constraint)
14028 {
14029   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14030   g_return_if_fail (name != NULL);
14031   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14032
14033   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14034   clutter_actor_add_constraint (self, constraint);
14035 }
14036
14037 /**
14038  * clutter_actor_remove_constraint:
14039  * @self: a #ClutterActor
14040  * @constraint: a #ClutterConstraint
14041  *
14042  * Removes @constraint from the list of constraints applied to @self
14043  *
14044  * The reference held by @self on the #ClutterConstraint will be released
14045  *
14046  * Since: 1.4
14047  */
14048 void
14049 clutter_actor_remove_constraint (ClutterActor      *self,
14050                                  ClutterConstraint *constraint)
14051 {
14052   ClutterActorPrivate *priv;
14053
14054   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14055   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14056
14057   priv = self->priv;
14058
14059   if (priv->constraints == NULL)
14060     return;
14061
14062   _clutter_meta_group_remove_meta (priv->constraints,
14063                                    CLUTTER_ACTOR_META (constraint));
14064   clutter_actor_queue_relayout (self);
14065
14066   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14067 }
14068
14069 /**
14070  * clutter_actor_remove_constraint_by_name:
14071  * @self: a #ClutterActor
14072  * @name: the name of the constraint to remove
14073  *
14074  * Removes the #ClutterConstraint with the given name from the list
14075  * of constraints applied to @self
14076  *
14077  * Since: 1.4
14078  */
14079 void
14080 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14081                                          const gchar  *name)
14082 {
14083   ClutterActorPrivate *priv;
14084   ClutterActorMeta *meta;
14085
14086   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14087   g_return_if_fail (name != NULL);
14088
14089   priv = self->priv;
14090
14091   if (priv->constraints == NULL)
14092     return;
14093
14094   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14095   if (meta == NULL)
14096     return;
14097
14098   _clutter_meta_group_remove_meta (priv->constraints, meta);
14099   clutter_actor_queue_relayout (self);
14100 }
14101
14102 /**
14103  * clutter_actor_get_constraints:
14104  * @self: a #ClutterActor
14105  *
14106  * Retrieves the list of constraints applied to @self
14107  *
14108  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14109  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14110  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14111  *   allocated by the returned #GList
14112  *
14113  * Since: 1.4
14114  */
14115 GList *
14116 clutter_actor_get_constraints (ClutterActor *self)
14117 {
14118   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14119
14120   if (self->priv->constraints == NULL)
14121     return NULL;
14122
14123   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14124 }
14125
14126 /**
14127  * clutter_actor_get_constraint:
14128  * @self: a #ClutterActor
14129  * @name: the name of the constraint to retrieve
14130  *
14131  * Retrieves the #ClutterConstraint with the given name in the list
14132  * of constraints applied to @self
14133  *
14134  * Return value: (transfer none): a #ClutterConstraint for the given
14135  *   name, or %NULL. The returned #ClutterConstraint is owned by the
14136  *   actor and it should not be unreferenced directly
14137  *
14138  * Since: 1.4
14139  */
14140 ClutterConstraint *
14141 clutter_actor_get_constraint (ClutterActor *self,
14142                               const gchar  *name)
14143 {
14144   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14145   g_return_val_if_fail (name != NULL, NULL);
14146
14147   if (self->priv->constraints == NULL)
14148     return NULL;
14149
14150   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14151 }
14152
14153 /**
14154  * clutter_actor_clear_constraints:
14155  * @self: a #ClutterActor
14156  *
14157  * Clears the list of constraints applied to @self
14158  *
14159  * Since: 1.4
14160  */
14161 void
14162 clutter_actor_clear_constraints (ClutterActor *self)
14163 {
14164   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14165
14166   if (self->priv->constraints == NULL)
14167     return;
14168
14169   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14170
14171   clutter_actor_queue_relayout (self);
14172 }
14173
14174 /**
14175  * clutter_actor_set_clip_to_allocation:
14176  * @self: a #ClutterActor
14177  * @clip_set: %TRUE to apply a clip tracking the allocation
14178  *
14179  * Sets whether @self should be clipped to the same size as its
14180  * allocation
14181  *
14182  * Since: 1.4
14183  */
14184 void
14185 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14186                                       gboolean      clip_set)
14187 {
14188   ClutterActorPrivate *priv;
14189
14190   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14191
14192   clip_set = !!clip_set;
14193
14194   priv = self->priv;
14195
14196   if (priv->clip_to_allocation != clip_set)
14197     {
14198       priv->clip_to_allocation = clip_set;
14199
14200       clutter_actor_queue_redraw (self);
14201
14202       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14203     }
14204 }
14205
14206 /**
14207  * clutter_actor_get_clip_to_allocation:
14208  * @self: a #ClutterActor
14209  *
14210  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14211  *
14212  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14213  *
14214  * Since: 1.4
14215  */
14216 gboolean
14217 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14218 {
14219   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14220
14221   return self->priv->clip_to_allocation;
14222 }
14223
14224 /**
14225  * clutter_actor_add_effect:
14226  * @self: a #ClutterActor
14227  * @effect: a #ClutterEffect
14228  *
14229  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14230  *
14231  * The #ClutterActor will hold a reference on the @effect until either
14232  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14233  * called.
14234  *
14235  * Since: 1.4
14236  */
14237 void
14238 clutter_actor_add_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_add_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_add_effect_with_name:
14253  * @self: a #ClutterActor
14254  * @name: the name to set on the effect
14255  * @effect: a #ClutterEffect
14256  *
14257  * A convenience function for setting the name of a #ClutterEffect
14258  * while adding it to the list of effectss applied to @self
14259  *
14260  * This function is the logical equivalent of:
14261  *
14262  * |[
14263  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14264  *   clutter_actor_add_effect (self, effect);
14265  * ]|
14266  *
14267  * Since: 1.4
14268  */
14269 void
14270 clutter_actor_add_effect_with_name (ClutterActor  *self,
14271                                     const gchar   *name,
14272                                     ClutterEffect *effect)
14273 {
14274   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14275   g_return_if_fail (name != NULL);
14276   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14277
14278   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14279   clutter_actor_add_effect (self, effect);
14280 }
14281
14282 /**
14283  * clutter_actor_remove_effect:
14284  * @self: a #ClutterActor
14285  * @effect: a #ClutterEffect
14286  *
14287  * Removes @effect from the list of effects applied to @self
14288  *
14289  * The reference held by @self on the #ClutterEffect will be released
14290  *
14291  * Since: 1.4
14292  */
14293 void
14294 clutter_actor_remove_effect (ClutterActor  *self,
14295                              ClutterEffect *effect)
14296 {
14297   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14298   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14299
14300   _clutter_actor_remove_effect_internal (self, effect);
14301
14302   clutter_actor_queue_redraw (self);
14303
14304   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14305 }
14306
14307 /**
14308  * clutter_actor_remove_effect_by_name:
14309  * @self: a #ClutterActor
14310  * @name: the name of the effect to remove
14311  *
14312  * Removes the #ClutterEffect with the given name from the list
14313  * of effects applied to @self
14314  *
14315  * Since: 1.4
14316  */
14317 void
14318 clutter_actor_remove_effect_by_name (ClutterActor *self,
14319                                      const gchar  *name)
14320 {
14321   ClutterActorPrivate *priv;
14322   ClutterActorMeta *meta;
14323
14324   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14325   g_return_if_fail (name != NULL);
14326
14327   priv = self->priv;
14328
14329   if (priv->effects == NULL)
14330     return;
14331
14332   meta = _clutter_meta_group_get_meta (priv->effects, name);
14333   if (meta == NULL)
14334     return;
14335
14336   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14337 }
14338
14339 /**
14340  * clutter_actor_get_effects:
14341  * @self: a #ClutterActor
14342  *
14343  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14344  *
14345  * Return value: (transfer container) (element-type Clutter.Effect): a list
14346  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14347  *   list are owned by Clutter and they should not be freed. You should
14348  *   free the returned list using g_list_free() when done
14349  *
14350  * Since: 1.4
14351  */
14352 GList *
14353 clutter_actor_get_effects (ClutterActor *self)
14354 {
14355   ClutterActorPrivate *priv;
14356
14357   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14358
14359   priv = self->priv;
14360
14361   if (priv->effects == NULL)
14362     return NULL;
14363
14364   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14365 }
14366
14367 /**
14368  * clutter_actor_get_effect:
14369  * @self: a #ClutterActor
14370  * @name: the name of the effect to retrieve
14371  *
14372  * Retrieves the #ClutterEffect with the given name in the list
14373  * of effects applied to @self
14374  *
14375  * Return value: (transfer none): a #ClutterEffect for the given
14376  *   name, or %NULL. The returned #ClutterEffect is owned by the
14377  *   actor and it should not be unreferenced directly
14378  *
14379  * Since: 1.4
14380  */
14381 ClutterEffect *
14382 clutter_actor_get_effect (ClutterActor *self,
14383                           const gchar  *name)
14384 {
14385   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14386   g_return_val_if_fail (name != NULL, NULL);
14387
14388   if (self->priv->effects == NULL)
14389     return NULL;
14390
14391   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14392 }
14393
14394 /**
14395  * clutter_actor_clear_effects:
14396  * @self: a #ClutterActor
14397  *
14398  * Clears the list of effects applied to @self
14399  *
14400  * Since: 1.4
14401  */
14402 void
14403 clutter_actor_clear_effects (ClutterActor *self)
14404 {
14405   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14406
14407   if (self->priv->effects == NULL)
14408     return;
14409
14410   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14411
14412   clutter_actor_queue_redraw (self);
14413 }
14414
14415 /**
14416  * clutter_actor_has_key_focus:
14417  * @self: a #ClutterActor
14418  *
14419  * Checks whether @self is the #ClutterActor that has key focus
14420  *
14421  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14422  *
14423  * Since: 1.4
14424  */
14425 gboolean
14426 clutter_actor_has_key_focus (ClutterActor *self)
14427 {
14428   ClutterActor *stage;
14429
14430   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14431
14432   stage = _clutter_actor_get_stage_internal (self);
14433   if (stage == NULL)
14434     return FALSE;
14435
14436   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14437 }
14438
14439 static gboolean
14440 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14441                                       ClutterPaintVolume *pv)
14442 {
14443   ClutterActorPrivate *priv = self->priv;
14444
14445   /* Actors are only expected to report a valid paint volume
14446    * while they have a valid allocation. */
14447   if (G_UNLIKELY (priv->needs_allocation))
14448     {
14449       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14450                     "Actor needs allocation",
14451                     _clutter_actor_get_debug_name (self));
14452       return FALSE;
14453     }
14454
14455   /* Check if there are any handlers connected to the paint
14456    * signal. If there are then all bets are off for what the paint
14457    * volume for this actor might possibly be!
14458    *
14459    * XXX: It's expected that this is going to end up being quite a
14460    * costly check to have to do here, but we haven't come up with
14461    * another solution that can reliably catch paint signal handlers at
14462    * the right time to either avoid artefacts due to invalid stage
14463    * clipping or due to incorrect culling.
14464    *
14465    * Previously we checked in clutter_actor_paint(), but at that time
14466    * we may already be using a stage clip that could be derived from
14467    * an invalid paint-volume. We used to try and handle that by
14468    * queuing a follow up, unclipped, redraw but still the previous
14469    * checking wasn't enough to catch invalid volumes involved in
14470    * culling (considering that containers may derive their volume from
14471    * children that haven't yet been painted)
14472    *
14473    * Longer term, improved solutions could be:
14474    * - Disallow painting in the paint signal, only allow using it
14475    *   for tracking when paints happen. We can add another API that
14476    *   allows monkey patching the paint of arbitrary actors but in a
14477    *   more controlled way and that also supports modifying the
14478    *   paint-volume.
14479    * - If we could be notified somehow when signal handlers are
14480    *   connected we wouldn't have to poll for handlers like this.
14481    */
14482   if (g_signal_has_handler_pending (self,
14483                                     actor_signals[PAINT],
14484                                     0,
14485                                     TRUE))
14486     {
14487       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14488                     "Actor has \"paint\" signal handlers",
14489                     _clutter_actor_get_debug_name (self));
14490       return FALSE;
14491     }
14492
14493   _clutter_paint_volume_init_static (pv, self);
14494
14495   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
14496     {
14497       clutter_paint_volume_free (pv);
14498       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14499                     "Actor failed to report a volume",
14500                     _clutter_actor_get_debug_name (self));
14501       return FALSE;
14502     }
14503
14504   /* since effects can modify the paint volume, we allow them to actually
14505    * do this by making get_paint_volume() "context sensitive"
14506    */
14507   if (priv->effects != NULL)
14508     {
14509       if (priv->current_effect != NULL)
14510         {
14511           const GList *effects, *l;
14512
14513           /* if we are being called from within the paint sequence of
14514            * an actor, get the paint volume up to the current effect
14515            */
14516           effects = _clutter_meta_group_peek_metas (priv->effects);
14517           for (l = effects;
14518                l != NULL || (l != NULL && l->data != priv->current_effect);
14519                l = l->next)
14520             {
14521               if (!_clutter_effect_get_paint_volume (l->data, pv))
14522                 {
14523                   clutter_paint_volume_free (pv);
14524                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14525                                 "Effect (%s) failed to report a volume",
14526                                 _clutter_actor_get_debug_name (self),
14527                                 _clutter_actor_meta_get_debug_name (l->data));
14528                   return FALSE;
14529                 }
14530             }
14531         }
14532       else
14533         {
14534           const GList *effects, *l;
14535
14536           /* otherwise, get the cumulative volume */
14537           effects = _clutter_meta_group_peek_metas (priv->effects);
14538           for (l = effects; l != NULL; l = l->next)
14539             if (!_clutter_effect_get_paint_volume (l->data, pv))
14540               {
14541                 clutter_paint_volume_free (pv);
14542                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14543                               "Effect (%s) failed to report a volume",
14544                               _clutter_actor_get_debug_name (self),
14545                               _clutter_actor_meta_get_debug_name (l->data));
14546                 return FALSE;
14547               }
14548         }
14549     }
14550
14551   return TRUE;
14552 }
14553
14554 /* The public clutter_actor_get_paint_volume API returns a const
14555  * pointer since we return a pointer directly to the cached
14556  * PaintVolume associated with the actor and don't want the user to
14557  * inadvertently modify it, but for internal uses we sometimes need
14558  * access to the same PaintVolume but need to apply some book-keeping
14559  * modifications to it so we don't want a const pointer.
14560  */
14561 static ClutterPaintVolume *
14562 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
14563 {
14564   ClutterActorPrivate *priv;
14565
14566   priv = self->priv;
14567
14568   if (priv->paint_volume_valid)
14569     clutter_paint_volume_free (&priv->paint_volume);
14570
14571   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
14572     {
14573       priv->paint_volume_valid = TRUE;
14574       return &priv->paint_volume;
14575     }
14576   else
14577     {
14578       priv->paint_volume_valid = FALSE;
14579       return NULL;
14580     }
14581 }
14582
14583 /**
14584  * clutter_actor_get_paint_volume:
14585  * @self: a #ClutterActor
14586  *
14587  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
14588  * when a paint volume can't be determined.
14589  *
14590  * The paint volume is defined as the 3D space occupied by an actor
14591  * when being painted.
14592  *
14593  * This function will call the <function>get_paint_volume()</function>
14594  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
14595  * should not usually care about overriding the default implementation,
14596  * unless they are, for instance: painting outside their allocation, or
14597  * actors with a depth factor (not in terms of #ClutterActor:depth but real
14598  * 3D depth).
14599  *
14600  * <note>2D actors overriding <function>get_paint_volume()</function>
14601  * ensure their volume has a depth of 0. (This will be true so long as
14602  * you don't call clutter_paint_volume_set_depth().)</note>
14603  *
14604  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
14605  *   or %NULL if no volume could be determined. The returned pointer
14606  *   is not guaranteed to be valid across multiple frames; if you want
14607  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
14608  *
14609  * Since: 1.6
14610  */
14611 const ClutterPaintVolume *
14612 clutter_actor_get_paint_volume (ClutterActor *self)
14613 {
14614   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14615
14616   return _clutter_actor_get_paint_volume_mutable (self);
14617 }
14618
14619 /**
14620  * clutter_actor_get_transformed_paint_volume:
14621  * @self: a #ClutterActor
14622  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
14623  *    (or %NULL for the stage)
14624  *
14625  * Retrieves the 3D paint volume of an actor like
14626  * clutter_actor_get_paint_volume() does (Please refer to the
14627  * documentation of clutter_actor_get_paint_volume() for more
14628  * details.) and it additionally transforms the paint volume into the
14629  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
14630  * is passed for @relative_to_ancestor)
14631  *
14632  * This can be used by containers that base their paint volume on
14633  * the volume of their children. Such containers can query the
14634  * transformed paint volume of all of its children and union them
14635  * together using clutter_paint_volume_union().
14636  *
14637  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
14638  *   or %NULL if no volume could be determined. The returned pointer is
14639  *   not guaranteed to be valid across multiple frames; if you wish to
14640  *   keep it, you will have to copy it using clutter_paint_volume_copy().
14641  *
14642  * Since: 1.6
14643  */
14644 const ClutterPaintVolume *
14645 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
14646                                             ClutterActor *relative_to_ancestor)
14647 {
14648   const ClutterPaintVolume *volume;
14649   ClutterActor *stage;
14650   ClutterPaintVolume *transformed_volume;
14651
14652   stage = _clutter_actor_get_stage_internal (self);
14653   if (G_UNLIKELY (stage == NULL))
14654     return NULL;
14655
14656   if (relative_to_ancestor == NULL)
14657     relative_to_ancestor = stage;
14658
14659   volume = clutter_actor_get_paint_volume (self);
14660   if (volume == NULL)
14661     return NULL;
14662
14663   transformed_volume =
14664     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
14665
14666   _clutter_paint_volume_copy_static (volume, transformed_volume);
14667
14668   _clutter_paint_volume_transform_relative (transformed_volume,
14669                                             relative_to_ancestor);
14670
14671   return transformed_volume;
14672 }
14673
14674 /**
14675  * clutter_actor_get_paint_box:
14676  * @self: a #ClutterActor
14677  * @box: (out): return location for a #ClutterActorBox
14678  *
14679  * Retrieves the paint volume of the passed #ClutterActor, and
14680  * transforms it into a 2D bounding box in stage coordinates.
14681  *
14682  * This function is useful to determine the on screen area occupied by
14683  * the actor. The box is only an approximation and may often be
14684  * considerably larger due to the optimizations used to calculate the
14685  * box. The box is never smaller though, so it can reliably be used
14686  * for culling.
14687  *
14688  * There are times when a 2D paint box can't be determined, e.g.
14689  * because the actor isn't yet parented under a stage or because
14690  * the actor is unable to determine a paint volume.
14691  *
14692  * Return value: %TRUE if a 2D paint box could be determined, else
14693  * %FALSE.
14694  *
14695  * Since: 1.6
14696  */
14697 gboolean
14698 clutter_actor_get_paint_box (ClutterActor    *self,
14699                              ClutterActorBox *box)
14700 {
14701   ClutterActor *stage;
14702   ClutterPaintVolume *pv;
14703
14704   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14705   g_return_val_if_fail (box != NULL, FALSE);
14706
14707   stage = _clutter_actor_get_stage_internal (self);
14708   if (G_UNLIKELY (!stage))
14709     return FALSE;
14710
14711   pv = _clutter_actor_get_paint_volume_mutable (self);
14712   if (G_UNLIKELY (!pv))
14713     return FALSE;
14714
14715   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
14716
14717   return TRUE;
14718 }
14719
14720 /**
14721  * clutter_actor_has_overlaps:
14722  * @self: A #ClutterActor
14723  *
14724  * Asks the actor's implementation whether it may contain overlapping
14725  * primitives.
14726  *
14727  * For example; Clutter may use this to determine whether the painting
14728  * should be redirected to an offscreen buffer to correctly implement
14729  * the opacity property.
14730  *
14731  * Custom actors can override the default response by implementing the
14732  * #ClutterActor <function>has_overlaps</function> virtual function. See
14733  * clutter_actor_set_offscreen_redirect() for more information.
14734  *
14735  * Return value: %TRUE if the actor may have overlapping primitives, and
14736  *   %FALSE otherwise
14737  *
14738  * Since: 1.8
14739  */
14740 gboolean
14741 clutter_actor_has_overlaps (ClutterActor *self)
14742 {
14743   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14744
14745   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
14746 }
14747
14748 /**
14749  * clutter_actor_has_effects:
14750  * @self: A #ClutterActor
14751  *
14752  * Returns whether the actor has any effects applied.
14753  *
14754  * Return value: %TRUE if the actor has any effects,
14755  *   %FALSE otherwise
14756  *
14757  * Since: 1.10
14758  */
14759 gboolean
14760 clutter_actor_has_effects (ClutterActor *self)
14761 {
14762   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14763
14764   if (self->priv->effects == NULL)
14765     return FALSE;
14766
14767   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
14768 }
14769
14770 /**
14771  * clutter_actor_has_constraints:
14772  * @self: A #ClutterActor
14773  *
14774  * Returns whether the actor has any constraints applied.
14775  *
14776  * Return value: %TRUE if the actor has any constraints,
14777  *   %FALSE otherwise
14778  *
14779  * Since: 1.10
14780  */
14781 gboolean
14782 clutter_actor_has_constraints (ClutterActor *self)
14783 {
14784   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14785
14786   return self->priv->constraints != NULL;
14787 }
14788
14789 /**
14790  * clutter_actor_has_actions:
14791  * @self: A #ClutterActor
14792  *
14793  * Returns whether the actor has any actions applied.
14794  *
14795  * Return value: %TRUE if the actor has any actions,
14796  *   %FALSE otherwise
14797  *
14798  * Since: 1.10
14799  */
14800 gboolean
14801 clutter_actor_has_actions (ClutterActor *self)
14802 {
14803   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14804
14805   return self->priv->actions != NULL;
14806 }
14807
14808 /**
14809  * clutter_actor_get_n_children:
14810  * @self: a #ClutterActor
14811  *
14812  * Retrieves the number of children of @self.
14813  *
14814  * Return value: the number of children of an actor
14815  *
14816  * Since: 1.10
14817  */
14818 gint
14819 clutter_actor_get_n_children (ClutterActor *self)
14820 {
14821   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14822
14823   return self->priv->n_children;
14824 }
14825
14826 /**
14827  * clutter_actor_get_child_at_index:
14828  * @self: a #ClutterActor
14829  * @index_: the position in the list of children
14830  *
14831  * Retrieves the actor at the given @index_ inside the list of
14832  * children of @self.
14833  *
14834  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
14835  *
14836  * Since: 1.10
14837  */
14838 ClutterActor *
14839 clutter_actor_get_child_at_index (ClutterActor *self,
14840                                   gint          index_)
14841 {
14842   ClutterActor *iter;
14843   int i;
14844
14845   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14846   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
14847
14848   for (iter = self->priv->first_child, i = 0;
14849        iter != NULL && i < index_;
14850        iter = iter->priv->next_sibling, i += 1)
14851     ;
14852
14853   return iter;
14854 }
14855
14856 /*< private >
14857  * _clutter_actor_foreach_child:
14858  * @actor: The actor whos children you want to iterate
14859  * @callback: The function to call for each child
14860  * @user_data: Private data to pass to @callback
14861  *
14862  * Calls a given @callback once for each child of the specified @actor and
14863  * passing the @user_data pointer each time.
14864  *
14865  * Return value: returns %TRUE if all children were iterated, else
14866  *    %FALSE if a callback broke out of iteration early.
14867  */
14868 gboolean
14869 _clutter_actor_foreach_child (ClutterActor           *self,
14870                               ClutterForeachCallback  callback,
14871                               gpointer                user_data)
14872 {
14873   ClutterActorPrivate *priv = self->priv;
14874   ClutterActor *iter;
14875   gboolean cont;
14876
14877   for (cont = TRUE, iter = priv->first_child;
14878        cont && iter != NULL;
14879        iter = iter->priv->next_sibling)
14880     {
14881       cont = callback (iter, user_data);
14882     }
14883
14884   return cont;
14885 }
14886
14887 /* For debugging purposes this gives us a simple way to print out
14888  * the scenegraph e.g in gdb using:
14889  * [|
14890  *   _clutter_actor_traverse (stage,
14891  *                            0,
14892  *                            _clutter_debug_print_actor_cb,
14893  *                            NULL,
14894  *                            NULL);
14895  * |]
14896  */
14897 ClutterActorTraverseVisitFlags
14898 _clutter_debug_print_actor_cb (ClutterActor *actor,
14899                                int depth,
14900                                void *user_data)
14901 {
14902   g_print ("%*s%s:%p\n",
14903            depth * 2, "",
14904            _clutter_actor_get_debug_name (actor),
14905            actor);
14906
14907   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14908 }
14909
14910 static void
14911 _clutter_actor_traverse_breadth (ClutterActor           *actor,
14912                                  ClutterTraverseCallback callback,
14913                                  gpointer                user_data)
14914 {
14915   GQueue *queue = g_queue_new ();
14916   ClutterActor dummy;
14917   int current_depth = 0;
14918
14919   g_queue_push_tail (queue, actor);
14920   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
14921
14922   while ((actor = g_queue_pop_head (queue)))
14923     {
14924       ClutterActorTraverseVisitFlags flags;
14925
14926       if (actor == &dummy)
14927         {
14928           current_depth++;
14929           g_queue_push_tail (queue, &dummy);
14930           continue;
14931         }
14932
14933       flags = callback (actor, current_depth, user_data);
14934       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14935         break;
14936       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14937         {
14938           ClutterActor *iter;
14939
14940           for (iter = actor->priv->first_child;
14941                iter != NULL;
14942                iter = iter->priv->next_sibling)
14943             {
14944               g_queue_push_tail (queue, iter);
14945             }
14946         }
14947     }
14948
14949   g_queue_free (queue);
14950 }
14951
14952 static ClutterActorTraverseVisitFlags
14953 _clutter_actor_traverse_depth (ClutterActor           *actor,
14954                                ClutterTraverseCallback before_children_callback,
14955                                ClutterTraverseCallback after_children_callback,
14956                                int                     current_depth,
14957                                gpointer                user_data)
14958 {
14959   ClutterActorTraverseVisitFlags flags;
14960
14961   flags = before_children_callback (actor, current_depth, user_data);
14962   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14963     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14964
14965   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14966     {
14967       ClutterActor *iter;
14968
14969       for (iter = actor->priv->first_child;
14970            iter != NULL;
14971            iter = iter->priv->next_sibling)
14972         {
14973           flags = _clutter_actor_traverse_depth (iter,
14974                                                  before_children_callback,
14975                                                  after_children_callback,
14976                                                  current_depth + 1,
14977                                                  user_data);
14978
14979           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14980             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14981         }
14982     }
14983
14984   if (after_children_callback)
14985     return after_children_callback (actor, current_depth, user_data);
14986   else
14987     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14988 }
14989
14990 /* _clutter_actor_traverse:
14991  * @actor: The actor to start traversing the graph from
14992  * @flags: These flags may affect how the traversal is done
14993  * @before_children_callback: A function to call before visiting the
14994  *   children of the current actor.
14995  * @after_children_callback: A function to call after visiting the
14996  *   children of the current actor. (Ignored if
14997  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
14998  * @user_data: The private data to pass to the callbacks
14999  *
15000  * Traverses the scenegraph starting at the specified @actor and
15001  * descending through all its children and its children's children.
15002  * For each actor traversed @before_children_callback and
15003  * @after_children_callback are called with the specified
15004  * @user_data, before and after visiting that actor's children.
15005  *
15006  * The callbacks can return flags that affect the ongoing traversal
15007  * such as by skipping over an actors children or bailing out of
15008  * any further traversing.
15009  */
15010 void
15011 _clutter_actor_traverse (ClutterActor              *actor,
15012                          ClutterActorTraverseFlags  flags,
15013                          ClutterTraverseCallback    before_children_callback,
15014                          ClutterTraverseCallback    after_children_callback,
15015                          gpointer                   user_data)
15016 {
15017   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15018     _clutter_actor_traverse_breadth (actor,
15019                                      before_children_callback,
15020                                      user_data);
15021   else /* DEPTH_FIRST */
15022     _clutter_actor_traverse_depth (actor,
15023                                    before_children_callback,
15024                                    after_children_callback,
15025                                    0, /* start depth */
15026                                    user_data);
15027 }
15028
15029 static void
15030 on_layout_manager_changed (ClutterLayoutManager *manager,
15031                            ClutterActor         *self)
15032 {
15033   clutter_actor_queue_relayout (self);
15034 }
15035
15036 /**
15037  * clutter_actor_set_layout_manager:
15038  * @self: a #ClutterActor
15039  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15040  *
15041  * Sets the #ClutterLayoutManager delegate object that will be used to
15042  * lay out the children of @self.
15043  *
15044  * The #ClutterActor will take a reference on the passed @manager which
15045  * will be released either when the layout manager is removed, or when
15046  * the actor is destroyed.
15047  *
15048  * Since: 1.10
15049  */
15050 void
15051 clutter_actor_set_layout_manager (ClutterActor         *self,
15052                                   ClutterLayoutManager *manager)
15053 {
15054   ClutterActorPrivate *priv;
15055
15056   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15057   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15058
15059   priv = self->priv;
15060
15061   if (priv->layout_manager != NULL)
15062     {
15063       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15064                                             G_CALLBACK (on_layout_manager_changed),
15065                                             self);
15066       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15067       g_object_unref (priv->layout_manager);
15068     }
15069
15070   priv->layout_manager = manager;
15071
15072   if (priv->layout_manager != NULL)
15073     {
15074       g_object_ref_sink (priv->layout_manager);
15075       clutter_layout_manager_set_container (priv->layout_manager,
15076                                             CLUTTER_CONTAINER (self));
15077       g_signal_connect (priv->layout_manager, "layout-changed",
15078                         G_CALLBACK (on_layout_manager_changed),
15079                         self);
15080     }
15081
15082   clutter_actor_queue_relayout (self);
15083
15084   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15085 }
15086
15087 /**
15088  * clutter_actor_get_layout_manager:
15089  * @self: a #ClutterActor
15090  *
15091  * Retrieves the #ClutterLayoutManager used by @self.
15092  *
15093  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15094  *   or %NULL
15095  *
15096  * Since: 1.10
15097  */
15098 ClutterLayoutManager *
15099 clutter_actor_get_layout_manager (ClutterActor *self)
15100 {
15101   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15102
15103   return self->priv->layout_manager;
15104 }
15105
15106 static const ClutterLayoutInfo default_layout_info = {
15107   0.f,                          /* fixed-x */
15108   0.f,                          /* fixed-y */
15109   { 0, 0, 0, 0 },               /* margin */
15110   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15111   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15112   0.f, 0.f,                     /* min_width, natural_width */
15113   0.f, 0.f,                     /* natual_width, natural_height */
15114 };
15115
15116 static void
15117 layout_info_free (gpointer data)
15118 {
15119   if (G_LIKELY (data != NULL))
15120     g_slice_free (ClutterLayoutInfo, data);
15121 }
15122
15123 /*< private >
15124  * _clutter_actor_get_layout_info:
15125  * @self: a #ClutterActor
15126  *
15127  * Retrieves a pointer to the ClutterLayoutInfo structure.
15128  *
15129  * If the actor does not have a ClutterLayoutInfo associated to it, one
15130  * will be created and initialized to the default values.
15131  *
15132  * This function should be used for setters.
15133  *
15134  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15135  * instead.
15136  *
15137  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15138  */
15139 ClutterLayoutInfo *
15140 _clutter_actor_get_layout_info (ClutterActor *self)
15141 {
15142   ClutterLayoutInfo *retval;
15143
15144   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15145   if (retval == NULL)
15146     {
15147       retval = g_slice_new (ClutterLayoutInfo);
15148
15149       *retval = default_layout_info;
15150
15151       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15152                                retval,
15153                                layout_info_free);
15154     }
15155
15156   return retval;
15157 }
15158
15159 /*< private >
15160  * _clutter_actor_get_layout_info_or_defaults:
15161  * @self: a #ClutterActor
15162  *
15163  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15164  *
15165  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15166  * then the default structure will be returned.
15167  *
15168  * This function should only be used for getters.
15169  *
15170  * Return value: a const pointer to the ClutterLayoutInfo structure
15171  */
15172 const ClutterLayoutInfo *
15173 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15174 {
15175   const ClutterLayoutInfo *info;
15176
15177   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15178   if (info == NULL)
15179     return &default_layout_info;
15180
15181   return info;
15182 }
15183
15184 /**
15185  * clutter_actor_set_x_align:
15186  * @self: a #ClutterActor
15187  * @x_align: the horizontal alignment policy
15188  *
15189  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15190  * actor received extra horizontal space.
15191  *
15192  * See also the #ClutterActor:x-align property.
15193  *
15194  * Since: 1.10
15195  */
15196 void
15197 clutter_actor_set_x_align (ClutterActor      *self,
15198                            ClutterActorAlign  x_align)
15199 {
15200   ClutterLayoutInfo *info;
15201
15202   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15203
15204   info = _clutter_actor_get_layout_info (self);
15205
15206   if (info->x_align != x_align)
15207     {
15208       info->x_align = x_align;
15209
15210       clutter_actor_queue_relayout (self);
15211
15212       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15213     }
15214 }
15215
15216 /**
15217  * clutter_actor_get_x_align:
15218  * @self: a #ClutterActor
15219  *
15220  * Retrieves the horizontal alignment policy set using
15221  * clutter_actor_set_x_align().
15222  *
15223  * Return value: the horizontal alignment policy.
15224  *
15225  * Since: 1.10
15226  */
15227 ClutterActorAlign
15228 clutter_actor_get_x_align (ClutterActor *self)
15229 {
15230   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15231
15232   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15233 }
15234
15235 /**
15236  * clutter_actor_set_y_align:
15237  * @self: a #ClutterActor
15238  * @y_align: the vertical alignment policy
15239  *
15240  * Sets the vertical alignment policy of a #ClutterActor, in case the
15241  * actor received extra vertical space.
15242  *
15243  * See also the #ClutterActor:y-align property.
15244  *
15245  * Since: 1.10
15246  */
15247 void
15248 clutter_actor_set_y_align (ClutterActor      *self,
15249                            ClutterActorAlign  y_align)
15250 {
15251   ClutterLayoutInfo *info;
15252
15253   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15254
15255   info = _clutter_actor_get_layout_info (self);
15256
15257   if (info->y_align != y_align)
15258     {
15259       info->y_align = y_align;
15260
15261       clutter_actor_queue_relayout (self);
15262
15263       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15264     }
15265 }
15266
15267 /**
15268  * clutter_actor_get_y_align:
15269  * @self: a #ClutterActor
15270  *
15271  * Retrieves the vertical alignment policy set using
15272  * clutter_actor_set_y_align().
15273  *
15274  * Return value: the vertical alignment policy.
15275  *
15276  * Since: 1.10
15277  */
15278 ClutterActorAlign
15279 clutter_actor_get_y_align (ClutterActor *self)
15280 {
15281   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15282
15283   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15284 }
15285
15286
15287 /**
15288  * clutter_margin_new:
15289  *
15290  * Creates a new #ClutterMargin.
15291  *
15292  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15293  *   clutter_margin_free() to free the resources associated with it when
15294  *   done.
15295  *
15296  * Since: 1.10
15297  */
15298 ClutterMargin *
15299 clutter_margin_new (void)
15300 {
15301   return g_slice_new0 (ClutterMargin);
15302 }
15303
15304 /**
15305  * clutter_margin_copy:
15306  * @margin_: a #ClutterMargin
15307  *
15308  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15309  * the newly created structure.
15310  *
15311  * Return value: (transfer full): a copy of the #ClutterMargin.
15312  *
15313  * Since: 1.10
15314  */
15315 ClutterMargin *
15316 clutter_margin_copy (const ClutterMargin *margin_)
15317 {
15318   if (G_LIKELY (margin_ != NULL))
15319     return g_slice_dup (ClutterMargin, margin_);
15320
15321   return NULL;
15322 }
15323
15324 /**
15325  * clutter_margin_free:
15326  * @margin_: a #ClutterMargin
15327  *
15328  * Frees the resources allocated by clutter_margin_new() and
15329  * clutter_margin_copy().
15330  *
15331  * Since: 1.10
15332  */
15333 void
15334 clutter_margin_free (ClutterMargin *margin_)
15335 {
15336   if (G_LIKELY (margin_ != NULL))
15337     g_slice_free (ClutterMargin, margin_);
15338 }
15339
15340 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15341                      clutter_margin_copy,
15342                      clutter_margin_free)
15343
15344 /**
15345  * clutter_actor_set_margin:
15346  * @self: a #ClutterActor
15347  * @margin: a #ClutterMargin
15348  *
15349  * Sets all the components of the margin of a #ClutterActor.
15350  *
15351  * Since: 1.10
15352  */
15353 void
15354 clutter_actor_set_margin (ClutterActor        *self,
15355                           const ClutterMargin *margin)
15356 {
15357   ClutterLayoutInfo *info;
15358   gboolean changed;
15359   GObject *obj;
15360
15361   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15362   g_return_if_fail (margin != NULL);
15363
15364   obj = G_OBJECT (self);
15365   changed = FALSE;
15366
15367   g_object_freeze_notify (obj);
15368
15369   info = _clutter_actor_get_layout_info (self);
15370
15371   if (info->margin.top != margin->top)
15372     {
15373       info->margin.top = margin->top;
15374       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15375       changed = TRUE;
15376     }
15377
15378   if (info->margin.right != margin->right)
15379     {
15380       info->margin.right = margin->right;
15381       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15382       changed = TRUE;
15383     }
15384
15385   if (info->margin.bottom != margin->bottom)
15386     {
15387       info->margin.bottom = margin->bottom;
15388       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15389       changed = TRUE;
15390     }
15391
15392   if (info->margin.left != margin->left)
15393     {
15394       info->margin.left = margin->left;
15395       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15396       changed = TRUE;
15397     }
15398
15399   if (changed)
15400     clutter_actor_queue_relayout (self);
15401
15402   g_object_thaw_notify (obj);
15403 }
15404
15405 /**
15406  * clutter_actor_get_margin:
15407  * @self: a #ClutterActor
15408  * @margin: (out caller-allocates): return location for a #ClutterMargin
15409  *
15410  * Retrieves all the components of the margin of a #ClutterActor.
15411  *
15412  * Since: 1.10
15413  */
15414 void
15415 clutter_actor_get_margin (ClutterActor  *self,
15416                           ClutterMargin *margin)
15417 {
15418   const ClutterLayoutInfo *info;
15419
15420   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15421   g_return_if_fail (margin != NULL);
15422
15423   info = _clutter_actor_get_layout_info_or_defaults (self);
15424
15425   *margin = info->margin;
15426 }
15427
15428 /**
15429  * clutter_actor_set_margin_top:
15430  * @self: a #ClutterActor
15431  * @margin: the top margin
15432  *
15433  * Sets the margin from the top of a #ClutterActor.
15434  *
15435  * Since: 1.10
15436  */
15437 void
15438 clutter_actor_set_margin_top (ClutterActor *self,
15439                               gfloat        margin)
15440 {
15441   ClutterLayoutInfo *info;
15442
15443   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15444   g_return_if_fail (margin >= 0.f);
15445
15446   info = _clutter_actor_get_layout_info (self);
15447
15448   if (info->margin.top == margin)
15449     return;
15450
15451   info->margin.top = margin;
15452
15453   clutter_actor_queue_relayout (self);
15454
15455   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15456 }
15457
15458 /**
15459  * clutter_actor_get_margin_top:
15460  * @self: a #ClutterActor
15461  *
15462  * Retrieves the top margin of a #ClutterActor.
15463  *
15464  * Return value: the top margin
15465  *
15466  * Since: 1.10
15467  */
15468 gfloat
15469 clutter_actor_get_margin_top (ClutterActor *self)
15470 {
15471   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15472
15473   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15474 }
15475
15476 /**
15477  * clutter_actor_set_margin_bottom:
15478  * @self: a #ClutterActor
15479  * @margin: the bottom margin
15480  *
15481  * Sets the margin from the bottom of a #ClutterActor.
15482  *
15483  * Since: 1.10
15484  */
15485 void
15486 clutter_actor_set_margin_bottom (ClutterActor *self,
15487                                  gfloat        margin)
15488 {
15489   ClutterLayoutInfo *info;
15490
15491   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15492   g_return_if_fail (margin >= 0.f);
15493
15494   info = _clutter_actor_get_layout_info (self);
15495
15496   if (info->margin.bottom == margin)
15497     return;
15498
15499   info->margin.bottom = margin;
15500
15501   clutter_actor_queue_relayout (self);
15502
15503   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
15504 }
15505
15506 /**
15507  * clutter_actor_get_margin_bottom:
15508  * @self: a #ClutterActor
15509  *
15510  * Retrieves the bottom margin of a #ClutterActor.
15511  *
15512  * Return value: the bottom margin
15513  *
15514  * Since: 1.10
15515  */
15516 gfloat
15517 clutter_actor_get_margin_bottom (ClutterActor *self)
15518 {
15519   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15520
15521   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
15522 }
15523
15524 /**
15525  * clutter_actor_set_margin_left:
15526  * @self: a #ClutterActor
15527  * @margin: the left margin
15528  *
15529  * Sets the margin from the left of a #ClutterActor.
15530  *
15531  * Since: 1.10
15532  */
15533 void
15534 clutter_actor_set_margin_left (ClutterActor *self,
15535                                gfloat        margin)
15536 {
15537   ClutterLayoutInfo *info;
15538
15539   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15540   g_return_if_fail (margin >= 0.f);
15541
15542   info = _clutter_actor_get_layout_info (self);
15543
15544   if (info->margin.left == margin)
15545     return;
15546
15547   info->margin.left = margin;
15548
15549   clutter_actor_queue_relayout (self);
15550
15551   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
15552 }
15553
15554 /**
15555  * clutter_actor_get_margin_left:
15556  * @self: a #ClutterActor
15557  *
15558  * Retrieves the left margin of a #ClutterActor.
15559  *
15560  * Return value: the left margin
15561  *
15562  * Since: 1.10
15563  */
15564 gfloat
15565 clutter_actor_get_margin_left (ClutterActor *self)
15566 {
15567   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15568
15569   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
15570 }
15571
15572 /**
15573  * clutter_actor_set_margin_right:
15574  * @self: a #ClutterActor
15575  * @margin: the right margin
15576  *
15577  * Sets the margin from the right of a #ClutterActor.
15578  *
15579  * Since: 1.10
15580  */
15581 void
15582 clutter_actor_set_margin_right (ClutterActor *self,
15583                                 gfloat        margin)
15584 {
15585   ClutterLayoutInfo *info;
15586
15587   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15588   g_return_if_fail (margin >= 0.f);
15589
15590   info = _clutter_actor_get_layout_info (self);
15591
15592   if (info->margin.right == margin)
15593     return;
15594
15595   info->margin.right = margin;
15596
15597   clutter_actor_queue_relayout (self);
15598
15599   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
15600 }
15601
15602 /**
15603  * clutter_actor_get_margin_right:
15604  * @self: a #ClutterActor
15605  *
15606  * Retrieves the right margin of a #ClutterActor.
15607  *
15608  * Return value: the right margin
15609  *
15610  * Since: 1.10
15611  */
15612 gfloat
15613 clutter_actor_get_margin_right (ClutterActor *self)
15614 {
15615   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15616
15617   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
15618 }
15619
15620 /**
15621  * clutter_actor_set_background_color:
15622  * @self: a #ClutterActor
15623  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
15624  *  set color
15625  *
15626  * Sets the background color of a #ClutterActor.
15627  *
15628  * The background color will be used to cover the whole allocation of the
15629  * actor. The default background color of an actor is transparent.
15630  *
15631  * To check whether an actor has a background color, you can use the
15632  * #ClutterActor:background-color-set actor property.
15633  *
15634  * Since: 1.10
15635  */
15636 void
15637 clutter_actor_set_background_color (ClutterActor       *self,
15638                                     const ClutterColor *color)
15639 {
15640   ClutterActorPrivate *priv;
15641
15642   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15643
15644   priv = self->priv;
15645
15646   if (color == NULL)
15647     {
15648       priv->bg_color_set = FALSE;
15649       g_object_notify_by_pspec (G_OBJECT (self),
15650                                 obj_props[PROP_BACKGROUND_COLOR_SET]);
15651       return;
15652     }
15653
15654   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
15655     return;
15656
15657   priv->bg_color = *color;
15658   priv->bg_color_set = TRUE;
15659
15660   clutter_actor_queue_redraw (self);
15661
15662   g_object_notify_by_pspec (G_OBJECT (self),
15663                             obj_props[PROP_BACKGROUND_COLOR_SET]);
15664   g_object_notify_by_pspec (G_OBJECT (self),
15665                             obj_props[PROP_BACKGROUND_COLOR]);
15666 }
15667
15668 /**
15669  * clutter_actor_get_background_color:
15670  * @self: a #ClutterActor
15671  * @color: (out caller-allocates): return location for a #ClutterColor
15672  *
15673  * Retrieves the color set using clutter_actor_set_background_color().
15674  *
15675  * Since: 1.10
15676  */
15677 void
15678 clutter_actor_get_background_color (ClutterActor *self,
15679                                     ClutterColor *color)
15680 {
15681   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15682   g_return_if_fail (color != NULL);
15683
15684   *color = self->priv->bg_color;
15685 }
15686
15687 /**
15688  * clutter_actor_get_previous_sibling:
15689  * @self: a #ClutterActor
15690  *
15691  * Retrieves the sibling of @self that comes before it in the list
15692  * of children of @self's parent.
15693  *
15694  * The returned pointer is only valid until the scene graph changes; it
15695  * is not safe to modify the list of children of @self while iterating
15696  * it.
15697  *
15698  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15699  *
15700  * Since: 1.10
15701  */
15702 ClutterActor *
15703 clutter_actor_get_previous_sibling (ClutterActor *self)
15704 {
15705   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15706
15707   return self->priv->prev_sibling;
15708 }
15709
15710 /**
15711  * clutter_actor_get_next_sibling:
15712  * @self: a #ClutterActor
15713  *
15714  * Retrieves the sibling of @self that comes after it in the list
15715  * of children of @self's parent.
15716  *
15717  * The returned pointer is only valid until the scene graph changes; it
15718  * is not safe to modify the list of children of @self while iterating
15719  * it.
15720  *
15721  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15722  *
15723  * Since: 1.10
15724  */
15725 ClutterActor *
15726 clutter_actor_get_next_sibling (ClutterActor *self)
15727 {
15728   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15729
15730   return self->priv->next_sibling;
15731 }
15732
15733 /**
15734  * clutter_actor_get_first_child:
15735  * @self: a #ClutterActor
15736  *
15737  * Retrieves the first child of @self.
15738  *
15739  * The returned pointer is only valid until the scene graph changes; it
15740  * is not safe to modify the list of children of @self while iterating
15741  * it.
15742  *
15743  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15744  *
15745  * Since: 1.10
15746  */
15747 ClutterActor *
15748 clutter_actor_get_first_child (ClutterActor *self)
15749 {
15750   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15751
15752   return self->priv->first_child;
15753 }
15754
15755 /**
15756  * clutter_actor_get_last_child:
15757  * @self: a #ClutterActor
15758  *
15759  * Retrieves the last child of @self.
15760  *
15761  * The returned pointer is only valid until the scene graph changes; it
15762  * is not safe to modify the list of children of @self while iterating
15763  * it.
15764  *
15765  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15766  *
15767  * Since: 1.10
15768  */
15769 ClutterActor *
15770 clutter_actor_get_last_child (ClutterActor *self)
15771 {
15772   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15773
15774   return self->priv->last_child;
15775 }
15776
15777 /* easy way to have properly named fields instead of the dummy ones
15778  * we use in the public structure
15779  */
15780 typedef struct _RealActorIter
15781 {
15782   ClutterActor *root;           /* dummy1 */
15783   ClutterActor *current;        /* dummy2 */
15784   gpointer padding_1;           /* dummy3 */
15785   gint age;                     /* dummy4 */
15786   gpointer padding_2;           /* dummy5 */
15787 } RealActorIter;
15788
15789 /**
15790  * clutter_actor_iter_init:
15791  * @iter: a #ClutterActorIter
15792  * @root: a #ClutterActor
15793  *
15794  * Initializes a #ClutterActorIter, which can then be used to iterate
15795  * efficiently over a section of the scene graph, and associates it
15796  * with @root.
15797  *
15798  * Modifying the scene graph section that contains @root will invalidate
15799  * the iterator.
15800  *
15801  * |[
15802  *   ClutterActorIter iter;
15803  *   ClutterActor *child;
15804  *
15805  *   clutter_actor_iter_init (&iter, container);
15806  *   while (clutter_actor_iter_next (&iter, &child))
15807  *     {
15808  *       /&ast; do something with child &ast;/
15809  *     }
15810  * ]|
15811  *
15812  * Since: 1.10
15813  */
15814 void
15815 clutter_actor_iter_init (ClutterActorIter *iter,
15816                          ClutterActor     *root)
15817 {
15818   RealActorIter *ri = (RealActorIter *) iter;
15819
15820   g_return_if_fail (iter != NULL);
15821   g_return_if_fail (CLUTTER_IS_ACTOR (root));
15822
15823   ri->root = root;
15824   ri->current = NULL;
15825   ri->age = root->priv->age;
15826 }
15827
15828 /**
15829  * clutter_actor_iter_next:
15830  * @iter: a #ClutterActorIter
15831  * @child: (out): return location for a #ClutterActor
15832  *
15833  * Advances the @iter and retrieves the next child of the root #ClutterActor
15834  * that was used to initialize the #ClutterActorIterator.
15835  *
15836  * If the iterator can advance, this function returns %TRUE and sets the
15837  * @child argument.
15838  *
15839  * If the iterator cannot advance, this function returns %FALSE, and
15840  * the contents of @child are undefined.
15841  *
15842  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15843  *
15844  * Since: 1.10
15845  */
15846 gboolean
15847 clutter_actor_iter_next (ClutterActorIter  *iter,
15848                          ClutterActor     **child)
15849 {
15850   RealActorIter *ri = (RealActorIter *) iter;
15851
15852   g_return_val_if_fail (iter != NULL, FALSE);
15853   g_return_val_if_fail (ri->root != NULL, FALSE);
15854 #ifndef G_DISABLE_ASSERT
15855   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15856 #endif
15857
15858   if (ri->current == NULL)
15859     ri->current = ri->root->priv->first_child;
15860   else
15861     ri->current = ri->current->priv->next_sibling;
15862
15863   if (child != NULL)
15864     *child = ri->current;
15865
15866   return ri->current != NULL;
15867 }
15868
15869 /**
15870  * clutter_actor_iter_prev:
15871  * @iter: a #ClutterActorIter
15872  * @child: (out): return location for a #ClutterActor
15873  *
15874  * Advances the @iter and retrieves the previous child of the root
15875  * #ClutterActor that was used to initialize the #ClutterActorIterator.
15876  *
15877  * If the iterator can advance, this function returns %TRUE and sets the
15878  * @child argument.
15879  *
15880  * If the iterator cannot advance, this function returns %FALSE, and
15881  * the contents of @child are undefined.
15882  *
15883  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15884  *
15885  * Since: 1.10
15886  */
15887 gboolean
15888 clutter_actor_iter_prev (ClutterActorIter  *iter,
15889                          ClutterActor     **child)
15890 {
15891   RealActorIter *ri = (RealActorIter *) iter;
15892
15893   g_return_val_if_fail (iter != NULL, FALSE);
15894   g_return_val_if_fail (ri->root != NULL, FALSE);
15895 #ifndef G_DISABLE_ASSERT
15896   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15897 #endif
15898
15899   if (ri->current == NULL)
15900     ri->current = ri->root->priv->last_child;
15901   else
15902     ri->current = ri->current->priv->prev_sibling;
15903
15904   if (child != NULL)
15905     *child = ri->current;
15906
15907   return ri->current != NULL;
15908 }
15909
15910 /**
15911  * clutter_actor_iter_remove:
15912  * @iter: a #ClutterActorIter
15913  *
15914  * Safely removes the #ClutterActor currently pointer to by the iterator
15915  * from its parent.
15916  *
15917  * This function can only be called after clutter_actor_iter_next() or
15918  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15919  * than once for the same actor.
15920  *
15921  * This function will call clutter_actor_remove_child() internally.
15922  *
15923  * Since: 1.10
15924  */
15925 void
15926 clutter_actor_iter_remove (ClutterActorIter *iter)
15927 {
15928   RealActorIter *ri = (RealActorIter *) iter;
15929   ClutterActor *cur;
15930
15931   g_return_if_fail (iter != NULL);
15932   g_return_if_fail (ri->root != NULL);
15933 #ifndef G_DISABLE_ASSERT
15934   g_return_if_fail (ri->age == ri->root->priv->age);
15935 #endif
15936   g_return_if_fail (ri->current != NULL);
15937
15938   cur = ri->current;
15939
15940   if (cur != NULL)
15941     {
15942       ri->current = cur->priv->prev_sibling;
15943
15944       clutter_actor_remove_child_internal (ri->root, cur,
15945                                            REMOVE_CHILD_DEFAULT_FLAGS);
15946
15947       ri->age += 1;
15948     }
15949 }
15950
15951 /**
15952  * clutter_actor_iter_destroy:
15953  * @iter: a #ClutterActorIter
15954  *
15955  * Safely destroys the #ClutterActor currently pointer to by the iterator
15956  * from its parent.
15957  *
15958  * This function can only be called after clutter_actor_iter_next() or
15959  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15960  * than once for the same actor.
15961  *
15962  * This function will call clutter_actor_destroy() internally.
15963  *
15964  * Since: 1.10
15965  */
15966 void
15967 clutter_actor_iter_destroy (ClutterActorIter *iter)
15968 {
15969   RealActorIter *ri = (RealActorIter *) iter;
15970   ClutterActor *cur;
15971
15972   g_return_if_fail (iter != NULL);
15973   g_return_if_fail (ri->root != NULL);
15974 #ifndef G_DISABLE_ASSERT
15975   g_return_if_fail (ri->age == ri->root->priv->age);
15976 #endif
15977   g_return_if_fail (ri->current != NULL);
15978
15979   cur = ri->current;
15980
15981   if (cur != NULL)
15982     {
15983       ri->current = cur->priv->prev_sibling;
15984
15985       clutter_actor_destroy (cur);
15986
15987       ri->age += 1;
15988     }
15989 }