actor: Allow insert_child_at_index to add a child at the end with an index
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: Base abstract class for all visual stage actors.
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="bin-layout">
113  *     <title>Actors</title>
114  *     <graphic fileref="test-actor.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-events">
119  *   <title>Handling events on an actor</title>
120  *   <para>A #ClutterActor can receive and handle input device events, for
121  *   instance pointer events and key events, as long as its
122  *   #ClutterActor:reactive property is set to %TRUE.</para>
123  *   <para>Once an actor has been determined to be the source of an event,
124  *   Clutter will traverse the scene graph from the top-level actor towards the
125  *   event source, emitting the #ClutterActor::captured-event signal on each
126  *   ancestor until it reaches the source; this phase is also called
127  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
128  *   stopped, the graph is walked backwards, from the source actor to the
129  *   top-level, and the #ClutterActor::event signal, along with other event
130  *   signals if needed, is emitted; this phase is also called <emphasis>the
131  *   bubble phase</emphasis>. At any point of the signal emission, signal
132  *   handlers can stop the propagation through the scene graph by returning
133  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
134  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
135  * </refsect2>
136  *
137  * <refsect2 id="ClutterActor-subclassing">
138  *   <title>Implementing an actor</title>
139  *   <para>Careful consideration should be given when deciding to implement
140  *   a #ClutterActor sub-class. It is generally recommended to implement a
141  *   sub-class of #ClutterActor only for actors that should be used as leaf
142  *   nodes of a scene graph.</para>
143  *   <para>If your actor should be painted in a custom way, you should
144  *   override the #ClutterActor::paint signal class handler. You can either
145  *   opt to chain up to the parent class implementation or decide to fully
146  *   override the default paint implementation; Clutter will set up the
147  *   transformations and clip regions prior to emitting the #ClutterActor::paint
148  *   signal.</para>
149  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
150  *   #ClutterActorClass.get_preferred_height() virtual functions it is
151  *   possible to change or provide the preferred size of an actor; similarly,
152  *   by overriding the #ClutterActorClass.allocate() virtual function it is
153  *   possible to control the layout of the children of an actor. Make sure to
154  *   always chain up to the parent implementation of the
155  *   #ClutterActorClass.allocate() virtual function.</para>
156  *   <para>In general, it is strongly encouraged to use delegation and
157  *   composition instead of direct subclassing.</para>
158  * </refsect2>
159  *
160  * <refsect2 id="ClutterActor-script">
161  *   <title>ClutterActor custom properties for #ClutterScript</title>
162  *   <para>#ClutterActor defines a custom "rotation" property which
163  *   allows a short-hand description of the rotations to be applied
164  *   to an actor.</para>
165  *   <para>The syntax of the "rotation" property is the following:</para>
166  *   <informalexample>
167  *     <programlisting>
168  * "rotation" : [
169  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
170  * ]
171  *     </programlisting>
172  *   </informalexample>
173  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
174  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
175  *   floating point value representing the rotation angle on the given axis,
176  *   in degrees.</para>
177  *   <para>The <emphasis>center</emphasis> array is optional, and if present
178  *   it must contain the center of rotation as described by two coordinates:
179  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
180  *   "z-axis".</para>
181  *   <para>#ClutterActor will also parse every positional and dimensional
182  *   property defined as a string through clutter_units_from_string(); you
183  *   should read the documentation for the #ClutterUnits parser format for
184  *   the valid units and syntax.</para>
185  * </refsect2>
186  *
187  * <refsect2 id="ClutterActor-animating">
188  *   <title>Custom animatable properties</title>
189  *   <para>#ClutterActor allows accessing properties of #ClutterAction
190  *   and #ClutterConstraint instances associated to an actor instance
191  *   for animation purposes.</para>
192  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
193  *   property it is necessary to set the #ClutterActorMeta:name property on the
194  *   given action or constraint.</para>
195  *   <para>The property can be accessed using the following syntax:</para>
196  *   <informalexample>
197  *     <programlisting>
198  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
199  *     </programlisting>
200  *   </informalexample>
201  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
202  *   <para>The <emphasis>section</emphasis> fragment can be one between
203  *   "actions", "constraints" and "effects".</para>
204  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
205  *   action or constraint, as specified by the #ClutterActorMeta:name
206  *   property.</para>
207  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
208  *   action or constraint property to be animated.</para>
209  *   <para>The example below animates a #ClutterBindConstraint applied to an
210  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
211  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
212  *   its initial state is fully transparent and overlapping the actor to
213  *   which is bound to. </para>
214  *   <informalexample><programlisting>
215  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
216  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
217  * clutter_actor_add_constraint (rect, constraint);
218  *
219  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
220  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
221  * clutter_actor_add_constraint (rect, constraint);
222  *
223  * clutter_actor_set_reactive (rect, TRUE);
224  * clutter_actor_set_opacity (rect, 0);
225  *
226  * g_signal_connect (rect, "button-press-event",
227  *                   G_CALLBACK (on_button_press),
228  *                   NULL);
229  *   </programlisting></informalexample>
230  *   <para>On button press, the rectangle "slides" from behind the actor to
231  *   which is bound to, using the #ClutterBindConstraint:offset property and
232  *   the #ClutterActor:opacity property.</para>
233  *   <informalexample><programlisting>
234  * float new_offset = clutter_actor_get_width (origin) + h_padding;
235  *
236  * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
237  *                        "opacity", 255,
238  *                        "@constraints.bind-x.offset", new_offset,
239  *                        NULL);
240  *   </programlisting></informalexample>
241  * </refsect2>
242  */
243
244 /**
245  * CLUTTER_ACTOR_IS_MAPPED:
246  * @a: a #ClutterActor
247  *
248  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
249  *
250  * The mapped state is set when the actor is visible and all its parents up
251  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
252  *
253  * This check can be used to see if an actor is going to be painted, as only
254  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
255  *
256  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
257  * not be checked directly; instead, the recommended usage is to connect a
258  * handler on the #GObject::notify signal for the #ClutterActor:mapped
259  * property of #ClutterActor, and check the presence of
260  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
261  *
262  * It is also important to note that Clutter may delay the changes of
263  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
264  * limitations, or during the reparenting of an actor, to optimize
265  * unnecessary (and potentially expensive) state changes.
266  *
267  * Since: 0.2
268  */
269
270 /**
271  * CLUTTER_ACTOR_IS_REALIZED:
272  * @a: a #ClutterActor
273  *
274  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
275  *
276  * The realized state has an actor-dependant interpretation. If an
277  * actor wants to delay allocating resources until it is attached to a
278  * stage, it may use the realize state to do so. However it is
279  * perfectly acceptable for an actor to allocate Cogl resources before
280  * being realized because there is only one drawing context used by Clutter
281  * so any resources will work on any stage.  If an actor is mapped it
282  * must also be realized, but an actor can be realized and unmapped
283  * (this is so hiding an actor temporarily doesn't do an expensive
284  * unrealize/realize).
285  *
286  * To be realized an actor must be inside a stage, and all its parents
287  * must be realized.
288  *
289  * Since: 0.2
290  */
291
292 /**
293  * CLUTTER_ACTOR_IS_VISIBLE:
294  * @a: a #ClutterActor
295  *
296  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
297  * Equivalent to the ClutterActor::visible object property.
298  *
299  * Note that an actor is only painted onscreen if it's mapped, which
300  * means it's visible, and all its parents are visible, and one of the
301  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
302  *
303  * Since: 0.2
304  */
305
306 /**
307  * CLUTTER_ACTOR_IS_REACTIVE:
308  * @a: a #ClutterActor
309  *
310  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
311  *
312  * Only reactive actors will receive event-related signals.
313  *
314  * Since: 0.6
315  */
316
317 #ifdef HAVE_CONFIG_H
318 #include "config.h"
319 #endif
320
321 #include <math.h>
322
323 #include "cogl/cogl.h"
324
325 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
326 #define CLUTTER_ENABLE_EXPERIMENTAL_API
327
328 #include "clutter-actor-private.h"
329
330 #include "clutter-action.h"
331 #include "clutter-actor-meta-private.h"
332 #include "clutter-animatable.h"
333 #include "clutter-color-static.h"
334 #include "clutter-color.h"
335 #include "clutter-constraint.h"
336 #include "clutter-container.h"
337 #include "clutter-debug.h"
338 #include "clutter-effect-private.h"
339 #include "clutter-enum-types.h"
340 #include "clutter-fixed-layout.h"
341 #include "clutter-main.h"
342 #include "clutter-marshal.h"
343 #include "clutter-flatten-effect.h"
344 #include "clutter-paint-volume-private.h"
345 #include "clutter-private.h"
346 #include "clutter-profile.h"
347 #include "clutter-scriptable.h"
348 #include "clutter-script-private.h"
349 #include "clutter-stage-private.h"
350 #include "clutter-units.h"
351
352 #include "deprecated/clutter-behaviour.h"
353 #include "deprecated/clutter-container.h"
354
355 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
356 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
357
358 /* Internal enum used to control mapped state update.  This is a hint
359  * which indicates when to do something other than just enforce
360  * invariants.
361  */
362 typedef enum {
363   MAP_STATE_CHECK,           /* just enforce invariants. */
364   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
365                               * used when about to unparent.
366                               */
367   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
368                               * used to set mapped on toplevels.
369                               */
370   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
371                               * used just before unmapping parent.
372                               */
373 } MapStateChange;
374
375 /* 3 entries should be a good compromise, few layout managers
376  * will ask for 3 different preferred size in each allocation cycle */
377 #define N_CACHED_SIZE_REQUESTS 3
378
379 struct _ClutterActorPrivate
380 {
381   /* request mode */
382   ClutterRequestMode request_mode;
383
384   /* our cached size requests for different width / height */
385   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
386   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
387
388   /* An age of 0 means the entry is not set */
389   guint cached_height_age;
390   guint cached_width_age;
391
392   /* the bounding box of the actor, relative to the parent's
393    * allocation
394    */
395   ClutterActorBox allocation;
396   ClutterAllocationFlags allocation_flags;
397
398   /* depth */
399   gfloat z;
400
401   /* clip, in actor coordinates */
402   cairo_rectangle_t clip;
403
404   /* the cached transformation matrix; see apply_transform() */
405   CoglMatrix transform;
406
407   guint8 opacity;
408   gint opacity_override;
409
410   ClutterOffscreenRedirect offscreen_redirect;
411
412   /* This is an internal effect used to implement the
413      offscreen-redirect property */
414   ClutterEffect *flatten_effect;
415
416   /* scene graph */
417   ClutterActor *parent;
418   ClutterActor *prev_sibling;
419   ClutterActor *next_sibling;
420   ClutterActor *first_child;
421   ClutterActor *last_child;
422
423   gint n_children;
424
425   /* tracks whenever the children of an actor are changed; the
426    * age is incremented by 1 whenever an actor is added or
427    * removed. the age is not incremented when the first or the
428    * last child pointers are changed, or when grandchildren of
429    * an actor are changed.
430    */
431   gint age;
432
433   gchar *name; /* a non-unique name, used for debugging */
434   guint32 id; /* unique id, used for backward compatibility */
435
436   gint32 pick_id; /* per-stage unique id, used for picking */
437
438   /* a back-pointer to the Pango context that we can use
439    * to create pre-configured PangoLayout
440    */
441   PangoContext *pango_context;
442
443   /* the text direction configured for this child - either by
444    * application code, or by the actor's parent
445    */
446   ClutterTextDirection text_direction;
447
448   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
449   gint internal_child;
450
451   /* meta classes */
452   ClutterMetaGroup *actions;
453   ClutterMetaGroup *constraints;
454   ClutterMetaGroup *effects;
455
456   /* delegate object used to allocate the children of this actor */
457   ClutterLayoutManager *layout_manager;
458
459   /* used when painting, to update the paint volume */
460   ClutterEffect *current_effect;
461
462   /* This is used to store an effect which needs to be redrawn. A
463      redraw can be queued to start from a particular effect. This is
464      used by parametrised effects that can cache an image of the
465      actor. If a parameter of the effect changes then it only needs to
466      redraw the cached image, not the actual actor. The pointer is
467      only valid if is_dirty == TRUE. If the pointer is NULL then the
468      whole actor is dirty. */
469   ClutterEffect *effect_to_redraw;
470
471   /* This is used when painting effects to implement the
472      clutter_actor_continue_paint() function. It points to the node in
473      the list of effects that is next in the chain */
474   const GList *next_effect_to_paint;
475
476   ClutterPaintVolume paint_volume;
477
478   /* NB: This volume isn't relative to this actor, it is in eye
479    * coordinates so that it can remain valid after the actor changes.
480    */
481   ClutterPaintVolume last_paint_volume;
482
483   ClutterStageQueueRedrawEntry *queue_redraw_entry;
484
485   ClutterColor bg_color;
486
487   /* bitfields */
488
489   /* fixed position and sizes */
490   guint position_set                : 1;
491   guint min_width_set               : 1;
492   guint min_height_set              : 1;
493   guint natural_width_set           : 1;
494   guint natural_height_set          : 1;
495   /* cached request is invalid (implies allocation is too) */
496   guint needs_width_request         : 1;
497   /* cached request is invalid (implies allocation is too) */
498   guint needs_height_request        : 1;
499   /* cached allocation is invalid (request has changed, probably) */
500   guint needs_allocation            : 1;
501   guint show_on_set_parent          : 1;
502   guint has_clip                    : 1;
503   guint clip_to_allocation          : 1;
504   guint enable_model_view_transform : 1;
505   guint enable_paint_unmapped       : 1;
506   guint has_pointer                 : 1;
507   guint propagated_one_redraw       : 1;
508   guint paint_volume_valid          : 1;
509   guint last_paint_volume_valid     : 1;
510   guint in_clone_paint              : 1;
511   guint transform_valid             : 1;
512   /* This is TRUE if anything has queued a redraw since we were last
513      painted. In this case effect_to_redraw will point to an effect
514      the redraw was queued from or it will be NULL if the redraw was
515      queued without an effect. */
516   guint is_dirty                    : 1;
517   guint bg_color_set                : 1;
518 };
519
520 enum
521 {
522   PROP_0,
523
524   PROP_NAME,
525
526   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
527    * when set they force a size request, when gotten they
528    * get the allocation if the allocation is valid, and the
529    * request otherwise
530    */
531   PROP_X,
532   PROP_Y,
533   PROP_WIDTH,
534   PROP_HEIGHT,
535
536   /* Then the rest of these size-related properties are the "actual"
537    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
538    */
539   PROP_FIXED_X,
540   PROP_FIXED_Y,
541
542   PROP_FIXED_POSITION_SET,
543
544   PROP_MIN_WIDTH,
545   PROP_MIN_WIDTH_SET,
546
547   PROP_MIN_HEIGHT,
548   PROP_MIN_HEIGHT_SET,
549
550   PROP_NATURAL_WIDTH,
551   PROP_NATURAL_WIDTH_SET,
552
553   PROP_NATURAL_HEIGHT,
554   PROP_NATURAL_HEIGHT_SET,
555
556   PROP_REQUEST_MODE,
557
558   /* Allocation properties are read-only */
559   PROP_ALLOCATION,
560
561   PROP_DEPTH,
562
563   PROP_CLIP,
564   PROP_HAS_CLIP,
565   PROP_CLIP_TO_ALLOCATION,
566
567   PROP_OPACITY,
568
569   PROP_OFFSCREEN_REDIRECT,
570
571   PROP_VISIBLE,
572   PROP_MAPPED,
573   PROP_REALIZED,
574   PROP_REACTIVE,
575
576   PROP_SCALE_X,
577   PROP_SCALE_Y,
578   PROP_SCALE_CENTER_X,
579   PROP_SCALE_CENTER_Y,
580   PROP_SCALE_GRAVITY,
581
582   PROP_ROTATION_ANGLE_X,
583   PROP_ROTATION_ANGLE_Y,
584   PROP_ROTATION_ANGLE_Z,
585   PROP_ROTATION_CENTER_X,
586   PROP_ROTATION_CENTER_Y,
587   PROP_ROTATION_CENTER_Z,
588   /* This property only makes sense for the z rotation because the
589      others would depend on the actor having a size along the
590      z-axis */
591   PROP_ROTATION_CENTER_Z_GRAVITY,
592
593   PROP_ANCHOR_X,
594   PROP_ANCHOR_Y,
595   PROP_ANCHOR_GRAVITY,
596
597   PROP_SHOW_ON_SET_PARENT,
598
599   PROP_TEXT_DIRECTION,
600   PROP_HAS_POINTER,
601
602   PROP_ACTIONS,
603   PROP_CONSTRAINTS,
604   PROP_EFFECT,
605
606   PROP_LAYOUT_MANAGER,
607
608   PROP_X_ALIGN,
609   PROP_Y_ALIGN,
610   PROP_MARGIN_TOP,
611   PROP_MARGIN_BOTTOM,
612   PROP_MARGIN_LEFT,
613   PROP_MARGIN_RIGHT,
614
615   PROP_BACKGROUND_COLOR,
616   PROP_BACKGROUND_COLOR_SET,
617
618   PROP_FIRST_CHILD,
619   PROP_LAST_CHILD,
620
621   PROP_LAST
622 };
623
624 static GParamSpec *obj_props[PROP_LAST];
625
626 enum
627 {
628   SHOW,
629   HIDE,
630   DESTROY,
631   PARENT_SET,
632   KEY_FOCUS_IN,
633   KEY_FOCUS_OUT,
634   PAINT,
635   PICK,
636   REALIZE,
637   UNREALIZE,
638   QUEUE_REDRAW,
639   QUEUE_RELAYOUT,
640   EVENT,
641   CAPTURED_EVENT,
642   BUTTON_PRESS_EVENT,
643   BUTTON_RELEASE_EVENT,
644   SCROLL_EVENT,
645   KEY_PRESS_EVENT,
646   KEY_RELEASE_EVENT,
647   MOTION_EVENT,
648   ENTER_EVENT,
649   LEAVE_EVENT,
650   ALLOCATION_CHANGED,
651
652   LAST_SIGNAL
653 };
654
655 static guint actor_signals[LAST_SIGNAL] = { 0, };
656
657 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
658 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
659 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
660 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
661
662 /* These setters are all static for now, maybe they should be in the
663  * public API, but they are perhaps obscure enough to leave only as
664  * properties
665  */
666 static void clutter_actor_set_min_width          (ClutterActor *self,
667                                                   gfloat        min_width);
668 static void clutter_actor_set_min_height         (ClutterActor *self,
669                                                   gfloat        min_height);
670 static void clutter_actor_set_natural_width      (ClutterActor *self,
671                                                   gfloat        natural_width);
672 static void clutter_actor_set_natural_height     (ClutterActor *self,
673                                                   gfloat        natural_height);
674 static void clutter_actor_set_min_width_set      (ClutterActor *self,
675                                                   gboolean      use_min_width);
676 static void clutter_actor_set_min_height_set     (ClutterActor *self,
677                                                   gboolean      use_min_height);
678 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
679                                                   gboolean  use_natural_width);
680 static void clutter_actor_set_natural_height_set (ClutterActor *self,
681                                                   gboolean  use_natural_height);
682 static void clutter_actor_update_map_state       (ClutterActor  *self,
683                                                   MapStateChange change);
684 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
685
686 /* Helper routines for managing anchor coords */
687 static void clutter_anchor_coord_get_units (ClutterActor      *self,
688                                             const AnchorCoord *coord,
689                                             gfloat            *x,
690                                             gfloat            *y,
691                                             gfloat            *z);
692 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
693                                             gfloat             x,
694                                             gfloat             y,
695                                             gfloat             z);
696
697 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
698 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
699                                                         ClutterGravity     gravity);
700
701 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
702
703 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
704
705 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
706                                                                ClutterActor *ancestor,
707                                                                CoglMatrix *matrix);
708
709 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
710
711 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
712
713 static void on_layout_manager_changed (ClutterLayoutManager *manager,
714                                        ClutterActor         *self);
715
716 /* Helper macro which translates by the anchor coord, applies the
717    given transformation and then translates back */
718 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
719   gfloat _tx, _ty, _tz;                                                \
720   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
721   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
722   { _transform; }                                                      \
723   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
724
725 static GQuark quark_shader_data = 0;
726 static GQuark quark_actor_layout_info = 0;
727 static GQuark quark_actor_transform_info = 0;
728
729 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
730                          clutter_actor,
731                          G_TYPE_INITIALLY_UNOWNED,
732                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
733                                                 clutter_container_iface_init)
734                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
735                                                 clutter_scriptable_iface_init)
736                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
737                                                 clutter_animatable_iface_init)
738                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
739                                                 atk_implementor_iface_init));
740
741 /*< private >
742  * clutter_actor_get_debug_name:
743  * @actor: a #ClutterActor
744  *
745  * Retrieves a printable name of @actor for debugging messages
746  *
747  * Return value: a string with a printable name
748  */
749 const gchar *
750 _clutter_actor_get_debug_name (ClutterActor *actor)
751 {
752   return actor->priv->name != NULL ? actor->priv->name
753                                    : G_OBJECT_TYPE_NAME (actor);
754 }
755
756 #ifdef CLUTTER_ENABLE_DEBUG
757 /* XXX - this is for debugging only, remove once working (or leave
758  * in only in some debug mode). Should leave it for a little while
759  * until we're confident in the new map/realize/visible handling.
760  */
761 static inline void
762 clutter_actor_verify_map_state (ClutterActor *self)
763 {
764   ClutterActorPrivate *priv = self->priv;
765
766   if (CLUTTER_ACTOR_IS_REALIZED (self))
767     {
768       /* all bets are off during reparent when we're potentially realized,
769        * but should not be according to invariants
770        */
771       if (!CLUTTER_ACTOR_IN_REPARENT (self))
772         {
773           if (priv->parent == NULL)
774             {
775               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
776                 {
777                 }
778               else
779                 g_warning ("Realized non-toplevel actor '%s' should "
780                            "have a parent",
781                            _clutter_actor_get_debug_name (self));
782             }
783           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
784             {
785               g_warning ("Realized actor %s has an unrealized parent %s",
786                          _clutter_actor_get_debug_name (self),
787                          _clutter_actor_get_debug_name (priv->parent));
788             }
789         }
790     }
791
792   if (CLUTTER_ACTOR_IS_MAPPED (self))
793     {
794       if (!CLUTTER_ACTOR_IS_REALIZED (self))
795         g_warning ("Actor '%s' is mapped but not realized",
796                    _clutter_actor_get_debug_name (self));
797
798       /* remaining bets are off during reparent when we're potentially
799        * mapped, but should not be according to invariants
800        */
801       if (!CLUTTER_ACTOR_IN_REPARENT (self))
802         {
803           if (priv->parent == NULL)
804             {
805               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
806                 {
807                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
808                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
809                     {
810                       g_warning ("Toplevel actor '%s' is mapped "
811                                  "but not visible",
812                                  _clutter_actor_get_debug_name (self));
813                     }
814                 }
815               else
816                 {
817                   g_warning ("Mapped actor '%s' should have a parent",
818                              _clutter_actor_get_debug_name (self));
819                 }
820             }
821           else
822             {
823               ClutterActor *iter = self;
824
825               /* check for the enable_paint_unmapped flag on the actor
826                * and parents; if the flag is enabled at any point of this
827                * branch of the scene graph then all the later checks
828                * become pointless
829                */
830               while (iter != NULL)
831                 {
832                   if (iter->priv->enable_paint_unmapped)
833                     return;
834
835                   iter = iter->priv->parent;
836                 }
837
838               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
839                 {
840                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
841                              "is not visible",
842                              _clutter_actor_get_debug_name (self),
843                              _clutter_actor_get_debug_name (priv->parent));
844                 }
845
846               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
847                 {
848                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
849                              "is not realized",
850                              _clutter_actor_get_debug_name (self),
851                              _clutter_actor_get_debug_name (priv->parent));
852                 }
853
854               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
855                 {
856                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
857                     g_warning ("Actor '%s' is mapped but its non-toplevel "
858                                "parent '%s' is not mapped",
859                                _clutter_actor_get_debug_name (self),
860                                _clutter_actor_get_debug_name (priv->parent));
861                 }
862             }
863         }
864     }
865 }
866
867 #endif /* CLUTTER_ENABLE_DEBUG */
868
869 static void
870 clutter_actor_set_mapped (ClutterActor *self,
871                           gboolean      mapped)
872 {
873   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
874     return;
875
876   if (mapped)
877     {
878       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
879       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
880     }
881   else
882     {
883       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
884       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
885     }
886 }
887
888 /* this function updates the mapped and realized states according to
889  * invariants, in the appropriate order.
890  */
891 static void
892 clutter_actor_update_map_state (ClutterActor  *self,
893                                 MapStateChange change)
894 {
895   gboolean was_mapped;
896
897   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
898
899   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
900     {
901       /* the mapped flag on top-level actors must be set by the
902        * per-backend implementation because it might be asynchronous.
903        *
904        * That is, the MAPPED flag on toplevels currently tracks the X
905        * server mapped-ness of the window, while the expected behavior
906        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
907        * This creates some weird complexity by breaking the invariant
908        * that if we're visible and all ancestors shown then we are
909        * also mapped - instead, we are mapped if all ancestors
910        * _possibly excepting_ the stage are mapped. The stage
911        * will map/unmap for example when it is minimized or
912        * moved to another workspace.
913        *
914        * So, the only invariant on the stage is that if visible it
915        * should be realized, and that it has to be visible to be
916        * mapped.
917        */
918       if (CLUTTER_ACTOR_IS_VISIBLE (self))
919         clutter_actor_realize (self);
920
921       switch (change)
922         {
923         case MAP_STATE_CHECK:
924           break;
925
926         case MAP_STATE_MAKE_MAPPED:
927           g_assert (!was_mapped);
928           clutter_actor_set_mapped (self, TRUE);
929           break;
930
931         case MAP_STATE_MAKE_UNMAPPED:
932           g_assert (was_mapped);
933           clutter_actor_set_mapped (self, FALSE);
934           break;
935
936         case MAP_STATE_MAKE_UNREALIZED:
937           /* we only use MAKE_UNREALIZED in unparent,
938            * and unparenting a stage isn't possible.
939            * If someone wants to just unrealize a stage
940            * then clutter_actor_unrealize() doesn't
941            * go through this codepath.
942            */
943           g_warning ("Trying to force unrealize stage is not allowed");
944           break;
945         }
946
947       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
948           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
949           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
950         {
951           g_warning ("Clutter toplevel of type '%s' is not visible, but "
952                      "it is somehow still mapped",
953                      _clutter_actor_get_debug_name (self));
954         }
955     }
956   else
957     {
958       ClutterActorPrivate *priv = self->priv;
959       ClutterActor *parent = priv->parent;
960       gboolean should_be_mapped;
961       gboolean may_be_realized;
962       gboolean must_be_realized;
963
964       should_be_mapped = FALSE;
965       may_be_realized = TRUE;
966       must_be_realized = FALSE;
967
968       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
969         {
970           may_be_realized = FALSE;
971         }
972       else
973         {
974           /* Maintain invariant that if parent is mapped, and we are
975            * visible, then we are mapped ...  unless parent is a
976            * stage, in which case we map regardless of parent's map
977            * state but do require stage to be visible and realized.
978            *
979            * If parent is realized, that does not force us to be
980            * realized; but if parent is unrealized, that does force
981            * us to be unrealized.
982            *
983            * The reason we don't force children to realize with
984            * parents is _clutter_actor_rerealize(); if we require that
985            * a realized parent means children are realized, then to
986            * unrealize an actor we would have to unrealize its
987            * parents, which would end up meaning unrealizing and
988            * hiding the entire stage. So we allow unrealizing a
989            * child (as long as that child is not mapped) while that
990            * child still has a realized parent.
991            *
992            * Also, if we unrealize from leaf nodes to root, and
993            * realize from root to leaf, the invariants are never
994            * violated if we allow children to be unrealized
995            * while parents are realized.
996            *
997            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
998            * to force us to unmap, even though parent is still
999            * mapped. This is because we're unmapping from leaf nodes
1000            * up to root nodes.
1001            */
1002           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1003               change != MAP_STATE_MAKE_UNMAPPED)
1004             {
1005               gboolean parent_is_visible_realized_toplevel;
1006
1007               parent_is_visible_realized_toplevel =
1008                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1009                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1010                  CLUTTER_ACTOR_IS_REALIZED (parent));
1011
1012               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1013                   parent_is_visible_realized_toplevel)
1014                 {
1015                   must_be_realized = TRUE;
1016                   should_be_mapped = TRUE;
1017                 }
1018             }
1019
1020           /* if the actor has been set to be painted even if unmapped
1021            * then we should map it and check for realization as well;
1022            * this is an override for the branch of the scene graph
1023            * which begins with this node
1024            */
1025           if (priv->enable_paint_unmapped)
1026             {
1027               if (priv->parent == NULL)
1028                 g_warning ("Attempting to map an unparented actor '%s'",
1029                            _clutter_actor_get_debug_name (self));
1030
1031               should_be_mapped = TRUE;
1032               must_be_realized = TRUE;
1033             }
1034
1035           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1036             may_be_realized = FALSE;
1037         }
1038
1039       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1040         {
1041           if (parent == NULL)
1042             g_warning ("Attempting to map a child that does not "
1043                        "meet the necessary invariants: the actor '%s' "
1044                        "has no parent",
1045                        _clutter_actor_get_debug_name (self));
1046           else
1047             g_warning ("Attempting to map a child that does not "
1048                        "meet the necessary invariants: the actor '%s' "
1049                        "is parented to an unmapped actor '%s'",
1050                        _clutter_actor_get_debug_name (self),
1051                        _clutter_actor_get_debug_name (priv->parent));
1052         }
1053
1054       /* If in reparent, we temporarily suspend unmap and unrealize.
1055        *
1056        * We want to go in the order "realize, map" and "unmap, unrealize"
1057        */
1058
1059       /* Unmap */
1060       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1061         clutter_actor_set_mapped (self, FALSE);
1062
1063       /* Realize */
1064       if (must_be_realized)
1065         clutter_actor_realize (self);
1066
1067       /* if we must be realized then we may be, presumably */
1068       g_assert (!(must_be_realized && !may_be_realized));
1069
1070       /* Unrealize */
1071       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1072         clutter_actor_unrealize_not_hiding (self);
1073
1074       /* Map */
1075       if (should_be_mapped)
1076         {
1077           if (!must_be_realized)
1078             g_warning ("Somehow we think actor '%s' should be mapped but "
1079                        "not realized, which isn't allowed",
1080                        _clutter_actor_get_debug_name (self));
1081
1082           /* realization is allowed to fail (though I don't know what
1083            * an app is supposed to do about that - shouldn't it just
1084            * be a g_error? anyway, we have to avoid mapping if this
1085            * happens)
1086            */
1087           if (CLUTTER_ACTOR_IS_REALIZED (self))
1088             clutter_actor_set_mapped (self, TRUE);
1089         }
1090     }
1091
1092 #ifdef CLUTTER_ENABLE_DEBUG
1093   /* check all invariants were kept */
1094   clutter_actor_verify_map_state (self);
1095 #endif
1096 }
1097
1098 static void
1099 clutter_actor_real_map (ClutterActor *self)
1100 {
1101   ClutterActorPrivate *priv = self->priv;
1102   ClutterActor *stage, *iter;
1103
1104   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1105
1106   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1107                 _clutter_actor_get_debug_name (self));
1108
1109   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1110
1111   stage = _clutter_actor_get_stage_internal (self);
1112   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1113
1114   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1115                 priv->pick_id,
1116                 _clutter_actor_get_debug_name (self));
1117
1118   /* notify on parent mapped before potentially mapping
1119    * children, so apps see a top-down notification.
1120    */
1121   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1122
1123   for (iter = self->priv->first_child;
1124        iter != NULL;
1125        iter = iter->priv->next_sibling)
1126     {
1127       clutter_actor_map (iter);
1128     }
1129 }
1130
1131 /**
1132  * clutter_actor_map:
1133  * @self: A #ClutterActor
1134  *
1135  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1136  * and realizes its children if they are visible. Does nothing if the
1137  * actor is not visible.
1138  *
1139  * Calling this function is strongly disencouraged: the default
1140  * implementation of #ClutterActorClass.map() will map all the children
1141  * of an actor when mapping its parent.
1142  *
1143  * When overriding map, it is mandatory to chain up to the parent
1144  * implementation.
1145  *
1146  * Since: 1.0
1147  */
1148 void
1149 clutter_actor_map (ClutterActor *self)
1150 {
1151   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1152
1153   if (CLUTTER_ACTOR_IS_MAPPED (self))
1154     return;
1155
1156   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1157     return;
1158
1159   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1160 }
1161
1162 static void
1163 clutter_actor_real_unmap (ClutterActor *self)
1164 {
1165   ClutterActorPrivate *priv = self->priv;
1166   ClutterActor *iter;
1167
1168   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1169
1170   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1171                 _clutter_actor_get_debug_name (self));
1172
1173   for (iter = self->priv->first_child;
1174        iter != NULL;
1175        iter = iter->priv->next_sibling)
1176     {
1177       clutter_actor_unmap (iter);
1178     }
1179
1180   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1181
1182   /* clear the contents of the last paint volume, so that hiding + moving +
1183    * showing will not result in the wrong area being repainted
1184    */
1185   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1186   priv->last_paint_volume_valid = TRUE;
1187
1188   /* notify on parent mapped after potentially unmapping
1189    * children, so apps see a bottom-up notification.
1190    */
1191   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1192
1193   /* relinquish keyboard focus if we were unmapped while owning it */
1194   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1195     {
1196       ClutterStage *stage;
1197
1198       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1199
1200       if (stage != NULL)
1201         _clutter_stage_release_pick_id (stage, priv->pick_id);
1202
1203       priv->pick_id = -1;
1204
1205       if (stage != NULL &&
1206           clutter_stage_get_key_focus (stage) == self)
1207         {
1208           clutter_stage_set_key_focus (stage, NULL);
1209         }
1210     }
1211 }
1212
1213 /**
1214  * clutter_actor_unmap:
1215  * @self: A #ClutterActor
1216  *
1217  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1218  * unmaps its children if they were mapped.
1219  *
1220  * Calling this function is not encouraged: the default #ClutterActor
1221  * implementation of #ClutterActorClass.unmap() will also unmap any
1222  * eventual children by default when their parent is unmapped.
1223  *
1224  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1225  * chain up to the parent implementation.
1226  *
1227  * <note>It is important to note that the implementation of the
1228  * #ClutterActorClass.unmap() virtual function may be called after
1229  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1230  * implementation, but it is guaranteed to be called before the
1231  * #GObjectClass.finalize() implementation.</note>
1232  *
1233  * Since: 1.0
1234  */
1235 void
1236 clutter_actor_unmap (ClutterActor *self)
1237 {
1238   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1239
1240   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1241     return;
1242
1243   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1244 }
1245
1246 static void
1247 clutter_actor_real_show (ClutterActor *self)
1248 {
1249   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1250     {
1251       ClutterActorPrivate *priv = self->priv;
1252
1253       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1254
1255       /* we notify on the "visible" flag in the clutter_actor_show()
1256        * wrapper so the entire show signal emission completes first
1257        * (?)
1258        */
1259       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1260
1261       /* we queue a relayout unless the actor is inside a
1262        * container that explicitly told us not to
1263        */
1264       if (priv->parent != NULL &&
1265           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1266         {
1267           /* While an actor is hidden the parent may not have
1268            * allocated/requested so we need to start from scratch
1269            * and avoid the short-circuiting in
1270            * clutter_actor_queue_relayout().
1271            */
1272           priv->needs_width_request  = FALSE;
1273           priv->needs_height_request = FALSE;
1274           priv->needs_allocation     = FALSE;
1275           clutter_actor_queue_relayout (self);
1276         }
1277     }
1278 }
1279
1280 static inline void
1281 set_show_on_set_parent (ClutterActor *self,
1282                         gboolean      set_show)
1283 {
1284   ClutterActorPrivate *priv = self->priv;
1285
1286   set_show = !!set_show;
1287
1288   if (priv->show_on_set_parent == set_show)
1289     return;
1290
1291   if (priv->parent == NULL)
1292     {
1293       priv->show_on_set_parent = set_show;
1294       g_object_notify_by_pspec (G_OBJECT (self),
1295                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1296     }
1297 }
1298
1299 /**
1300  * clutter_actor_show:
1301  * @self: A #ClutterActor
1302  *
1303  * Flags an actor to be displayed. An actor that isn't shown will not
1304  * be rendered on the stage.
1305  *
1306  * Actors are visible by default.
1307  *
1308  * If this function is called on an actor without a parent, the
1309  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1310  * effect.
1311  */
1312 void
1313 clutter_actor_show (ClutterActor *self)
1314 {
1315   ClutterActorPrivate *priv;
1316
1317   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1318
1319   /* simple optimization */
1320   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1321     {
1322       /* we still need to set the :show-on-set-parent property, in
1323        * case show() is called on an unparented actor
1324        */
1325       set_show_on_set_parent (self, TRUE);
1326       return;
1327     }
1328
1329 #ifdef CLUTTER_ENABLE_DEBUG
1330   clutter_actor_verify_map_state (self);
1331 #endif
1332
1333   priv = self->priv;
1334
1335   g_object_freeze_notify (G_OBJECT (self));
1336
1337   set_show_on_set_parent (self, TRUE);
1338
1339   g_signal_emit (self, actor_signals[SHOW], 0);
1340   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1341
1342   if (priv->parent != NULL)
1343     clutter_actor_queue_redraw (priv->parent);
1344
1345   g_object_thaw_notify (G_OBJECT (self));
1346 }
1347
1348 /**
1349  * clutter_actor_show_all:
1350  * @self: a #ClutterActor
1351  *
1352  * Calls clutter_actor_show() on all children of an actor (if any).
1353  *
1354  * Since: 0.2
1355  *
1356  * Deprecated: 1.10: Actors are visible by default
1357  */
1358 void
1359 clutter_actor_show_all (ClutterActor *self)
1360 {
1361   ClutterActorClass *klass;
1362
1363   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1364
1365   klass = CLUTTER_ACTOR_GET_CLASS (self);
1366   if (klass->show_all)
1367     klass->show_all (self);
1368 }
1369
1370 static void
1371 clutter_actor_real_hide (ClutterActor *self)
1372 {
1373   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1374     {
1375       ClutterActorPrivate *priv = self->priv;
1376
1377       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1378
1379       /* we notify on the "visible" flag in the clutter_actor_hide()
1380        * wrapper so the entire hide signal emission completes first
1381        * (?)
1382        */
1383       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1384
1385       /* we queue a relayout unless the actor is inside a
1386        * container that explicitly told us not to
1387        */
1388       if (priv->parent != NULL &&
1389           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1390         clutter_actor_queue_relayout (priv->parent);
1391     }
1392 }
1393
1394 /**
1395  * clutter_actor_hide:
1396  * @self: A #ClutterActor
1397  *
1398  * Flags an actor to be hidden. A hidden actor will not be
1399  * rendered on the stage.
1400  *
1401  * Actors are visible by default.
1402  *
1403  * If this function is called on an actor without a parent, the
1404  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1405  * as a side-effect.
1406  */
1407 void
1408 clutter_actor_hide (ClutterActor *self)
1409 {
1410   ClutterActorPrivate *priv;
1411
1412   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1413
1414   /* simple optimization */
1415   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1416     {
1417       /* we still need to set the :show-on-set-parent property, in
1418        * case hide() is called on an unparented actor
1419        */
1420       set_show_on_set_parent (self, FALSE);
1421       return;
1422     }
1423
1424 #ifdef CLUTTER_ENABLE_DEBUG
1425   clutter_actor_verify_map_state (self);
1426 #endif
1427
1428   priv = self->priv;
1429
1430   g_object_freeze_notify (G_OBJECT (self));
1431
1432   set_show_on_set_parent (self, FALSE);
1433
1434   g_signal_emit (self, actor_signals[HIDE], 0);
1435   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1436
1437   if (priv->parent != NULL)
1438     clutter_actor_queue_redraw (priv->parent);
1439
1440   g_object_thaw_notify (G_OBJECT (self));
1441 }
1442
1443 /**
1444  * clutter_actor_hide_all:
1445  * @self: a #ClutterActor
1446  *
1447  * Calls clutter_actor_hide() on all child actors (if any).
1448  *
1449  * Since: 0.2
1450  *
1451  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1452  *   prevent its children from being painted as well.
1453  */
1454 void
1455 clutter_actor_hide_all (ClutterActor *self)
1456 {
1457   ClutterActorClass *klass;
1458
1459   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1460
1461   klass = CLUTTER_ACTOR_GET_CLASS (self);
1462   if (klass->hide_all)
1463     klass->hide_all (self);
1464 }
1465
1466 /**
1467  * clutter_actor_realize:
1468  * @self: A #ClutterActor
1469  *
1470  * Realization informs the actor that it is attached to a stage. It
1471  * can use this to allocate resources if it wanted to delay allocation
1472  * until it would be rendered. However it is perfectly acceptable for
1473  * an actor to create resources before being realized because Clutter
1474  * only ever has a single rendering context so that actor is free to
1475  * be moved from one stage to another.
1476  *
1477  * This function does nothing if the actor is already realized.
1478  *
1479  * Because a realized actor must have realized parent actors, calling
1480  * clutter_actor_realize() will also realize all parents of the actor.
1481  *
1482  * This function does not realize child actors, except in the special
1483  * case that realizing the stage, when the stage is visible, will
1484  * suddenly map (and thus realize) the children of the stage.
1485  **/
1486 void
1487 clutter_actor_realize (ClutterActor *self)
1488 {
1489   ClutterActorPrivate *priv;
1490
1491   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1492
1493   priv = self->priv;
1494
1495 #ifdef CLUTTER_ENABLE_DEBUG
1496   clutter_actor_verify_map_state (self);
1497 #endif
1498
1499   if (CLUTTER_ACTOR_IS_REALIZED (self))
1500     return;
1501
1502   /* To be realized, our parent actors must be realized first.
1503    * This will only succeed if we're inside a toplevel.
1504    */
1505   if (priv->parent != NULL)
1506     clutter_actor_realize (priv->parent);
1507
1508   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1509     {
1510       /* toplevels can be realized at any time */
1511     }
1512   else
1513     {
1514       /* "Fail" the realization if parent is missing or unrealized;
1515        * this should really be a g_warning() not some kind of runtime
1516        * failure; how can an app possibly recover? Instead it's a bug
1517        * in the app and the app should get an explanatory warning so
1518        * someone can fix it. But for now it's too hard to fix this
1519        * because e.g. ClutterTexture needs reworking.
1520        */
1521       if (priv->parent == NULL ||
1522           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1523         return;
1524     }
1525
1526   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1527
1528   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1529   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1530
1531   g_signal_emit (self, actor_signals[REALIZE], 0);
1532
1533   /* Stage actor is allowed to unset the realized flag again in its
1534    * default signal handler, though that is a pathological situation.
1535    */
1536
1537   /* If realization "failed" we'll have to update child state. */
1538   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1539 }
1540
1541 static void
1542 clutter_actor_real_unrealize (ClutterActor *self)
1543 {
1544   /* we must be unmapped (implying our children are also unmapped) */
1545   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1546 }
1547
1548 /**
1549  * clutter_actor_unrealize:
1550  * @self: A #ClutterActor
1551  *
1552  * Unrealization informs the actor that it may be being destroyed or
1553  * moved to another stage. The actor may want to destroy any
1554  * underlying graphics resources at this point. However it is
1555  * perfectly acceptable for it to retain the resources until the actor
1556  * is destroyed because Clutter only ever uses a single rendering
1557  * context and all of the graphics resources are valid on any stage.
1558  *
1559  * Because mapped actors must be realized, actors may not be
1560  * unrealized if they are mapped. This function hides the actor to be
1561  * sure it isn't mapped, an application-visible side effect that you
1562  * may not be expecting.
1563  *
1564  * This function should not be called by application code.
1565  */
1566 void
1567 clutter_actor_unrealize (ClutterActor *self)
1568 {
1569   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1570   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1571
1572 /* This function should not really be in the public API, because
1573  * there isn't a good reason to call it. ClutterActor will already
1574  * unrealize things for you when it's important to do so.
1575  *
1576  * If you were using clutter_actor_unrealize() in a dispose
1577  * implementation, then don't, just chain up to ClutterActor's
1578  * dispose.
1579  *
1580  * If you were using clutter_actor_unrealize() to implement
1581  * unrealizing children of your container, then don't, ClutterActor
1582  * will already take care of that.
1583  *
1584  * If you were using clutter_actor_unrealize() to re-realize to
1585  * create your resources in a different way, then use
1586  * _clutter_actor_rerealize() (inside Clutter) or just call your
1587  * code that recreates your resources directly (outside Clutter).
1588  */
1589
1590 #ifdef CLUTTER_ENABLE_DEBUG
1591   clutter_actor_verify_map_state (self);
1592 #endif
1593
1594   clutter_actor_hide (self);
1595
1596   clutter_actor_unrealize_not_hiding (self);
1597 }
1598
1599 static ClutterActorTraverseVisitFlags
1600 unrealize_actor_before_children_cb (ClutterActor *self,
1601                                     int depth,
1602                                     void *user_data)
1603 {
1604   /* If an actor is already unrealized we know its children have also
1605    * already been unrealized... */
1606   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1607     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1608
1609   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1610
1611   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1612 }
1613
1614 static ClutterActorTraverseVisitFlags
1615 unrealize_actor_after_children_cb (ClutterActor *self,
1616                                    int depth,
1617                                    void *user_data)
1618 {
1619   /* We want to unset the realized flag only _after_
1620    * child actors are unrealized, to maintain invariants.
1621    */
1622   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1623   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1624   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1625 }
1626
1627 /*
1628  * clutter_actor_unrealize_not_hiding:
1629  * @self: A #ClutterActor
1630  *
1631  * Unrealization informs the actor that it may be being destroyed or
1632  * moved to another stage. The actor may want to destroy any
1633  * underlying graphics resources at this point. However it is
1634  * perfectly acceptable for it to retain the resources until the actor
1635  * is destroyed because Clutter only ever uses a single rendering
1636  * context and all of the graphics resources are valid on any stage.
1637  *
1638  * Because mapped actors must be realized, actors may not be
1639  * unrealized if they are mapped. You must hide the actor or one of
1640  * its parents before attempting to unrealize.
1641  *
1642  * This function is separate from clutter_actor_unrealize() because it
1643  * does not automatically hide the actor.
1644  * Actors need not be hidden to be unrealized, they just need to
1645  * be unmapped. In fact we don't want to mess up the application's
1646  * setting of the "visible" flag, so hiding is very undesirable.
1647  *
1648  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1649  * backward compatibility.
1650  */
1651 static void
1652 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1653 {
1654   _clutter_actor_traverse (self,
1655                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1656                            unrealize_actor_before_children_cb,
1657                            unrealize_actor_after_children_cb,
1658                            NULL);
1659 }
1660
1661 /*
1662  * _clutter_actor_rerealize:
1663  * @self: A #ClutterActor
1664  * @callback: Function to call while unrealized
1665  * @data: data for callback
1666  *
1667  * If an actor is already unrealized, this just calls the callback.
1668  *
1669  * If it is realized, it unrealizes temporarily, calls the callback,
1670  * and then re-realizes the actor.
1671  *
1672  * As a side effect, leaves all children of the actor unrealized if
1673  * the actor was realized but not showing.  This is because when we
1674  * unrealize the actor temporarily we must unrealize its children
1675  * (e.g. children of a stage can't be realized if stage window is
1676  * gone). And we aren't clever enough to save the realization state of
1677  * all children. In most cases this should not matter, because
1678  * the children will automatically realize when they next become mapped.
1679  */
1680 void
1681 _clutter_actor_rerealize (ClutterActor    *self,
1682                           ClutterCallback  callback,
1683                           void            *data)
1684 {
1685   gboolean was_mapped;
1686   gboolean was_showing;
1687   gboolean was_realized;
1688
1689   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1690
1691 #ifdef CLUTTER_ENABLE_DEBUG
1692   clutter_actor_verify_map_state (self);
1693 #endif
1694
1695   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1696   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1697   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1698
1699   /* Must be unmapped to unrealize. Note we only have to hide this
1700    * actor if it was mapped (if all parents were showing).  If actor
1701    * is merely visible (but not mapped), then that's fine, we can
1702    * leave it visible.
1703    */
1704   if (was_mapped)
1705     clutter_actor_hide (self);
1706
1707   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1708
1709   /* unrealize self and all children */
1710   clutter_actor_unrealize_not_hiding (self);
1711
1712   if (callback != NULL)
1713     {
1714       (* callback) (self, data);
1715     }
1716
1717   if (was_showing)
1718     clutter_actor_show (self); /* will realize only if mapping implies it */
1719   else if (was_realized)
1720     clutter_actor_realize (self); /* realize self and all parents */
1721 }
1722
1723 static void
1724 clutter_actor_real_pick (ClutterActor       *self,
1725                          const ClutterColor *color)
1726 {
1727   /* the default implementation is just to paint a rectangle
1728    * with the same size of the actor using the passed color
1729    */
1730   if (clutter_actor_should_pick_paint (self))
1731     {
1732       ClutterActorBox box = { 0, };
1733       float width, height;
1734
1735       clutter_actor_get_allocation_box (self, &box);
1736
1737       width = box.x2 - box.x1;
1738       height = box.y2 - box.y1;
1739
1740       cogl_set_source_color4ub (color->red,
1741                                 color->green,
1742                                 color->blue,
1743                                 color->alpha);
1744
1745       cogl_rectangle (0, 0, width, height);
1746     }
1747
1748   /* XXX - this thoroughly sucks, but we need to maintain compatibility
1749    * with existing container classes that override the pick() virtual
1750    * and chain up to the default implementation - otherwise we'll end up
1751    * painting our children twice.
1752    *
1753    * this has to go away for 2.0; hopefully along the pick() itself.
1754    */
1755   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1756     {
1757       ClutterActor *iter;
1758
1759       for (iter = self->priv->first_child;
1760            iter != NULL;
1761            iter = iter->priv->next_sibling)
1762         clutter_actor_paint (iter);
1763     }
1764 }
1765
1766 /**
1767  * clutter_actor_should_pick_paint:
1768  * @self: A #ClutterActor
1769  *
1770  * Should be called inside the implementation of the
1771  * #ClutterActor::pick virtual function in order to check whether
1772  * the actor should paint itself in pick mode or not.
1773  *
1774  * This function should never be called directly by applications.
1775  *
1776  * Return value: %TRUE if the actor should paint its silhouette,
1777  *   %FALSE otherwise
1778  */
1779 gboolean
1780 clutter_actor_should_pick_paint (ClutterActor *self)
1781 {
1782   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1783
1784   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1785       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1786        CLUTTER_ACTOR_IS_REACTIVE (self)))
1787     return TRUE;
1788
1789   return FALSE;
1790 }
1791
1792 static void
1793 clutter_actor_real_get_preferred_width (ClutterActor *self,
1794                                         gfloat        for_height,
1795                                         gfloat       *min_width_p,
1796                                         gfloat       *natural_width_p)
1797 {
1798   ClutterActorPrivate *priv = self->priv;
1799
1800   if (priv->n_children != 0 &&
1801       priv->layout_manager != NULL)
1802     {
1803       ClutterContainer *container = CLUTTER_CONTAINER (self);
1804
1805       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1806                     "for the preferred width",
1807                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1808                     priv->layout_manager);
1809
1810       clutter_layout_manager_get_preferred_width (priv->layout_manager,
1811                                                   container,
1812                                                   for_height,
1813                                                   min_width_p,
1814                                                   natural_width_p);
1815
1816       return;
1817     }
1818
1819   /* Default implementation is always 0x0, usually an actor
1820    * using this default is relying on someone to set the
1821    * request manually
1822    */
1823   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1824
1825   if (min_width_p)
1826     *min_width_p = 0;
1827
1828   if (natural_width_p)
1829     *natural_width_p = 0;
1830 }
1831
1832 static void
1833 clutter_actor_real_get_preferred_height (ClutterActor *self,
1834                                          gfloat        for_width,
1835                                          gfloat       *min_height_p,
1836                                          gfloat       *natural_height_p)
1837 {
1838   ClutterActorPrivate *priv = self->priv;
1839
1840   if (priv->n_children != 0 &&
1841       priv->layout_manager != NULL)
1842     {
1843       ClutterContainer *container = CLUTTER_CONTAINER (self);
1844
1845       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1846                     "for the preferred height",
1847                     G_OBJECT_TYPE_NAME (priv->layout_manager),
1848                     priv->layout_manager);
1849
1850       clutter_layout_manager_get_preferred_height (priv->layout_manager,
1851                                                    container,
1852                                                    for_width,
1853                                                    min_height_p,
1854                                                    natural_height_p);
1855
1856       return;
1857     }
1858   /* Default implementation is always 0x0, usually an actor
1859    * using this default is relying on someone to set the
1860    * request manually
1861    */
1862   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1863
1864   if (min_height_p)
1865     *min_height_p = 0;
1866
1867   if (natural_height_p)
1868     *natural_height_p = 0;
1869 }
1870
1871 static void
1872 clutter_actor_store_old_geometry (ClutterActor    *self,
1873                                   ClutterActorBox *box)
1874 {
1875   *box = self->priv->allocation;
1876 }
1877
1878 static inline void
1879 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
1880                                           const ClutterActorBox *old)
1881 {
1882   ClutterActorPrivate *priv = self->priv;
1883   GObject *obj = G_OBJECT (self);
1884
1885   g_object_freeze_notify (obj);
1886
1887   /* to avoid excessive requisition or allocation cycles we
1888    * use the cached values.
1889    *
1890    * - if we don't have an allocation we assume that we need
1891    *   to notify anyway
1892    * - if we don't have a width or a height request we notify
1893    *   width and height
1894    * - if we have a valid allocation then we check the old
1895    *   bounding box with the current allocation and we notify
1896    *   the changes
1897    */
1898   if (priv->needs_allocation)
1899     {
1900       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1901       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1902       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1903       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1904     }
1905   else if (priv->needs_width_request || priv->needs_height_request)
1906     {
1907       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1908       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1909     }
1910   else
1911     {
1912       gfloat xu, yu;
1913       gfloat widthu, heightu;
1914
1915       xu = priv->allocation.x1;
1916       yu = priv->allocation.y1;
1917       widthu = priv->allocation.x2 - priv->allocation.x1;
1918       heightu = priv->allocation.y2 - priv->allocation.y1;
1919
1920       if (xu != old->x1)
1921         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1922
1923       if (yu != old->y1)
1924         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1925
1926       if (widthu != (old->x2 - old->x1))
1927         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1928
1929       if (heightu != (old->y2 - old->y1))
1930         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1931     }
1932
1933   g_object_thaw_notify (obj);
1934 }
1935
1936 /*< private >
1937  * clutter_actor_set_allocation_internal:
1938  * @self: a #ClutterActor
1939  * @box: a #ClutterActorBox
1940  * @flags: allocation flags
1941  *
1942  * Stores the allocation of @self.
1943  *
1944  * This function only performs basic storage and property notification.
1945  *
1946  * This function should be called by clutter_actor_set_allocation()
1947  * and by the default implementation of #ClutterActorClass.allocate().
1948  *
1949  * Return value: %TRUE if the allocation of the #ClutterActor has been
1950  *   changed, and %FALSE otherwise
1951  */
1952 static inline gboolean
1953 clutter_actor_set_allocation_internal (ClutterActor           *self,
1954                                        const ClutterActorBox  *box,
1955                                        ClutterAllocationFlags  flags)
1956 {
1957   ClutterActorPrivate *priv = self->priv;
1958   GObject *obj;
1959   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
1960   gboolean flags_changed;
1961   gboolean retval;
1962   ClutterActorBox old_alloc = { 0, };
1963
1964   obj = G_OBJECT (self);
1965
1966   g_object_freeze_notify (obj);
1967
1968   clutter_actor_store_old_geometry (self, &old_alloc);
1969
1970   x1_changed = priv->allocation.x1 != box->x1;
1971   y1_changed = priv->allocation.y1 != box->y1;
1972   x2_changed = priv->allocation.x2 != box->x2;
1973   y2_changed = priv->allocation.y2 != box->y2;
1974
1975   flags_changed = priv->allocation_flags != flags;
1976
1977   priv->allocation = *box;
1978   priv->allocation_flags = flags;
1979
1980   /* allocation is authoritative */
1981   priv->needs_width_request = FALSE;
1982   priv->needs_height_request = FALSE;
1983   priv->needs_allocation = FALSE;
1984
1985   if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
1986     {
1987       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
1988                     _clutter_actor_get_debug_name (self));
1989
1990       priv->transform_valid = FALSE;
1991
1992       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
1993
1994       retval = TRUE;
1995     }
1996   else
1997     retval = FALSE;
1998
1999   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2000
2001   g_object_thaw_notify (obj);
2002
2003   return retval;
2004 }
2005
2006 static void clutter_actor_real_allocate (ClutterActor           *self,
2007                                          const ClutterActorBox  *box,
2008                                          ClutterAllocationFlags  flags);
2009
2010 static inline void
2011 clutter_actor_maybe_layout_children (ClutterActor           *self,
2012                                      const ClutterActorBox  *allocation,
2013                                      ClutterAllocationFlags  flags)
2014 {
2015   ClutterActorPrivate *priv = self->priv;
2016
2017   /* this is going to be a bit hard to follow, so let's put an explanation
2018    * here.
2019    *
2020    * we want ClutterActor to have a default layout manager if the actor was
2021    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2022    *
2023    * we also want any subclass of ClutterActor that does not override the
2024    * ::allocate() virtual function to delegate to a layout manager.
2025    *
2026    * finally, we want to allow people subclassing ClutterActor and overriding
2027    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2028    *
2029    * on the other hand, we want existing actor subclasses overriding the
2030    * ::allocate() virtual function and chaining up to the parent's
2031    * implementation to continue working without allocating their children
2032    * twice, or without entering an allocation loop.
2033    *
2034    * for the first two points, we check if the class of the actor is
2035    * overridding the ::allocate() virtual function; if it isn't, then we
2036    * follow through with checking whether we have children and a layout
2037    * manager, and eventually calling clutter_layout_manager_allocate().
2038    *
2039    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2040    * allocation flags that we got passed, and if it is present, we continue
2041    * with the check above.
2042    *
2043    * if neither of these two checks yields a positive result, we just
2044    * assume that the ::allocate() virtual function that resulted in this
2045    * function being called will also allocate the children of the actor.
2046    */
2047
2048   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2049     goto check_layout;
2050
2051   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2052     goto check_layout;
2053
2054   return;
2055
2056 check_layout:
2057   if (priv->n_children != 0 &&
2058       priv->layout_manager != NULL)
2059     {
2060       ClutterContainer *container = CLUTTER_CONTAINER (self);
2061       ClutterAllocationFlags children_flags;
2062       ClutterActorBox children_box;
2063
2064       /* normalize the box passed to the layout manager */
2065       children_box.x1 = children_box.y1 = 0.f;
2066       children_box.x2 = (allocation->x2 - allocation->x1);
2067       children_box.y2 = (allocation->y2 - allocation->y1);
2068
2069       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2070        * the actor's children, since it refers only to the current
2071        * actor's allocation.
2072        */
2073       children_flags = flags;
2074       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2075
2076       CLUTTER_NOTE (LAYOUT,
2077                     "Allocating %d children of %s "
2078                     "at { %.2f, %.2f - %.2f x %.2f } "
2079                     "using %s",
2080                     priv->n_children,
2081                     _clutter_actor_get_debug_name (self),
2082                     allocation->x1,
2083                     allocation->y1,
2084                     (allocation->x2 - allocation->x1),
2085                     (allocation->y2 - allocation->y1),
2086                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2087
2088       clutter_layout_manager_allocate (priv->layout_manager,
2089                                        container,
2090                                        &children_box,
2091                                        children_flags);
2092     }
2093 }
2094
2095 static void
2096 clutter_actor_real_allocate (ClutterActor           *self,
2097                              const ClutterActorBox  *box,
2098                              ClutterAllocationFlags  flags)
2099 {
2100   ClutterActorPrivate *priv = self->priv;
2101   gboolean changed;
2102
2103   g_object_freeze_notify (G_OBJECT (self));
2104
2105   changed = clutter_actor_set_allocation_internal (self, box, flags);
2106
2107   /* we allocate our children before we notify changes in our geometry,
2108    * so that people connecting to properties will be able to get valid
2109    * data out of the sub-tree of the scene graph that has this actor at
2110    * the root.
2111    */
2112   clutter_actor_maybe_layout_children (self, box, flags);
2113
2114   if (changed)
2115     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2116                    &priv->allocation,
2117                    priv->allocation_flags);
2118
2119   g_object_thaw_notify (G_OBJECT (self));
2120 }
2121
2122 static void
2123 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2124                                     ClutterActor *origin)
2125 {
2126   /* no point in queuing a redraw on a destroyed actor */
2127   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2128     return;
2129
2130   /* NB: We can't bail out early here if the actor is hidden in case
2131    * the actor bas been cloned. In this case the clone will need to
2132    * receive the signal so it can queue its own redraw.
2133    */
2134
2135   /* calls klass->queue_redraw in default handler */
2136   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2137 }
2138
2139 static void
2140 clutter_actor_real_queue_redraw (ClutterActor *self,
2141                                  ClutterActor *origin)
2142 {
2143   ClutterActor *parent;
2144
2145   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2146                 _clutter_actor_get_debug_name (self),
2147                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2148                                : "same actor");
2149
2150   /* no point in queuing a redraw on a destroyed actor */
2151   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2152     return;
2153
2154   /* If the queue redraw is coming from a child then the actor has
2155      become dirty and any queued effect is no longer valid */
2156   if (self != origin)
2157     {
2158       self->priv->is_dirty = TRUE;
2159       self->priv->effect_to_redraw = NULL;
2160     }
2161
2162   /* If the actor isn't visible, we still had to emit the signal
2163    * to allow for a ClutterClone, but the appearance of the parent
2164    * won't change so we don't have to propagate up the hierarchy.
2165    */
2166   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2167     return;
2168
2169   /* Although we could determine here that a full stage redraw
2170    * has already been queued and immediately bail out, we actually
2171    * guarantee that we will propagate a queue-redraw signal to our
2172    * parent at least once so that it's possible to implement a
2173    * container that tracks which of its children have queued a
2174    * redraw.
2175    */
2176   if (self->priv->propagated_one_redraw)
2177     {
2178       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2179       if (stage != NULL &&
2180           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2181         return;
2182     }
2183
2184   self->priv->propagated_one_redraw = TRUE;
2185
2186   /* notify parents, if they are all visible eventually we'll
2187    * queue redraw on the stage, which queues the redraw idle.
2188    */
2189   parent = clutter_actor_get_parent (self);
2190   if (parent != NULL)
2191     {
2192       /* this will go up recursively */
2193       _clutter_actor_signal_queue_redraw (parent, origin);
2194     }
2195 }
2196
2197 static void
2198 clutter_actor_real_queue_relayout (ClutterActor *self)
2199 {
2200   ClutterActorPrivate *priv = self->priv;
2201
2202   /* no point in queueing a redraw on a destroyed actor */
2203   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2204     return;
2205
2206   priv->needs_width_request  = TRUE;
2207   priv->needs_height_request = TRUE;
2208   priv->needs_allocation     = TRUE;
2209
2210   /* reset the cached size requests */
2211   memset (priv->width_requests, 0,
2212           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2213   memset (priv->height_requests, 0,
2214           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2215
2216   /* We need to go all the way up the hierarchy */
2217   if (priv->parent != NULL)
2218     _clutter_actor_queue_only_relayout (priv->parent);
2219 }
2220
2221 /**
2222  * clutter_actor_apply_relative_transform_to_point:
2223  * @self: A #ClutterActor
2224  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2225  *   default #ClutterStage
2226  * @point: A point as #ClutterVertex
2227  * @vertex: (out caller-allocates): The translated #ClutterVertex
2228  *
2229  * Transforms @point in coordinates relative to the actor into
2230  * ancestor-relative coordinates using the relevant transform
2231  * stack (i.e. scale, rotation, etc).
2232  *
2233  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2234  * this case, the coordinates returned will be the coordinates on
2235  * the stage before the projection is applied. This is different from
2236  * the behaviour of clutter_actor_apply_transform_to_point().
2237  *
2238  * Since: 0.6
2239  */
2240 void
2241 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2242                                                  ClutterActor        *ancestor,
2243                                                  const ClutterVertex *point,
2244                                                  ClutterVertex       *vertex)
2245 {
2246   gfloat w;
2247   CoglMatrix matrix;
2248
2249   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2250   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2251   g_return_if_fail (point != NULL);
2252   g_return_if_fail (vertex != NULL);
2253
2254   *vertex = *point;
2255   w = 1.0;
2256
2257   if (ancestor == NULL)
2258     ancestor = _clutter_actor_get_stage_internal (self);
2259
2260   if (ancestor == NULL)
2261     {
2262       *vertex = *point;
2263       return;
2264     }
2265
2266   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2267   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2268 }
2269
2270 static gboolean
2271 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2272                                          const ClutterVertex *vertices_in,
2273                                          ClutterVertex *vertices_out,
2274                                          int n_vertices)
2275 {
2276   ClutterActor *stage;
2277   CoglMatrix modelview;
2278   CoglMatrix projection;
2279   float viewport[4];
2280
2281   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2282
2283   stage = _clutter_actor_get_stage_internal (self);
2284
2285   /* We really can't do anything meaningful in this case so don't try
2286    * to do any transform */
2287   if (stage == NULL)
2288     return FALSE;
2289
2290   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2291    * that gets us to stage coordinates, we want to go all the way to eye
2292    * coordinates */
2293   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2294
2295   /* Fetch the projection and viewport */
2296   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2297   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2298                                &viewport[0],
2299                                &viewport[1],
2300                                &viewport[2],
2301                                &viewport[3]);
2302
2303   _clutter_util_fully_transform_vertices (&modelview,
2304                                           &projection,
2305                                           viewport,
2306                                           vertices_in,
2307                                           vertices_out,
2308                                           n_vertices);
2309
2310   return TRUE;
2311 }
2312
2313 /**
2314  * clutter_actor_apply_transform_to_point:
2315  * @self: A #ClutterActor
2316  * @point: A point as #ClutterVertex
2317  * @vertex: (out caller-allocates): The translated #ClutterVertex
2318  *
2319  * Transforms @point in coordinates relative to the actor
2320  * into screen-relative coordinates with the current actor
2321  * transformation (i.e. scale, rotation, etc)
2322  *
2323  * Since: 0.4
2324  **/
2325 void
2326 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2327                                         const ClutterVertex *point,
2328                                         ClutterVertex       *vertex)
2329 {
2330   g_return_if_fail (point != NULL);
2331   g_return_if_fail (vertex != NULL);
2332   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2333 }
2334
2335 /*
2336  * _clutter_actor_get_relative_transformation_matrix:
2337  * @self: The actor whose coordinate space you want to transform from.
2338  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2339  *            or %NULL if you want to transform all the way to eye coordinates.
2340  * @matrix: A #CoglMatrix to store the transformation
2341  *
2342  * This gets a transformation @matrix that will transform coordinates from the
2343  * coordinate space of @self into the coordinate space of @ancestor.
2344  *
2345  * For example if you need a matrix that can transform the local actor
2346  * coordinates of @self into stage coordinates you would pass the actor's stage
2347  * pointer as the @ancestor.
2348  *
2349  * If you pass %NULL then the transformation will take you all the way through
2350  * to eye coordinates. This can be useful if you want to extract the entire
2351  * modelview transform that Clutter applies before applying the projection
2352  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2353  * using cogl_set_modelview_matrix() for example then you would want a matrix
2354  * that transforms into eye coordinates.
2355  *
2356  * <note><para>This function explicitly initializes the given @matrix. If you just
2357  * want clutter to multiply a relative transformation with an existing matrix
2358  * you can use clutter_actor_apply_relative_transformation_matrix()
2359  * instead.</para></note>
2360  *
2361  */
2362 /* XXX: We should consider caching the stage relative modelview along with
2363  * the actor itself */
2364 static void
2365 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2366                                                    ClutterActor *ancestor,
2367                                                    CoglMatrix *matrix)
2368 {
2369   cogl_matrix_init_identity (matrix);
2370
2371   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2372 }
2373
2374 /* Project the given @box into stage window coordinates, writing the
2375  * transformed vertices to @verts[]. */
2376 static gboolean
2377 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2378                                           const ClutterActorBox *box,
2379                                           ClutterVertex          verts[])
2380 {
2381   ClutterVertex box_vertices[4];
2382
2383   box_vertices[0].x = box->x1;
2384   box_vertices[0].y = box->y1;
2385   box_vertices[0].z = 0;
2386   box_vertices[1].x = box->x2;
2387   box_vertices[1].y = box->y1;
2388   box_vertices[1].z = 0;
2389   box_vertices[2].x = box->x1;
2390   box_vertices[2].y = box->y2;
2391   box_vertices[2].z = 0;
2392   box_vertices[3].x = box->x2;
2393   box_vertices[3].y = box->y2;
2394   box_vertices[3].z = 0;
2395
2396   return
2397     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2398 }
2399
2400 /**
2401  * clutter_actor_get_allocation_vertices:
2402  * @self: A #ClutterActor
2403  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2404  *   against, or %NULL to use the #ClutterStage
2405  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2406  *   location for an array of 4 #ClutterVertex in which to store the result
2407  *
2408  * Calculates the transformed coordinates of the four corners of the
2409  * actor in the plane of @ancestor. The returned vertices relate to
2410  * the #ClutterActorBox coordinates as follows:
2411  * <itemizedlist>
2412  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2413  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2414  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2415  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2416  * </itemizedlist>
2417  *
2418  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2419  * this case, the coordinates returned will be the coordinates on
2420  * the stage before the projection is applied. This is different from
2421  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2422  *
2423  * Since: 0.6
2424  */
2425 void
2426 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2427                                        ClutterActor  *ancestor,
2428                                        ClutterVertex  verts[])
2429 {
2430   ClutterActorPrivate *priv;
2431   ClutterActorBox box;
2432   ClutterVertex vertices[4];
2433   CoglMatrix modelview;
2434
2435   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2436   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2437
2438   if (ancestor == NULL)
2439     ancestor = _clutter_actor_get_stage_internal (self);
2440
2441   /* Fallback to a NOP transform if the actor isn't parented under a
2442    * stage. */
2443   if (ancestor == NULL)
2444     ancestor = self;
2445
2446   priv = self->priv;
2447
2448   /* if the actor needs to be allocated we force a relayout, so that
2449    * we will have valid values to use in the transformations */
2450   if (priv->needs_allocation)
2451     {
2452       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2453       if (stage)
2454         _clutter_stage_maybe_relayout (stage);
2455       else
2456         {
2457           box.x1 = box.y1 = 0;
2458           /* The result isn't really meaningful in this case but at
2459            * least try to do something *vaguely* reasonable... */
2460           clutter_actor_get_size (self, &box.x2, &box.y2);
2461         }
2462     }
2463
2464   clutter_actor_get_allocation_box (self, &box);
2465
2466   vertices[0].x = box.x1;
2467   vertices[0].y = box.y1;
2468   vertices[0].z = 0;
2469   vertices[1].x = box.x2;
2470   vertices[1].y = box.y1;
2471   vertices[1].z = 0;
2472   vertices[2].x = box.x1;
2473   vertices[2].y = box.y2;
2474   vertices[2].z = 0;
2475   vertices[3].x = box.x2;
2476   vertices[3].y = box.y2;
2477   vertices[3].z = 0;
2478
2479   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2480                                                      &modelview);
2481
2482   cogl_matrix_transform_points (&modelview,
2483                                 3,
2484                                 sizeof (ClutterVertex),
2485                                 vertices,
2486                                 sizeof (ClutterVertex),
2487                                 vertices,
2488                                 4);
2489 }
2490
2491 /**
2492  * clutter_actor_get_abs_allocation_vertices:
2493  * @self: A #ClutterActor
2494  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2495  *   of 4 #ClutterVertex where to store the result.
2496  *
2497  * Calculates the transformed screen coordinates of the four corners of
2498  * the actor; the returned vertices relate to the #ClutterActorBox
2499  * coordinates  as follows:
2500  * <itemizedlist>
2501  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2502  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2503  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2504  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2505  * </itemizedlist>
2506  *
2507  * Since: 0.4
2508  */
2509 void
2510 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2511                                            ClutterVertex  verts[])
2512 {
2513   ClutterActorPrivate *priv;
2514   ClutterActorBox actor_space_allocation;
2515
2516   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2517
2518   priv = self->priv;
2519
2520   /* if the actor needs to be allocated we force a relayout, so that
2521    * the actor allocation box will be valid for
2522    * _clutter_actor_transform_and_project_box()
2523    */
2524   if (priv->needs_allocation)
2525     {
2526       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2527       /* There's nothing meaningful we can do now */
2528       if (!stage)
2529         return;
2530
2531       _clutter_stage_maybe_relayout (stage);
2532     }
2533
2534   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2535    * own coordinate space... */
2536   actor_space_allocation.x1 = 0;
2537   actor_space_allocation.y1 = 0;
2538   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2539   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2540   _clutter_actor_transform_and_project_box (self,
2541                                             &actor_space_allocation,
2542                                             verts);
2543 }
2544
2545 static void
2546 clutter_actor_real_apply_transform (ClutterActor *self,
2547                                     CoglMatrix   *matrix)
2548 {
2549   ClutterActorPrivate *priv = self->priv;
2550
2551   if (!priv->transform_valid)
2552     {
2553       CoglMatrix *transform = &priv->transform;
2554       const ClutterTransformInfo *info;
2555
2556       info = _clutter_actor_get_transform_info_or_defaults (self);
2557
2558       cogl_matrix_init_identity (transform);
2559
2560       cogl_matrix_translate (transform,
2561                              priv->allocation.x1,
2562                              priv->allocation.y1,
2563                              0.0);
2564
2565       if (priv->z)
2566         cogl_matrix_translate (transform, 0, 0, priv->z);
2567
2568       /*
2569        * because the rotation involves translations, we must scale
2570        * before applying the rotations (if we apply the scale after
2571        * the rotations, the translations included in the rotation are
2572        * not scaled and so the entire object will move on the screen
2573        * as a result of rotating it).
2574        */
2575       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2576         {
2577           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2578                                         &info->scale_center,
2579                                         cogl_matrix_scale (transform,
2580                                                            info->scale_x,
2581                                                            info->scale_y,
2582                                                            1.0));
2583         }
2584
2585       if (info->rz_angle)
2586         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2587                                       &info->rz_center,
2588                                       cogl_matrix_rotate (transform,
2589                                                           info->rz_angle,
2590                                                           0, 0, 1.0));
2591
2592       if (info->ry_angle)
2593         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2594                                       &info->ry_center,
2595                                       cogl_matrix_rotate (transform,
2596                                                           info->ry_angle,
2597                                                           0, 1.0, 0));
2598
2599       if (info->rx_angle)
2600         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2601                                       &info->rx_center,
2602                                       cogl_matrix_rotate (transform,
2603                                                           info->rx_angle,
2604                                                           1.0, 0, 0));
2605
2606       if (!clutter_anchor_coord_is_zero (&info->anchor))
2607         {
2608           gfloat x, y, z;
2609
2610           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2611           cogl_matrix_translate (transform, -x, -y, -z);
2612         }
2613
2614       priv->transform_valid = TRUE;
2615     }
2616
2617   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2618 }
2619
2620 /* Applies the transforms associated with this actor to the given
2621  * matrix. */
2622 void
2623 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2624                                           CoglMatrix *matrix)
2625 {
2626   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2627 }
2628
2629 /*
2630  * clutter_actor_apply_relative_transformation_matrix:
2631  * @self: The actor whose coordinate space you want to transform from.
2632  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2633  *            or %NULL if you want to transform all the way to eye coordinates.
2634  * @matrix: A #CoglMatrix to apply the transformation too.
2635  *
2636  * This multiplies a transform with @matrix that will transform coordinates
2637  * from the coordinate space of @self into the coordinate space of @ancestor.
2638  *
2639  * For example if you need a matrix that can transform the local actor
2640  * coordinates of @self into stage coordinates you would pass the actor's stage
2641  * pointer as the @ancestor.
2642  *
2643  * If you pass %NULL then the transformation will take you all the way through
2644  * to eye coordinates. This can be useful if you want to extract the entire
2645  * modelview transform that Clutter applies before applying the projection
2646  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2647  * using cogl_set_modelview_matrix() for example then you would want a matrix
2648  * that transforms into eye coordinates.
2649  *
2650  * <note>This function doesn't initialize the given @matrix, it simply
2651  * multiplies the requested transformation matrix with the existing contents of
2652  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2653  * before calling this function, or you can use
2654  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2655  */
2656 void
2657 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2658                                                      ClutterActor *ancestor,
2659                                                      CoglMatrix *matrix)
2660 {
2661   ClutterActor *parent;
2662
2663   /* Note we terminate before ever calling stage->apply_transform()
2664    * since that would conceptually be relative to the underlying
2665    * window OpenGL coordinates so we'd need a special @ancestor
2666    * value to represent the fake parent of the stage. */
2667   if (self == ancestor)
2668     return;
2669
2670   parent = clutter_actor_get_parent (self);
2671
2672   if (parent != NULL)
2673     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2674                                                          matrix);
2675
2676   _clutter_actor_apply_modelview_transform (self, matrix);
2677 }
2678
2679 static void
2680 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2681                                        ClutterPaintVolume *pv,
2682                                        const char *label,
2683                                        const CoglColor *color)
2684 {
2685   static CoglPipeline *outline = NULL;
2686   CoglPrimitive *prim;
2687   ClutterVertex line_ends[12 * 2];
2688   int n_vertices;
2689   CoglContext *ctx =
2690     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2691   /* XXX: at some point we'll query this from the stage but we can't
2692    * do that until the osx backend uses Cogl natively. */
2693   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2694
2695   if (outline == NULL)
2696     outline = cogl_pipeline_new ();
2697
2698   _clutter_paint_volume_complete (pv);
2699
2700   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2701
2702   /* Front face */
2703   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2704   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2705   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2706   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2707
2708   if (!pv->is_2d)
2709     {
2710       /* Back face */
2711       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2712       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2713       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2714       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2715
2716       /* Lines connecting front face to back face */
2717       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2718       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2719       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2720       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2721     }
2722
2723   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES, n_vertices,
2724                                 (CoglVertexP3 *)line_ends);
2725
2726   cogl_pipeline_set_color (outline, color);
2727   cogl_framebuffer_draw_primitive (fb, outline, prim);
2728   cogl_object_unref (prim);
2729
2730   if (label)
2731     {
2732       PangoLayout *layout;
2733       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2734       pango_layout_set_text (layout, label, -1);
2735       cogl_pango_render_layout (layout,
2736                                 pv->vertices[0].x,
2737                                 pv->vertices[0].y,
2738                                 color,
2739                                 0);
2740       g_object_unref (layout);
2741     }
2742 }
2743
2744 static void
2745 _clutter_actor_draw_paint_volume (ClutterActor *self)
2746 {
2747   ClutterPaintVolume *pv;
2748   CoglColor color;
2749
2750   pv = _clutter_actor_get_paint_volume_mutable (self);
2751   if (!pv)
2752     {
2753       gfloat width, height;
2754       ClutterPaintVolume fake_pv;
2755
2756       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2757       _clutter_paint_volume_init_static (&fake_pv, stage);
2758
2759       clutter_actor_get_size (self, &width, &height);
2760       clutter_paint_volume_set_width (&fake_pv, width);
2761       clutter_paint_volume_set_height (&fake_pv, height);
2762
2763       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2764       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2765                                              _clutter_actor_get_debug_name (self),
2766                                              &color);
2767
2768       clutter_paint_volume_free (&fake_pv);
2769     }
2770   else
2771     {
2772       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2773       _clutter_actor_draw_paint_volume_full (self, pv,
2774                                              _clutter_actor_get_debug_name (self),
2775                                              &color);
2776     }
2777 }
2778
2779 static void
2780 _clutter_actor_paint_cull_result (ClutterActor *self,
2781                                   gboolean success,
2782                                   ClutterCullResult result)
2783 {
2784   ClutterPaintVolume *pv;
2785   CoglColor color;
2786
2787   if (success)
2788     {
2789       if (result == CLUTTER_CULL_RESULT_IN)
2790         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2791       else if (result == CLUTTER_CULL_RESULT_OUT)
2792         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2793       else
2794         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2795     }
2796   else
2797     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2798
2799   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2800     _clutter_actor_draw_paint_volume_full (self, pv,
2801                                            _clutter_actor_get_debug_name (self),
2802                                            &color);
2803   else
2804     {
2805       PangoLayout *layout;
2806       char *label =
2807         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2808       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2809       cogl_set_source_color (&color);
2810
2811       layout = pango_layout_new (clutter_actor_get_pango_context (self));
2812       pango_layout_set_text (layout, label, -1);
2813       cogl_pango_render_layout (layout,
2814                                 0,
2815                                 0,
2816                                 &color,
2817                                 0);
2818       g_free (label);
2819       g_object_unref (layout);
2820     }
2821 }
2822
2823 static int clone_paint_level = 0;
2824
2825 void
2826 _clutter_actor_push_clone_paint (void)
2827 {
2828   clone_paint_level++;
2829 }
2830
2831 void
2832 _clutter_actor_pop_clone_paint (void)
2833 {
2834   clone_paint_level--;
2835 }
2836
2837 static gboolean
2838 in_clone_paint (void)
2839 {
2840   return clone_paint_level > 0;
2841 }
2842
2843 /* Returns TRUE if the actor can be ignored */
2844 /* FIXME: we should return a ClutterCullResult, and
2845  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2846  * means there's no point in trying to cull descendants of the current
2847  * node. */
2848 static gboolean
2849 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2850 {
2851   ClutterActorPrivate *priv = self->priv;
2852   ClutterActor *stage;
2853   const ClutterPlane *stage_clip;
2854
2855   if (!priv->last_paint_volume_valid)
2856     {
2857       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2858                     "->last_paint_volume_valid == FALSE",
2859                     _clutter_actor_get_debug_name (self));
2860       return FALSE;
2861     }
2862
2863   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2864     return FALSE;
2865
2866   stage = _clutter_actor_get_stage_internal (self);
2867   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2868   if (G_UNLIKELY (!stage_clip))
2869     {
2870       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2871                     "No stage clip set",
2872                     _clutter_actor_get_debug_name (self));
2873       return FALSE;
2874     }
2875
2876   if (cogl_get_draw_framebuffer () !=
2877       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2878     {
2879       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2880                     "Current framebuffer doesn't correspond to stage",
2881                     _clutter_actor_get_debug_name (self));
2882       return FALSE;
2883     }
2884
2885   *result_out =
2886     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2887   return TRUE;
2888 }
2889
2890 static void
2891 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2892 {
2893   ClutterActorPrivate *priv = self->priv;
2894   const ClutterPaintVolume *pv;
2895
2896   if (priv->last_paint_volume_valid)
2897     {
2898       clutter_paint_volume_free (&priv->last_paint_volume);
2899       priv->last_paint_volume_valid = FALSE;
2900     }
2901
2902   pv = clutter_actor_get_paint_volume (self);
2903   if (!pv)
2904     {
2905       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2906                     "Actor failed to report a paint volume",
2907                     _clutter_actor_get_debug_name (self));
2908       return;
2909     }
2910
2911   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2912
2913   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2914                                             NULL); /* eye coordinates */
2915
2916   priv->last_paint_volume_valid = TRUE;
2917 }
2918
2919 static inline gboolean
2920 actor_has_shader_data (ClutterActor *self)
2921 {
2922   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2923 }
2924
2925 guint32
2926 _clutter_actor_get_pick_id (ClutterActor *self)
2927 {
2928   if (self->priv->pick_id < 0)
2929     return 0;
2930
2931   return self->priv->pick_id;
2932 }
2933
2934 /* This is the same as clutter_actor_add_effect except that it doesn't
2935    queue a redraw and it doesn't notify on the effect property */
2936 static void
2937 _clutter_actor_add_effect_internal (ClutterActor  *self,
2938                                     ClutterEffect *effect)
2939 {
2940   ClutterActorPrivate *priv = self->priv;
2941
2942   if (priv->effects == NULL)
2943     {
2944       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
2945       priv->effects->actor = self;
2946     }
2947
2948   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2949 }
2950
2951 /* This is the same as clutter_actor_remove_effect except that it doesn't
2952    queue a redraw and it doesn't notify on the effect property */
2953 static void
2954 _clutter_actor_remove_effect_internal (ClutterActor  *self,
2955                                        ClutterEffect *effect)
2956 {
2957   ClutterActorPrivate *priv = self->priv;
2958
2959   if (priv->effects == NULL)
2960     return;
2961
2962   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
2963 }
2964
2965 static gboolean
2966 needs_flatten_effect (ClutterActor *self)
2967 {
2968   ClutterActorPrivate *priv = self->priv;
2969
2970   if (G_UNLIKELY (clutter_paint_debug_flags &
2971                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
2972     return FALSE;
2973
2974   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
2975     return TRUE;
2976   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
2977     {
2978       if (clutter_actor_get_paint_opacity (self) < 255 &&
2979           clutter_actor_has_overlaps (self))
2980         return TRUE;
2981     }
2982
2983   return FALSE;
2984 }
2985
2986 static void
2987 add_or_remove_flatten_effect (ClutterActor *self)
2988 {
2989   ClutterActorPrivate *priv = self->priv;
2990
2991   /* Add or remove the flatten effect depending on the
2992      offscreen-redirect property. */
2993   if (needs_flatten_effect (self))
2994     {
2995       if (priv->flatten_effect == NULL)
2996         {
2997           ClutterActorMeta *actor_meta;
2998           gint priority;
2999
3000           priv->flatten_effect = _clutter_flatten_effect_new ();
3001           /* Keep a reference to the effect so that we can queue
3002              redraws from it */
3003           g_object_ref_sink (priv->flatten_effect);
3004
3005           /* Set the priority of the effect to high so that it will
3006              always be applied to the actor first. It uses an internal
3007              priority so that it won't be visible to applications */
3008           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3009           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3010           _clutter_actor_meta_set_priority (actor_meta, priority);
3011
3012           /* This will add the effect without queueing a redraw */
3013           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3014         }
3015     }
3016   else
3017     {
3018       if (priv->flatten_effect != NULL)
3019         {
3020           /* Destroy the effect so that it will lose its fbo cache of
3021              the actor */
3022           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3023           g_object_unref (priv->flatten_effect);
3024           priv->flatten_effect = NULL;
3025         }
3026     }
3027 }
3028
3029 static void
3030 clutter_actor_real_paint (ClutterActor *actor)
3031 {
3032   ClutterActorPrivate *priv = actor->priv;
3033   ClutterActor *iter;
3034
3035   /* paint the background color, if set */
3036   if (priv->bg_color_set)
3037     {
3038       float width, height;
3039       guint8 real_alpha;
3040
3041       clutter_actor_box_get_size (&priv->allocation, &width, &height);
3042
3043       real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3044                  * priv->bg_color.alpha
3045                  / 255;
3046
3047       cogl_set_source_color4ub (priv->bg_color.red,
3048                                 priv->bg_color.green,
3049                                 priv->bg_color.blue,
3050                                 real_alpha);
3051
3052       cogl_rectangle (0, 0, width, height);
3053     }
3054
3055   for (iter = priv->first_child;
3056        iter != NULL;
3057        iter = iter->priv->next_sibling)
3058     {
3059       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3060                     _clutter_actor_get_debug_name (iter),
3061                     _clutter_actor_get_debug_name (actor),
3062                     iter->priv->allocation.x1,
3063                     iter->priv->allocation.y1,
3064                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3065                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3066
3067       clutter_actor_paint (iter);
3068     }
3069 }
3070
3071 /**
3072  * clutter_actor_paint:
3073  * @self: A #ClutterActor
3074  *
3075  * Renders the actor to display.
3076  *
3077  * This function should not be called directly by applications.
3078  * Call clutter_actor_queue_redraw() to queue paints, instead.
3079  *
3080  * This function is context-aware, and will either cause a
3081  * regular paint or a pick paint.
3082  *
3083  * This function will emit the #ClutterActor::paint signal or
3084  * the #ClutterActor::pick signal, depending on the context.
3085  *
3086  * This function does not paint the actor if the actor is set to 0,
3087  * unless it is performing a pick paint.
3088  */
3089 void
3090 clutter_actor_paint (ClutterActor *self)
3091 {
3092   ClutterActorPrivate *priv;
3093   ClutterPickMode pick_mode;
3094   gboolean clip_set = FALSE;
3095   gboolean shader_applied = FALSE;
3096
3097   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3098                           "Actor real-paint counter",
3099                           "Increments each time any actor is painted",
3100                           0 /* no application private data */);
3101   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3102                           "Actor pick-paint counter",
3103                           "Increments each time any actor is painted "
3104                           "for picking",
3105                           0 /* no application private data */);
3106
3107   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3108
3109   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3110     return;
3111
3112   priv = self->priv;
3113
3114   pick_mode = _clutter_context_get_pick_mode ();
3115
3116   if (pick_mode == CLUTTER_PICK_NONE)
3117     priv->propagated_one_redraw = FALSE;
3118
3119   /* It's an important optimization that we consider painting of
3120    * actors with 0 opacity to be a NOP... */
3121   if (pick_mode == CLUTTER_PICK_NONE &&
3122       /* ignore top-levels, since they might be transparent */
3123       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3124       /* Use the override opacity if its been set */
3125       ((priv->opacity_override >= 0) ?
3126        priv->opacity_override : priv->opacity) == 0)
3127     return;
3128
3129   /* if we aren't paintable (not in a toplevel with all
3130    * parents paintable) then do nothing.
3131    */
3132   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3133     return;
3134
3135   /* mark that we are in the paint process */
3136   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3137
3138   cogl_push_matrix();
3139
3140   if (priv->enable_model_view_transform)
3141     {
3142       CoglMatrix matrix;
3143
3144       /* XXX: It could be better to cache the modelview with the actor
3145        * instead of progressively building up the transformations on
3146        * the matrix stack every time we paint. */
3147       cogl_get_modelview_matrix (&matrix);
3148       _clutter_actor_apply_modelview_transform (self, &matrix);
3149
3150 #ifdef CLUTTER_ENABLE_DEBUG
3151       /* Catch when out-of-band transforms have been made by actors not as part
3152        * of an apply_transform vfunc... */
3153       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3154         {
3155           CoglMatrix expected_matrix;
3156
3157           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3158                                                              &expected_matrix);
3159
3160           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3161             {
3162               GString *buf = g_string_sized_new (1024);
3163               ClutterActor *parent;
3164
3165               parent = self;
3166               while (parent != NULL)
3167                 {
3168                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3169
3170                   if (parent->priv->parent != NULL)
3171                     g_string_append (buf, "->");
3172
3173                   parent = parent->priv->parent;
3174                 }
3175
3176               g_warning ("Unexpected transform found when painting actor "
3177                          "\"%s\". This will be caused by one of the actor's "
3178                          "ancestors (%s) using the Cogl API directly to transform "
3179                          "children instead of using ::apply_transform().",
3180                          _clutter_actor_get_debug_name (self),
3181                          buf->str);
3182
3183               g_string_free (buf, TRUE);
3184             }
3185         }
3186 #endif /* CLUTTER_ENABLE_DEBUG */
3187
3188       cogl_set_modelview_matrix (&matrix);
3189     }
3190
3191   if (priv->has_clip)
3192     {
3193       cogl_clip_push_rectangle (priv->clip.x,
3194                                 priv->clip.y,
3195                                 priv->clip.x + priv->clip.width,
3196                                 priv->clip.y + priv->clip.height);
3197       clip_set = TRUE;
3198     }
3199   else if (priv->clip_to_allocation)
3200     {
3201       gfloat width, height;
3202
3203       width  = priv->allocation.x2 - priv->allocation.x1;
3204       height = priv->allocation.y2 - priv->allocation.y1;
3205
3206       cogl_clip_push_rectangle (0, 0, width, height);
3207       clip_set = TRUE;
3208     }
3209
3210   if (pick_mode == CLUTTER_PICK_NONE)
3211     {
3212       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3213
3214       /* We check whether we need to add the flatten effect before
3215          each paint so that we can avoid having a mechanism for
3216          applications to notify when the value of the
3217          has_overlaps virtual changes. */
3218       add_or_remove_flatten_effect (self);
3219     }
3220   else
3221     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3222
3223   /* We save the current paint volume so that the next time the
3224    * actor queues a redraw we can constrain the redraw to just
3225    * cover the union of the new bounding box and the old.
3226    *
3227    * We also fetch the current paint volume to perform culling so
3228    * we can avoid painting actors outside the current clip region.
3229    *
3230    * If we are painting inside a clone, we should neither update
3231    * the paint volume or use it to cull painting, since the paint
3232    * box represents the location of the source actor on the
3233    * screen.
3234    *
3235    * XXX: We are starting to do a lot of vertex transforms on
3236    * the CPU in a typical paint, so at some point we should
3237    * audit these and consider caching some things.
3238    *
3239    * NB: We don't perform culling while picking at this point because
3240    * clutter-stage.c doesn't setup the clipping planes appropriately.
3241    *
3242    * NB: We don't want to update the last-paint-volume during picking
3243    * because the last-paint-volume is used to determine the old screen
3244    * space location of an actor that has moved so we can know the
3245    * minimal region to redraw to clear an old view of the actor. If we
3246    * update this during picking then by the time we come around to
3247    * paint then the last-paint-volume would likely represent the new
3248    * actor position not the old.
3249    */
3250   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3251     {
3252       gboolean success;
3253       /* annoyingly gcc warns if uninitialized even though
3254        * the initialization is redundant :-( */
3255       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3256
3257       if (G_LIKELY ((clutter_paint_debug_flags &
3258                      (CLUTTER_DEBUG_DISABLE_CULLING |
3259                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3260                     (CLUTTER_DEBUG_DISABLE_CULLING |
3261                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3262         _clutter_actor_update_last_paint_volume (self);
3263
3264       success = cull_actor (self, &result);
3265
3266       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3267         _clutter_actor_paint_cull_result (self, success, result);
3268       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3269         goto done;
3270     }
3271
3272   if (priv->effects == NULL)
3273     {
3274       if (pick_mode == CLUTTER_PICK_NONE &&
3275           actor_has_shader_data (self))
3276         {
3277           _clutter_actor_shader_pre_paint (self, FALSE);
3278           shader_applied = TRUE;
3279         }
3280
3281       priv->next_effect_to_paint = NULL;
3282     }
3283   else
3284     priv->next_effect_to_paint =
3285       _clutter_meta_group_peek_metas (priv->effects);
3286
3287   clutter_actor_continue_paint (self);
3288
3289   if (shader_applied)
3290     _clutter_actor_shader_post_paint (self);
3291
3292   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3293                   pick_mode == CLUTTER_PICK_NONE))
3294     _clutter_actor_draw_paint_volume (self);
3295
3296 done:
3297   /* If we make it here then the actor has run through a complete
3298      paint run including all the effects so it's no longer dirty */
3299   if (pick_mode == CLUTTER_PICK_NONE)
3300     priv->is_dirty = FALSE;
3301
3302   if (clip_set)
3303     cogl_clip_pop();
3304
3305   cogl_pop_matrix();
3306
3307   /* paint sequence complete */
3308   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3309 }
3310
3311 /**
3312  * clutter_actor_continue_paint:
3313  * @self: A #ClutterActor
3314  *
3315  * Run the next stage of the paint sequence. This function should only
3316  * be called within the implementation of the ‘run’ virtual of a
3317  * #ClutterEffect. It will cause the run method of the next effect to
3318  * be applied, or it will paint the actual actor if the current effect
3319  * is the last effect in the chain.
3320  *
3321  * Since: 1.8
3322  */
3323 void
3324 clutter_actor_continue_paint (ClutterActor *self)
3325 {
3326   ClutterActorPrivate *priv;
3327
3328   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3329   /* This should only be called from with in the ‘run’ implementation
3330      of a ClutterEffect */
3331   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3332
3333   priv = self->priv;
3334
3335   /* Skip any effects that are disabled */
3336   while (priv->next_effect_to_paint &&
3337          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3338     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3339
3340   /* If this has come from the last effect then we'll just paint the
3341      actual actor */
3342   if (priv->next_effect_to_paint == NULL)
3343     {
3344       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3345         {
3346           g_signal_emit (self, actor_signals[PAINT], 0);
3347         }
3348       else
3349         {
3350           ClutterColor col = { 0, };
3351
3352           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3353
3354           /* Actor will then paint silhouette of itself in supplied
3355            * color.  See clutter_stage_get_actor_at_pos() for where
3356            * picking is enabled.
3357            */
3358           g_signal_emit (self, actor_signals[PICK], 0, &col);
3359         }
3360     }
3361   else
3362     {
3363       ClutterEffect *old_current_effect;
3364       ClutterEffectPaintFlags run_flags = 0;
3365
3366       /* Cache the current effect so that we can put it back before
3367          returning */
3368       old_current_effect = priv->current_effect;
3369
3370       priv->current_effect = priv->next_effect_to_paint->data;
3371       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3372
3373       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3374         {
3375           if (priv->is_dirty)
3376             {
3377               /* If there's an effect queued with this redraw then all
3378                  effects up to that one will be considered dirty. It
3379                  is expected the queued effect will paint the cached
3380                  image and not call clutter_actor_continue_paint again
3381                  (although it should work ok if it does) */
3382               if (priv->effect_to_redraw == NULL ||
3383                   priv->current_effect != priv->effect_to_redraw)
3384                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3385             }
3386
3387           _clutter_effect_paint (priv->current_effect, run_flags);
3388         }
3389       else
3390         {
3391           /* We can't determine when an actor has been modified since
3392              its last pick so lets just assume it has always been
3393              modified */
3394           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3395
3396           _clutter_effect_pick (priv->current_effect, run_flags);
3397         }
3398
3399       priv->current_effect = old_current_effect;
3400     }
3401 }
3402
3403 static ClutterActorTraverseVisitFlags
3404 invalidate_queue_redraw_entry (ClutterActor *self,
3405                                int           depth,
3406                                gpointer      user_data)
3407 {
3408   ClutterActorPrivate *priv = self->priv;
3409
3410   if (priv->queue_redraw_entry != NULL)
3411     {
3412       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3413       priv->queue_redraw_entry = NULL;
3414     }
3415
3416   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3417 }
3418
3419 static inline void
3420 remove_child (ClutterActor *self,
3421               ClutterActor *child)
3422 {
3423   ClutterActor *prev_sibling, *next_sibling;
3424
3425   prev_sibling = child->priv->prev_sibling;
3426   next_sibling = child->priv->next_sibling;
3427
3428   if (prev_sibling != NULL)
3429     prev_sibling->priv->next_sibling = next_sibling;
3430
3431   if (next_sibling != NULL)
3432     next_sibling->priv->prev_sibling = prev_sibling;
3433
3434   if (self->priv->first_child == child)
3435     self->priv->first_child = next_sibling;
3436
3437   if (self->priv->last_child == child)
3438     self->priv->last_child = prev_sibling;
3439
3440   child->priv->parent = NULL;
3441   child->priv->prev_sibling = NULL;
3442   child->priv->next_sibling = NULL;
3443 }
3444
3445 typedef enum {
3446   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3447   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3448   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3449   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3450   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3451   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3452
3453   /* default flags for public API */
3454   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3455                                     REMOVE_CHILD_EMIT_PARENT_SET |
3456                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3457                                     REMOVE_CHILD_CHECK_STATE |
3458                                     REMOVE_CHILD_FLUSH_QUEUE |
3459                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3460
3461   /* flags for legacy/deprecated API */
3462   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3463                                     REMOVE_CHILD_FLUSH_QUEUE |
3464                                     REMOVE_CHILD_EMIT_PARENT_SET |
3465                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3466 } ClutterActorRemoveChildFlags;
3467
3468 /*< private >
3469  * clutter_actor_remove_child_internal:
3470  * @self: a #ClutterActor
3471  * @child: the child of @self that has to be removed
3472  * @flags: control the removal operations
3473  *
3474  * Removes @child from the list of children of @self.
3475  */
3476 static void
3477 clutter_actor_remove_child_internal (ClutterActor                 *self,
3478                                      ClutterActor                 *child,
3479                                      ClutterActorRemoveChildFlags  flags)
3480 {
3481   ClutterActor *old_first, *old_last;
3482   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3483   gboolean flush_queue;
3484   gboolean notify_first_last;
3485   gboolean was_mapped;
3486
3487   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3488   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3489   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3490   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3491   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3492   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3493
3494   if (destroy_meta)
3495     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3496
3497   if (check_state)
3498     {
3499       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3500
3501       /* we need to unrealize *before* we set parent_actor to NULL,
3502        * because in an unrealize method actors are dissociating from the
3503        * stage, which means they need to be able to
3504        * clutter_actor_get_stage().
3505        *
3506        * yhis should unmap and unrealize, unless we're reparenting.
3507        */
3508       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3509     }
3510   else
3511     was_mapped = FALSE;
3512
3513   if (flush_queue)
3514     {
3515       /* We take this opportunity to invalidate any queue redraw entry
3516        * associated with the actor and descendants since we won't be able to
3517        * determine the appropriate stage after this.
3518        *
3519        * we do this after we updated the mapped state because actors might
3520        * end up queueing redraws inside their mapped/unmapped virtual
3521        * functions, and if we invalidate the redraw entry we could end up
3522        * with an inconsistent state and weird memory corruption. see
3523        * bugs:
3524        *
3525        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3526        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3527        */
3528       _clutter_actor_traverse (child,
3529                                0,
3530                                invalidate_queue_redraw_entry,
3531                                NULL,
3532                                NULL);
3533     }
3534
3535   old_first = self->priv->first_child;
3536   old_last = self->priv->last_child;
3537
3538   remove_child (self, child);
3539
3540   self->priv->n_children -= 1;
3541
3542   self->priv->age += 1;
3543
3544   /* clutter_actor_reparent() will emit ::parent-set for us */
3545   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3546     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3547
3548   /* if the child was mapped then we need to relayout ourselves to account
3549    * for the removed child
3550    */
3551   if (was_mapped)
3552     clutter_actor_queue_relayout (self);
3553
3554   /* we need to emit the signal before dropping the reference */
3555   if (emit_actor_removed)
3556     g_signal_emit_by_name (self, "actor-removed", child);
3557
3558   if (notify_first_last)
3559     {
3560       if (old_first != self->priv->first_child)
3561         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3562
3563       if (old_last != self->priv->last_child)
3564         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3565     }
3566
3567   /* remove the reference we acquired in clutter_actor_add_child() */
3568   g_object_unref (child);
3569 }
3570
3571 static const ClutterTransformInfo default_transform_info = {
3572   0.0, { 0, },          /* rotation-x */
3573   0.0, { 0, },          /* rotation-y */
3574   0.0, { 0, },          /* rotation-z */
3575
3576   1.0, 1.0, { 0, },     /* scale */
3577
3578   { 0, },               /* anchor */
3579 };
3580
3581 /*< private >
3582  * _clutter_actor_get_transform_info_or_defaults:
3583  * @self: a #ClutterActor
3584  *
3585  * Retrieves the ClutterTransformInfo structure associated to an actor.
3586  *
3587  * If the actor does not have a ClutterTransformInfo structure associated
3588  * to it, then the default structure will be returned.
3589  *
3590  * This function should only be used for getters.
3591  *
3592  * Return value: a const pointer to the ClutterTransformInfo structure
3593  */
3594 const ClutterTransformInfo *
3595 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3596 {
3597   ClutterTransformInfo *info;
3598
3599   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3600   if (info != NULL)
3601     return info;
3602
3603   return &default_transform_info;
3604 }
3605
3606 static void
3607 clutter_transform_info_free (gpointer data)
3608 {
3609   if (data != NULL)
3610     g_slice_free (ClutterTransformInfo, data);
3611 }
3612
3613 /*< private >
3614  * _clutter_actor_get_transform_info:
3615  * @self: a #ClutterActor
3616  *
3617  * Retrieves a pointer to the ClutterTransformInfo structure.
3618  *
3619  * If the actor does not have a ClutterTransformInfo associated to it, one
3620  * will be created and initialized to the default values.
3621  *
3622  * This function should be used for setters.
3623  *
3624  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3625  * instead.
3626  *
3627  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3628  *   structure
3629  */
3630 ClutterTransformInfo *
3631 _clutter_actor_get_transform_info (ClutterActor *self)
3632 {
3633   ClutterTransformInfo *info;
3634
3635   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3636   if (info == NULL)
3637     {
3638       info = g_slice_new (ClutterTransformInfo);
3639
3640       *info = default_transform_info;
3641
3642       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3643                                info,
3644                                clutter_transform_info_free);
3645     }
3646
3647   return info;
3648 }
3649
3650 /*< private >
3651  * clutter_actor_set_rotation_angle_internal:
3652  * @self: a #ClutterActor
3653  * @axis: the axis of the angle to change
3654  * @angle: the angle of rotation
3655  *
3656  * Sets the rotation angle on the given axis without affecting the
3657  * rotation center point.
3658  */
3659 static inline void
3660 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3661                                            ClutterRotateAxis  axis,
3662                                            gdouble            angle)
3663 {
3664   GObject *obj = G_OBJECT (self);
3665   ClutterTransformInfo *info;
3666
3667   info = _clutter_actor_get_transform_info (self);
3668
3669   g_object_freeze_notify (obj);
3670
3671   switch (axis)
3672     {
3673     case CLUTTER_X_AXIS:
3674       info->rx_angle = angle;
3675       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3676       break;
3677
3678     case CLUTTER_Y_AXIS:
3679       info->ry_angle = angle;
3680       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3681       break;
3682
3683     case CLUTTER_Z_AXIS:
3684       info->rz_angle = angle;
3685       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3686       break;
3687     }
3688
3689   self->priv->transform_valid = FALSE;
3690
3691   g_object_thaw_notify (obj);
3692
3693   clutter_actor_queue_redraw (self);
3694 }
3695
3696 /*< private >
3697  * clutter_actor_set_rotation_center_internal:
3698  * @self: a #ClutterActor
3699  * @axis: the axis of the center to change
3700  * @center: the coordinates of the rotation center
3701  *
3702  * Sets the rotation center on the given axis without affecting the
3703  * rotation angle.
3704  */
3705 static inline void
3706 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
3707                                             ClutterRotateAxis    axis,
3708                                             const ClutterVertex *center)
3709 {
3710   GObject *obj = G_OBJECT (self);
3711   ClutterTransformInfo *info;
3712   ClutterVertex v = { 0, 0, 0 };
3713
3714   info = _clutter_actor_get_transform_info (self);
3715
3716   if (center != NULL)
3717     v = *center;
3718
3719   g_object_freeze_notify (obj);
3720
3721   switch (axis)
3722     {
3723     case CLUTTER_X_AXIS:
3724       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3725       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3726       break;
3727
3728     case CLUTTER_Y_AXIS:
3729       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3730       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3731       break;
3732
3733     case CLUTTER_Z_AXIS:
3734       /* if the previously set rotation center was fractional, then
3735        * setting explicit coordinates will have to notify the
3736        * :rotation-center-z-gravity property as well
3737        */
3738       if (info->rz_center.is_fractional)
3739         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3740
3741       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3742       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3743       break;
3744     }
3745
3746   self->priv->transform_valid = FALSE;
3747
3748   g_object_thaw_notify (obj);
3749
3750   clutter_actor_queue_redraw (self);
3751 }
3752
3753 static inline void
3754 clutter_actor_set_scale_factor (ClutterActor      *self,
3755                                 ClutterRotateAxis  axis,
3756                                 gdouble            factor)
3757 {
3758   GObject *obj = G_OBJECT (self);
3759   ClutterTransformInfo *info;
3760
3761   info = _clutter_actor_get_transform_info (self);
3762
3763   g_object_freeze_notify (obj);
3764
3765   switch (axis)
3766     {
3767     case CLUTTER_X_AXIS:
3768       info->scale_x = factor;
3769       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
3770       break;
3771
3772     case CLUTTER_Y_AXIS:
3773       info->scale_y = factor;
3774       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
3775       break;
3776
3777     default:
3778       g_assert_not_reached ();
3779     }
3780
3781   self->priv->transform_valid = FALSE;
3782
3783   clutter_actor_queue_redraw (self);
3784
3785   g_object_thaw_notify (obj);
3786 }
3787
3788 static inline void
3789 clutter_actor_set_scale_center (ClutterActor      *self,
3790                                 ClutterRotateAxis  axis,
3791                                 gfloat             coord)
3792 {
3793   GObject *obj = G_OBJECT (self);
3794   ClutterTransformInfo *info;
3795   gfloat center_x, center_y;
3796
3797   info = _clutter_actor_get_transform_info (self);
3798
3799   g_object_freeze_notify (obj);
3800
3801   /* get the current scale center coordinates */
3802   clutter_anchor_coord_get_units (self, &info->scale_center,
3803                                   &center_x,
3804                                   &center_y,
3805                                   NULL);
3806
3807   /* we need to notify this too, because setting explicit coordinates will
3808    * change the gravity as a side effect
3809    */
3810   if (info->scale_center.is_fractional)
3811     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3812
3813   switch (axis)
3814     {
3815     case CLUTTER_X_AXIS:
3816       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3817       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3818       break;
3819
3820     case CLUTTER_Y_AXIS:
3821       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3822       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3823       break;
3824
3825     default:
3826       g_assert_not_reached ();
3827     }
3828
3829   self->priv->transform_valid = FALSE;
3830
3831   clutter_actor_queue_redraw (self);
3832
3833   g_object_thaw_notify (obj);
3834 }
3835
3836 static inline void
3837 clutter_actor_set_anchor_coord (ClutterActor      *self,
3838                                 ClutterRotateAxis  axis,
3839                                 gfloat             coord)
3840 {
3841   GObject *obj = G_OBJECT (self);
3842   ClutterTransformInfo *info;
3843   gfloat anchor_x, anchor_y;
3844
3845   info = _clutter_actor_get_transform_info (self);
3846
3847   g_object_freeze_notify (obj);
3848
3849   clutter_anchor_coord_get_units (self, &info->anchor,
3850                                   &anchor_x,
3851                                   &anchor_y,
3852                                   NULL);
3853
3854   if (info->anchor.is_fractional)
3855     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
3856
3857   switch (axis)
3858     {
3859     case CLUTTER_X_AXIS:
3860       clutter_anchor_coord_set_units (&info->anchor,
3861                                       coord,
3862                                       anchor_y,
3863                                       0.0);
3864       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
3865       break;
3866
3867     case CLUTTER_Y_AXIS:
3868       clutter_anchor_coord_set_units (&info->anchor,
3869                                       anchor_x,
3870                                       coord,
3871                                       0.0);
3872       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
3873       break;
3874
3875     default:
3876       g_assert_not_reached ();
3877     }
3878
3879   self->priv->transform_valid = FALSE;
3880
3881   clutter_actor_queue_redraw (self);
3882
3883   g_object_thaw_notify (obj);
3884 }
3885
3886 static void
3887 clutter_actor_set_property (GObject      *object,
3888                             guint         prop_id,
3889                             const GValue *value,
3890                             GParamSpec   *pspec)
3891 {
3892   ClutterActor *actor = CLUTTER_ACTOR (object);
3893   ClutterActorPrivate *priv = actor->priv;
3894
3895   switch (prop_id)
3896     {
3897     case PROP_X:
3898       clutter_actor_set_x (actor, g_value_get_float (value));
3899       break;
3900
3901     case PROP_Y:
3902       clutter_actor_set_y (actor, g_value_get_float (value));
3903       break;
3904
3905     case PROP_WIDTH:
3906       clutter_actor_set_width (actor, g_value_get_float (value));
3907       break;
3908
3909     case PROP_HEIGHT:
3910       clutter_actor_set_height (actor, g_value_get_float (value));
3911       break;
3912
3913     case PROP_FIXED_X:
3914       clutter_actor_set_x (actor, g_value_get_float (value));
3915       break;
3916
3917     case PROP_FIXED_Y:
3918       clutter_actor_set_y (actor, g_value_get_float (value));
3919       break;
3920
3921     case PROP_FIXED_POSITION_SET:
3922       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
3923       break;
3924
3925     case PROP_MIN_WIDTH:
3926       clutter_actor_set_min_width (actor, g_value_get_float (value));
3927       break;
3928
3929     case PROP_MIN_HEIGHT:
3930       clutter_actor_set_min_height (actor, g_value_get_float (value));
3931       break;
3932
3933     case PROP_NATURAL_WIDTH:
3934       clutter_actor_set_natural_width (actor, g_value_get_float (value));
3935       break;
3936
3937     case PROP_NATURAL_HEIGHT:
3938       clutter_actor_set_natural_height (actor, g_value_get_float (value));
3939       break;
3940
3941     case PROP_MIN_WIDTH_SET:
3942       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
3943       break;
3944
3945     case PROP_MIN_HEIGHT_SET:
3946       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
3947       break;
3948
3949     case PROP_NATURAL_WIDTH_SET:
3950       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
3951       break;
3952
3953     case PROP_NATURAL_HEIGHT_SET:
3954       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
3955       break;
3956
3957     case PROP_REQUEST_MODE:
3958       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
3959       break;
3960
3961     case PROP_DEPTH:
3962       clutter_actor_set_depth (actor, g_value_get_float (value));
3963       break;
3964
3965     case PROP_OPACITY:
3966       clutter_actor_set_opacity (actor, g_value_get_uint (value));
3967       break;
3968
3969     case PROP_OFFSCREEN_REDIRECT:
3970       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
3971       break;
3972
3973     case PROP_NAME:
3974       clutter_actor_set_name (actor, g_value_get_string (value));
3975       break;
3976
3977     case PROP_VISIBLE:
3978       if (g_value_get_boolean (value) == TRUE)
3979         clutter_actor_show (actor);
3980       else
3981         clutter_actor_hide (actor);
3982       break;
3983
3984     case PROP_SCALE_X:
3985       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
3986                                       g_value_get_double (value));
3987       break;
3988
3989     case PROP_SCALE_Y:
3990       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
3991                                       g_value_get_double (value));
3992       break;
3993
3994     case PROP_SCALE_CENTER_X:
3995       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
3996                                       g_value_get_float (value));
3997       break;
3998
3999     case PROP_SCALE_CENTER_Y:
4000       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4001                                       g_value_get_float (value));
4002       break;
4003
4004     case PROP_SCALE_GRAVITY:
4005       {
4006         const ClutterTransformInfo *info;
4007         ClutterGravity gravity;
4008
4009         info = _clutter_actor_get_transform_info_or_defaults (actor);
4010         gravity = g_value_get_enum (value);
4011
4012         clutter_actor_set_scale_with_gravity (actor,
4013                                               info->scale_x,
4014                                               info->scale_y,
4015                                               gravity);
4016       }
4017       break;
4018
4019     case PROP_CLIP:
4020       {
4021         const ClutterGeometry *geom = g_value_get_boxed (value);
4022
4023         clutter_actor_set_clip (actor,
4024                                 geom->x, geom->y,
4025                                 geom->width, geom->height);
4026       }
4027       break;
4028
4029     case PROP_CLIP_TO_ALLOCATION:
4030       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4031       break;
4032
4033     case PROP_REACTIVE:
4034       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4035       break;
4036
4037     case PROP_ROTATION_ANGLE_X:
4038       clutter_actor_set_rotation_angle_internal (actor,
4039                                                  CLUTTER_X_AXIS,
4040                                                  g_value_get_double (value));
4041       break;
4042
4043     case PROP_ROTATION_ANGLE_Y:
4044       clutter_actor_set_rotation_angle_internal (actor,
4045                                                  CLUTTER_Y_AXIS,
4046                                                  g_value_get_double (value));
4047       break;
4048
4049     case PROP_ROTATION_ANGLE_Z:
4050       clutter_actor_set_rotation_angle_internal (actor,
4051                                                  CLUTTER_Z_AXIS,
4052                                                  g_value_get_double (value));
4053       break;
4054
4055     case PROP_ROTATION_CENTER_X:
4056       clutter_actor_set_rotation_center_internal (actor,
4057                                                   CLUTTER_X_AXIS,
4058                                                   g_value_get_boxed (value));
4059       break;
4060
4061     case PROP_ROTATION_CENTER_Y:
4062       clutter_actor_set_rotation_center_internal (actor,
4063                                                   CLUTTER_Y_AXIS,
4064                                                   g_value_get_boxed (value));
4065       break;
4066
4067     case PROP_ROTATION_CENTER_Z:
4068       clutter_actor_set_rotation_center_internal (actor,
4069                                                   CLUTTER_Z_AXIS,
4070                                                   g_value_get_boxed (value));
4071       break;
4072
4073     case PROP_ROTATION_CENTER_Z_GRAVITY:
4074       {
4075         const ClutterTransformInfo *info;
4076
4077         info = _clutter_actor_get_transform_info_or_defaults (actor);
4078         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4079                                                    g_value_get_enum (value));
4080       }
4081       break;
4082
4083     case PROP_ANCHOR_X:
4084       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4085                                       g_value_get_float (value));
4086       break;
4087
4088     case PROP_ANCHOR_Y:
4089       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4090                                       g_value_get_float (value));
4091       break;
4092
4093     case PROP_ANCHOR_GRAVITY:
4094       clutter_actor_set_anchor_point_from_gravity (actor,
4095                                                    g_value_get_enum (value));
4096       break;
4097
4098     case PROP_SHOW_ON_SET_PARENT:
4099       priv->show_on_set_parent = g_value_get_boolean (value);
4100       break;
4101
4102     case PROP_TEXT_DIRECTION:
4103       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4104       break;
4105
4106     case PROP_ACTIONS:
4107       clutter_actor_add_action (actor, g_value_get_object (value));
4108       break;
4109
4110     case PROP_CONSTRAINTS:
4111       clutter_actor_add_constraint (actor, g_value_get_object (value));
4112       break;
4113
4114     case PROP_EFFECT:
4115       clutter_actor_add_effect (actor, g_value_get_object (value));
4116       break;
4117
4118     case PROP_LAYOUT_MANAGER:
4119       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4120       break;
4121
4122     case PROP_X_ALIGN:
4123       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4124       break;
4125
4126     case PROP_Y_ALIGN:
4127       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4128       break;
4129
4130     case PROP_MARGIN_TOP:
4131       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4132       break;
4133
4134     case PROP_MARGIN_BOTTOM:
4135       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4136       break;
4137
4138     case PROP_MARGIN_LEFT:
4139       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4140       break;
4141
4142     case PROP_MARGIN_RIGHT:
4143       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4144       break;
4145
4146     case PROP_BACKGROUND_COLOR:
4147       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4148       break;
4149
4150     default:
4151       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4152       break;
4153     }
4154 }
4155
4156 static void
4157 clutter_actor_get_property (GObject    *object,
4158                             guint       prop_id,
4159                             GValue     *value,
4160                             GParamSpec *pspec)
4161 {
4162   ClutterActor *actor = CLUTTER_ACTOR (object);
4163   ClutterActorPrivate *priv = actor->priv;
4164
4165   switch (prop_id)
4166     {
4167     case PROP_X:
4168       g_value_set_float (value, clutter_actor_get_x (actor));
4169       break;
4170
4171     case PROP_Y:
4172       g_value_set_float (value, clutter_actor_get_y (actor));
4173       break;
4174
4175     case PROP_WIDTH:
4176       g_value_set_float (value, clutter_actor_get_width (actor));
4177       break;
4178
4179     case PROP_HEIGHT:
4180       g_value_set_float (value, clutter_actor_get_height (actor));
4181       break;
4182
4183     case PROP_FIXED_X:
4184       {
4185         const ClutterLayoutInfo *info;
4186
4187         info = _clutter_actor_get_layout_info_or_defaults (actor);
4188         g_value_set_float (value, info->fixed_x);
4189       }
4190       break;
4191
4192     case PROP_FIXED_Y:
4193       {
4194         const ClutterLayoutInfo *info;
4195
4196         info = _clutter_actor_get_layout_info_or_defaults (actor);
4197         g_value_set_float (value, info->fixed_y);
4198       }
4199       break;
4200
4201     case PROP_FIXED_POSITION_SET:
4202       g_value_set_boolean (value, priv->position_set);
4203       break;
4204
4205     case PROP_MIN_WIDTH:
4206       {
4207         const ClutterLayoutInfo *info;
4208
4209         info = _clutter_actor_get_layout_info_or_defaults (actor);
4210         g_value_set_float (value, info->min_width);
4211       }
4212       break;
4213
4214     case PROP_MIN_HEIGHT:
4215       {
4216         const ClutterLayoutInfo *info;
4217
4218         info = _clutter_actor_get_layout_info_or_defaults (actor);
4219         g_value_set_float (value, info->min_height);
4220       }
4221       break;
4222
4223     case PROP_NATURAL_WIDTH:
4224       {
4225         const ClutterLayoutInfo *info;
4226
4227         info = _clutter_actor_get_layout_info_or_defaults (actor);
4228         g_value_set_float (value, info->natural_width);
4229       }
4230       break;
4231
4232     case PROP_NATURAL_HEIGHT:
4233       {
4234         const ClutterLayoutInfo *info;
4235
4236         info = _clutter_actor_get_layout_info_or_defaults (actor);
4237         g_value_set_float (value, info->natural_height);
4238       }
4239       break;
4240
4241     case PROP_MIN_WIDTH_SET:
4242       g_value_set_boolean (value, priv->min_width_set);
4243       break;
4244
4245     case PROP_MIN_HEIGHT_SET:
4246       g_value_set_boolean (value, priv->min_height_set);
4247       break;
4248
4249     case PROP_NATURAL_WIDTH_SET:
4250       g_value_set_boolean (value, priv->natural_width_set);
4251       break;
4252
4253     case PROP_NATURAL_HEIGHT_SET:
4254       g_value_set_boolean (value, priv->natural_height_set);
4255       break;
4256
4257     case PROP_REQUEST_MODE:
4258       g_value_set_enum (value, priv->request_mode);
4259       break;
4260
4261     case PROP_ALLOCATION:
4262       g_value_set_boxed (value, &priv->allocation);
4263       break;
4264
4265     case PROP_DEPTH:
4266       g_value_set_float (value, clutter_actor_get_depth (actor));
4267       break;
4268
4269     case PROP_OPACITY:
4270       g_value_set_uint (value, priv->opacity);
4271       break;
4272
4273     case PROP_OFFSCREEN_REDIRECT:
4274       g_value_set_enum (value, priv->offscreen_redirect);
4275       break;
4276
4277     case PROP_NAME:
4278       g_value_set_string (value, priv->name);
4279       break;
4280
4281     case PROP_VISIBLE:
4282       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4283       break;
4284
4285     case PROP_MAPPED:
4286       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4287       break;
4288
4289     case PROP_REALIZED:
4290       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4291       break;
4292
4293     case PROP_HAS_CLIP:
4294       g_value_set_boolean (value, priv->has_clip);
4295       break;
4296
4297     case PROP_CLIP:
4298       {
4299         ClutterGeometry clip;
4300
4301         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4302         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4303         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4304         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4305
4306         g_value_set_boxed (value, &clip);
4307       }
4308       break;
4309
4310     case PROP_CLIP_TO_ALLOCATION:
4311       g_value_set_boolean (value, priv->clip_to_allocation);
4312       break;
4313
4314     case PROP_SCALE_X:
4315       {
4316         const ClutterTransformInfo *info;
4317
4318         info = _clutter_actor_get_transform_info_or_defaults (actor);
4319         g_value_set_double (value, info->scale_x);
4320       }
4321       break;
4322
4323     case PROP_SCALE_Y:
4324       {
4325         const ClutterTransformInfo *info;
4326
4327         info = _clutter_actor_get_transform_info_or_defaults (actor);
4328         g_value_set_double (value, info->scale_y);
4329       }
4330       break;
4331
4332     case PROP_SCALE_CENTER_X:
4333       {
4334         gfloat center;
4335
4336         clutter_actor_get_scale_center (actor, &center, NULL);
4337
4338         g_value_set_float (value, center);
4339       }
4340       break;
4341
4342     case PROP_SCALE_CENTER_Y:
4343       {
4344         gfloat center;
4345
4346         clutter_actor_get_scale_center (actor, NULL, &center);
4347
4348         g_value_set_float (value, center);
4349       }
4350       break;
4351
4352     case PROP_SCALE_GRAVITY:
4353       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4354       break;
4355
4356     case PROP_REACTIVE:
4357       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4358       break;
4359
4360     case PROP_ROTATION_ANGLE_X:
4361       {
4362         const ClutterTransformInfo *info;
4363
4364         info = _clutter_actor_get_transform_info_or_defaults (actor);
4365         g_value_set_double (value, info->rx_angle);
4366       }
4367       break;
4368
4369     case PROP_ROTATION_ANGLE_Y:
4370       {
4371         const ClutterTransformInfo *info;
4372
4373         info = _clutter_actor_get_transform_info_or_defaults (actor);
4374         g_value_set_double (value, info->ry_angle);
4375       }
4376       break;
4377
4378     case PROP_ROTATION_ANGLE_Z:
4379       {
4380         const ClutterTransformInfo *info;
4381
4382         info = _clutter_actor_get_transform_info_or_defaults (actor);
4383         g_value_set_double (value, info->rz_angle);
4384       }
4385       break;
4386
4387     case PROP_ROTATION_CENTER_X:
4388       {
4389         ClutterVertex center;
4390
4391         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4392                                     &center.x,
4393                                     &center.y,
4394                                     &center.z);
4395
4396         g_value_set_boxed (value, &center);
4397       }
4398       break;
4399
4400     case PROP_ROTATION_CENTER_Y:
4401       {
4402         ClutterVertex center;
4403
4404         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4405                                     &center.x,
4406                                     &center.y,
4407                                     &center.z);
4408
4409         g_value_set_boxed (value, &center);
4410       }
4411       break;
4412
4413     case PROP_ROTATION_CENTER_Z:
4414       {
4415         ClutterVertex center;
4416
4417         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4418                                     &center.x,
4419                                     &center.y,
4420                                     &center.z);
4421
4422         g_value_set_boxed (value, &center);
4423       }
4424       break;
4425
4426     case PROP_ROTATION_CENTER_Z_GRAVITY:
4427       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4428       break;
4429
4430     case PROP_ANCHOR_X:
4431       {
4432         const ClutterTransformInfo *info;
4433         gfloat anchor_x;
4434
4435         info = _clutter_actor_get_transform_info_or_defaults (actor);
4436         clutter_anchor_coord_get_units (actor, &info->anchor,
4437                                         &anchor_x,
4438                                         NULL,
4439                                         NULL);
4440         g_value_set_float (value, anchor_x);
4441       }
4442       break;
4443
4444     case PROP_ANCHOR_Y:
4445       {
4446         const ClutterTransformInfo *info;
4447         gfloat anchor_y;
4448
4449         info = _clutter_actor_get_transform_info_or_defaults (actor);
4450         clutter_anchor_coord_get_units (actor, &info->anchor,
4451                                         NULL,
4452                                         &anchor_y,
4453                                         NULL);
4454         g_value_set_float (value, anchor_y);
4455       }
4456       break;
4457
4458     case PROP_ANCHOR_GRAVITY:
4459       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4460       break;
4461
4462     case PROP_SHOW_ON_SET_PARENT:
4463       g_value_set_boolean (value, priv->show_on_set_parent);
4464       break;
4465
4466     case PROP_TEXT_DIRECTION:
4467       g_value_set_enum (value, priv->text_direction);
4468       break;
4469
4470     case PROP_HAS_POINTER:
4471       g_value_set_boolean (value, priv->has_pointer);
4472       break;
4473
4474     case PROP_LAYOUT_MANAGER:
4475       g_value_set_object (value, priv->layout_manager);
4476       break;
4477
4478     case PROP_X_ALIGN:
4479       {
4480         const ClutterLayoutInfo *info;
4481
4482         info = _clutter_actor_get_layout_info_or_defaults (actor);
4483         g_value_set_enum (value, info->x_align);
4484       }
4485       break;
4486
4487     case PROP_Y_ALIGN:
4488       {
4489         const ClutterLayoutInfo *info;
4490
4491         info = _clutter_actor_get_layout_info_or_defaults (actor);
4492         g_value_set_enum (value, info->y_align);
4493       }
4494       break;
4495
4496     case PROP_MARGIN_TOP:
4497       {
4498         const ClutterLayoutInfo *info;
4499
4500         info = _clutter_actor_get_layout_info_or_defaults (actor);
4501         g_value_set_float (value, info->margin.top);
4502       }
4503       break;
4504
4505     case PROP_MARGIN_BOTTOM:
4506       {
4507         const ClutterLayoutInfo *info;
4508
4509         info = _clutter_actor_get_layout_info_or_defaults (actor);
4510         g_value_set_float (value, info->margin.bottom);
4511       }
4512       break;
4513
4514     case PROP_MARGIN_LEFT:
4515       {
4516         const ClutterLayoutInfo *info;
4517
4518         info = _clutter_actor_get_layout_info_or_defaults (actor);
4519         g_value_set_float (value, info->margin.left);
4520       }
4521       break;
4522
4523     case PROP_MARGIN_RIGHT:
4524       {
4525         const ClutterLayoutInfo *info;
4526
4527         info = _clutter_actor_get_layout_info_or_defaults (actor);
4528         g_value_set_float (value, info->margin.right);
4529       }
4530       break;
4531
4532     case PROP_BACKGROUND_COLOR_SET:
4533       g_value_set_boolean (value, priv->bg_color_set);
4534       break;
4535
4536     case PROP_BACKGROUND_COLOR:
4537       g_value_set_boxed (value, &priv->bg_color);
4538       break;
4539
4540     case PROP_FIRST_CHILD:
4541       g_value_set_object (value, priv->first_child);
4542       break;
4543
4544     case PROP_LAST_CHILD:
4545       g_value_set_object (value, priv->last_child);
4546       break;
4547
4548     default:
4549       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4550       break;
4551     }
4552 }
4553
4554 static void
4555 clutter_actor_dispose (GObject *object)
4556 {
4557   ClutterActor *self = CLUTTER_ACTOR (object);
4558   ClutterActorPrivate *priv = self->priv;
4559
4560   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4561                 priv->id,
4562                 g_type_name (G_OBJECT_TYPE (self)),
4563                 object->ref_count);
4564
4565   g_signal_emit (self, actor_signals[DESTROY], 0);
4566
4567   /* avoid recursing when called from clutter_actor_destroy() */
4568   if (priv->parent != NULL)
4569     {
4570       ClutterActor *parent = priv->parent;
4571
4572       /* go through the Container implementation unless this
4573        * is an internal child and has been marked as such.
4574        *
4575        * removing the actor from its parent will reset the
4576        * realized and mapped states.
4577        */
4578       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4579         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4580       else
4581         clutter_actor_remove_child_internal (parent, self,
4582                                              REMOVE_CHILD_LEGACY_FLAGS);
4583     }
4584
4585   /* parent must be gone at this point */
4586   g_assert (priv->parent == NULL);
4587
4588   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4589     {
4590       /* can't be mapped or realized with no parent */
4591       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4592       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4593     }
4594
4595   g_clear_object (&priv->pango_context);
4596   g_clear_object (&priv->actions);
4597   g_clear_object (&priv->constraints);
4598   g_clear_object (&priv->effects);
4599   g_clear_object (&priv->flatten_effect);
4600
4601   if (priv->layout_manager != NULL)
4602     {
4603       clutter_layout_manager_set_container (priv->layout_manager, NULL);
4604       g_object_unref (priv->layout_manager);
4605       priv->layout_manager = NULL;
4606     }
4607
4608   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4609 }
4610
4611 static void
4612 clutter_actor_finalize (GObject *object)
4613 {
4614   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4615
4616   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4617                 priv->name != NULL ? priv->name : "<none>",
4618                 priv->id,
4619                 g_type_name (G_OBJECT_TYPE (object)));
4620
4621   _clutter_context_release_id (priv->id);
4622
4623   g_free (priv->name);
4624
4625   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4626 }
4627
4628
4629 /**
4630  * clutter_actor_get_accessible:
4631  * @self: a #ClutterActor
4632  *
4633  * Returns the accessible object that describes the actor to an
4634  * assistive technology.
4635  *
4636  * If no class-specific #AtkObject implementation is available for the
4637  * actor instance in question, it will inherit an #AtkObject
4638  * implementation from the first ancestor class for which such an
4639  * implementation is defined.
4640  *
4641  * The documentation of the <ulink
4642  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4643  * library contains more information about accessible objects and
4644  * their uses.
4645  *
4646  * Returns: (transfer none): the #AtkObject associated with @actor
4647  */
4648 AtkObject *
4649 clutter_actor_get_accessible (ClutterActor *self)
4650 {
4651   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4652
4653   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4654 }
4655
4656 static AtkObject *
4657 clutter_actor_real_get_accessible (ClutterActor *actor)
4658 {
4659   return atk_gobject_accessible_for_object (G_OBJECT (actor));
4660 }
4661
4662 static AtkObject *
4663 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4664 {
4665   AtkObject *accessible;
4666
4667   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4668   if (accessible != NULL)
4669     g_object_ref (accessible);
4670
4671   return accessible;
4672 }
4673
4674 static void
4675 atk_implementor_iface_init (AtkImplementorIface *iface)
4676 {
4677   iface->ref_accessible = _clutter_actor_ref_accessible;
4678 }
4679
4680 static gboolean
4681 clutter_actor_real_get_paint_volume (ClutterActor       *self,
4682                                      ClutterPaintVolume *volume)
4683 {
4684   ClutterActorPrivate *priv = self->priv;
4685   ClutterActor *child;
4686   gboolean res;
4687
4688   /* this is the default return value: we cannot know if a class
4689    * is going to paint outside its allocation, so we take the
4690    * conservative approach.
4691    */
4692   res = FALSE;
4693
4694   /* we start from the allocation */
4695   clutter_paint_volume_set_width (volume,
4696                                   priv->allocation.x2 - priv->allocation.x1);
4697   clutter_paint_volume_set_height (volume,
4698                                    priv->allocation.y2 - priv->allocation.y1);
4699
4700   /* if the actor has a clip set then we have a pretty definite
4701    * size for the paint volume: the actor cannot possibly paint
4702    * outside the clip region.
4703    */
4704   if (priv->clip_to_allocation)
4705     {
4706       /* the allocation has already been set, so we just flip the
4707        * return value
4708        */
4709       res = TRUE;
4710     }
4711   else
4712     {
4713       if (priv->has_clip &&
4714           priv->clip.width >= 0 &&
4715           priv->clip.height >= 0)
4716         {
4717           ClutterVertex origin;
4718
4719           origin.x = priv->clip.x;
4720           origin.y = priv->clip.y;
4721           origin.z = 0;
4722
4723           clutter_paint_volume_set_origin (volume, &origin);
4724           clutter_paint_volume_set_width (volume, priv->clip.width);
4725           clutter_paint_volume_set_height (volume, priv->clip.height);
4726
4727           res = TRUE;
4728         }
4729
4730       /* if we don't have children we just bail out here... */
4731       if (priv->n_children == 0)
4732         return res;
4733
4734       /* ...but if we have children then we ask for their paint volume in
4735        * our coordinates. if any of our children replies that it doesn't
4736        * have a paint volume, we bail out
4737        */
4738       for (child = priv->first_child;
4739            child != NULL;
4740            child = child->priv->next_sibling)
4741         {
4742           const ClutterPaintVolume *child_volume;
4743
4744           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4745           if (child_volume == NULL)
4746             {
4747               res = FALSE;
4748               break;
4749             }
4750
4751           clutter_paint_volume_union (volume, child_volume);
4752           res = TRUE;
4753         }
4754     }
4755
4756   return res;
4757 }
4758
4759 static gboolean
4760 clutter_actor_real_has_overlaps (ClutterActor *self)
4761 {
4762   /* By default we'll assume that all actors need an offscreen redirect to get
4763    * the correct opacity. Actors such as ClutterTexture that would never need
4764    * an offscreen redirect can override this to return FALSE. */
4765   return TRUE;
4766 }
4767
4768 static void
4769 clutter_actor_real_destroy (ClutterActor *actor)
4770 {
4771   ClutterActorIter iter;
4772
4773   clutter_actor_iter_init (&iter, actor);
4774   while (clutter_actor_iter_next (&iter, NULL))
4775     clutter_actor_iter_destroy (&iter);
4776 }
4777
4778 static GObject *
4779 clutter_actor_constructor (GType gtype,
4780                            guint n_props,
4781                            GObjectConstructParam *props)
4782 {
4783   GObjectClass *gobject_class;
4784   ClutterActor *self;
4785   GObject *retval;
4786
4787   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
4788   retval = gobject_class->constructor (gtype, n_props, props);
4789   self = CLUTTER_ACTOR (retval);
4790
4791   if (self->priv->layout_manager == NULL)
4792     {
4793       ClutterLayoutManager *default_layout;
4794
4795       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
4796
4797       default_layout = clutter_fixed_layout_new ();
4798       clutter_actor_set_layout_manager (self, default_layout);
4799     }
4800
4801   return retval;
4802 }
4803
4804 static void
4805 clutter_actor_class_init (ClutterActorClass *klass)
4806 {
4807   GObjectClass *object_class = G_OBJECT_CLASS (klass);
4808
4809   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
4810   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
4811   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
4812
4813   object_class->constructor = clutter_actor_constructor;
4814   object_class->set_property = clutter_actor_set_property;
4815   object_class->get_property = clutter_actor_get_property;
4816   object_class->dispose = clutter_actor_dispose;
4817   object_class->finalize = clutter_actor_finalize;
4818
4819   klass->show = clutter_actor_real_show;
4820   klass->show_all = clutter_actor_show;
4821   klass->hide = clutter_actor_real_hide;
4822   klass->hide_all = clutter_actor_hide;
4823   klass->map = clutter_actor_real_map;
4824   klass->unmap = clutter_actor_real_unmap;
4825   klass->unrealize = clutter_actor_real_unrealize;
4826   klass->pick = clutter_actor_real_pick;
4827   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
4828   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
4829   klass->allocate = clutter_actor_real_allocate;
4830   klass->queue_redraw = clutter_actor_real_queue_redraw;
4831   klass->queue_relayout = clutter_actor_real_queue_relayout;
4832   klass->apply_transform = clutter_actor_real_apply_transform;
4833   klass->get_accessible = clutter_actor_real_get_accessible;
4834   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
4835   klass->has_overlaps = clutter_actor_real_has_overlaps;
4836   klass->paint = clutter_actor_real_paint;
4837   klass->destroy = clutter_actor_real_destroy;
4838
4839   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
4840
4841   /**
4842    * ClutterActor:x:
4843    *
4844    * X coordinate of the actor in pixels. If written, forces a fixed
4845    * position for the actor. If read, returns the fixed position if any,
4846    * otherwise the allocation if available, otherwise 0.
4847    */
4848   obj_props[PROP_X] =
4849     g_param_spec_float ("x",
4850                         P_("X coordinate"),
4851                         P_("X coordinate of the actor"),
4852                         -G_MAXFLOAT, G_MAXFLOAT,
4853                         0.0,
4854                         CLUTTER_PARAM_READWRITE);
4855
4856   /**
4857    * ClutterActor:y:
4858    *
4859    * Y coordinate of the actor in pixels. If written, forces a fixed
4860    * position for the actor.  If read, returns the fixed position if
4861    * any, otherwise the allocation if available, otherwise 0.
4862    */
4863   obj_props[PROP_Y] =
4864     g_param_spec_float ("y",
4865                         P_("Y coordinate"),
4866                         P_("Y coordinate of the actor"),
4867                         -G_MAXFLOAT, G_MAXFLOAT,
4868                         0.0,
4869                         CLUTTER_PARAM_READWRITE);
4870
4871   /**
4872    * ClutterActor:width:
4873    *
4874    * Width of the actor (in pixels). If written, forces the minimum and
4875    * natural size request of the actor to the given width. If read, returns
4876    * the allocated width if available, otherwise the width request.
4877    */
4878   obj_props[PROP_WIDTH] =
4879     g_param_spec_float ("width",
4880                         P_("Width"),
4881                         P_("Width of the actor"),
4882                         0.0, G_MAXFLOAT,
4883                         0.0,
4884                         CLUTTER_PARAM_READWRITE);
4885
4886   /**
4887    * ClutterActor:height:
4888    *
4889    * Height of the actor (in pixels).  If written, forces the minimum and
4890    * natural size request of the actor to the given height. If read, returns
4891    * the allocated height if available, otherwise the height request.
4892    */
4893   obj_props[PROP_HEIGHT] =
4894     g_param_spec_float ("height",
4895                         P_("Height"),
4896                         P_("Height of the actor"),
4897                         0.0, G_MAXFLOAT,
4898                         0.0,
4899                         CLUTTER_PARAM_READWRITE);
4900
4901   /**
4902    * ClutterActor:fixed-x:
4903    *
4904    * The fixed X position of the actor in pixels.
4905    *
4906    * Writing this property sets #ClutterActor:fixed-position-set
4907    * property as well, as a side effect
4908    *
4909    * Since: 0.8
4910    */
4911   obj_props[PROP_FIXED_X] =
4912     g_param_spec_float ("fixed-x",
4913                         P_("Fixed X"),
4914                         P_("Forced X position of the actor"),
4915                         -G_MAXFLOAT, G_MAXFLOAT,
4916                         0.0,
4917                         CLUTTER_PARAM_READWRITE);
4918
4919   /**
4920    * ClutterActor:fixed-y:
4921    *
4922    * The fixed Y position of the actor in pixels.
4923    *
4924    * Writing this property sets the #ClutterActor:fixed-position-set
4925    * property as well, as a side effect
4926    *
4927    * Since: 0.8
4928    */
4929   obj_props[PROP_FIXED_Y] =
4930     g_param_spec_float ("fixed-y",
4931                         P_("Fixed Y"),
4932                         P_("Forced Y position of the actor"),
4933                         -G_MAXFLOAT, G_MAXFLOAT,
4934                         0,
4935                         CLUTTER_PARAM_READWRITE);
4936
4937   /**
4938    * ClutterActor:fixed-position-set:
4939    *
4940    * This flag controls whether the #ClutterActor:fixed-x and
4941    * #ClutterActor:fixed-y properties are used
4942    *
4943    * Since: 0.8
4944    */
4945   obj_props[PROP_FIXED_POSITION_SET] =
4946     g_param_spec_boolean ("fixed-position-set",
4947                           P_("Fixed position set"),
4948                           P_("Whether to use fixed positioning for the actor"),
4949                           FALSE,
4950                           CLUTTER_PARAM_READWRITE);
4951
4952   /**
4953    * ClutterActor:min-width:
4954    *
4955    * A forced minimum width request for the actor, in pixels
4956    *
4957    * Writing this property sets the #ClutterActor:min-width-set property
4958    * as well, as a side effect.
4959    *
4960    *This property overrides the usual width request of the actor.
4961    *
4962    * Since: 0.8
4963    */
4964   obj_props[PROP_MIN_WIDTH] =
4965     g_param_spec_float ("min-width",
4966                         P_("Min Width"),
4967                         P_("Forced minimum width request for the actor"),
4968                         0.0, G_MAXFLOAT,
4969                         0.0,
4970                         CLUTTER_PARAM_READWRITE);
4971
4972   /**
4973    * ClutterActor:min-height:
4974    *
4975    * A forced minimum height request for the actor, in pixels
4976    *
4977    * Writing this property sets the #ClutterActor:min-height-set property
4978    * as well, as a side effect. This property overrides the usual height
4979    * request of the actor.
4980    *
4981    * Since: 0.8
4982    */
4983   obj_props[PROP_MIN_HEIGHT] =
4984     g_param_spec_float ("min-height",
4985                         P_("Min Height"),
4986                         P_("Forced minimum height request for the actor"),
4987                         0.0, G_MAXFLOAT,
4988                         0.0,
4989                         CLUTTER_PARAM_READWRITE);
4990
4991   /**
4992    * ClutterActor:natural-width:
4993    *
4994    * A forced natural width request for the actor, in pixels
4995    *
4996    * Writing this property sets the #ClutterActor:natural-width-set
4997    * property as well, as a side effect. This property overrides the
4998    * usual width request of the actor
4999    *
5000    * Since: 0.8
5001    */
5002   obj_props[PROP_NATURAL_WIDTH] =
5003     g_param_spec_float ("natural-width",
5004                         P_("Natural Width"),
5005                         P_("Forced natural width request for the actor"),
5006                         0.0, G_MAXFLOAT,
5007                         0.0,
5008                         CLUTTER_PARAM_READWRITE);
5009
5010   /**
5011    * ClutterActor:natural-height:
5012    *
5013    * A forced natural height request for the actor, in pixels
5014    *
5015    * Writing this property sets the #ClutterActor:natural-height-set
5016    * property as well, as a side effect. This property overrides the
5017    * usual height request of the actor
5018    *
5019    * Since: 0.8
5020    */
5021   obj_props[PROP_NATURAL_HEIGHT] =
5022     g_param_spec_float ("natural-height",
5023                         P_("Natural Height"),
5024                         P_("Forced natural height request for the actor"),
5025                         0.0, G_MAXFLOAT,
5026                         0.0,
5027                         CLUTTER_PARAM_READWRITE);
5028
5029   /**
5030    * ClutterActor:min-width-set:
5031    *
5032    * This flag controls whether the #ClutterActor:min-width property
5033    * is used
5034    *
5035    * Since: 0.8
5036    */
5037   obj_props[PROP_MIN_WIDTH_SET] =
5038     g_param_spec_boolean ("min-width-set",
5039                           P_("Minimum width set"),
5040                           P_("Whether to use the min-width property"),
5041                           FALSE,
5042                           CLUTTER_PARAM_READWRITE);
5043
5044   /**
5045    * ClutterActor:min-height-set:
5046    *
5047    * This flag controls whether the #ClutterActor:min-height property
5048    * is used
5049    *
5050    * Since: 0.8
5051    */
5052   obj_props[PROP_MIN_HEIGHT_SET] =
5053     g_param_spec_boolean ("min-height-set",
5054                           P_("Minimum height set"),
5055                           P_("Whether to use the min-height property"),
5056                           FALSE,
5057                           CLUTTER_PARAM_READWRITE);
5058
5059   /**
5060    * ClutterActor:natural-width-set:
5061    *
5062    * This flag controls whether the #ClutterActor:natural-width property
5063    * is used
5064    *
5065    * Since: 0.8
5066    */
5067   obj_props[PROP_NATURAL_WIDTH_SET] =
5068     g_param_spec_boolean ("natural-width-set",
5069                           P_("Natural width set"),
5070                           P_("Whether to use the natural-width property"),
5071                           FALSE,
5072                           CLUTTER_PARAM_READWRITE);
5073
5074   /**
5075    * ClutterActor:natural-height-set:
5076    *
5077    * This flag controls whether the #ClutterActor:natural-height property
5078    * is used
5079    *
5080    * Since: 0.8
5081    */
5082   obj_props[PROP_NATURAL_HEIGHT_SET] =
5083     g_param_spec_boolean ("natural-height-set",
5084                           P_("Natural height set"),
5085                           P_("Whether to use the natural-height property"),
5086                           FALSE,
5087                           CLUTTER_PARAM_READWRITE);
5088
5089   /**
5090    * ClutterActor:allocation:
5091    *
5092    * The allocation for the actor, in pixels
5093    *
5094    * This is property is read-only, but you might monitor it to know when an
5095    * actor moves or resizes
5096    *
5097    * Since: 0.8
5098    */
5099   obj_props[PROP_ALLOCATION] =
5100     g_param_spec_boxed ("allocation",
5101                         P_("Allocation"),
5102                         P_("The actor's allocation"),
5103                         CLUTTER_TYPE_ACTOR_BOX,
5104                         CLUTTER_PARAM_READABLE);
5105
5106   /**
5107    * ClutterActor:request-mode:
5108    *
5109    * Request mode for the #ClutterActor. The request mode determines the
5110    * type of geometry management used by the actor, either height for width
5111    * (the default) or width for height.
5112    *
5113    * For actors implementing height for width, the parent container should get
5114    * the preferred width first, and then the preferred height for that width.
5115    *
5116    * For actors implementing width for height, the parent container should get
5117    * the preferred height first, and then the preferred width for that height.
5118    *
5119    * For instance:
5120    *
5121    * |[
5122    *   ClutterRequestMode mode;
5123    *   gfloat natural_width, min_width;
5124    *   gfloat natural_height, min_height;
5125    *
5126    *   mode = clutter_actor_get_request_mode (child);
5127    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5128    *     {
5129    *       clutter_actor_get_preferred_width (child, -1,
5130    *                                          &amp;min_width,
5131    *                                          &amp;natural_width);
5132    *       clutter_actor_get_preferred_height (child, natural_width,
5133    *                                           &amp;min_height,
5134    *                                           &amp;natural_height);
5135    *     }
5136    *   else
5137    *     {
5138    *       clutter_actor_get_preferred_height (child, -1,
5139    *                                           &amp;min_height,
5140    *                                           &amp;natural_height);
5141    *       clutter_actor_get_preferred_width (child, natural_height,
5142    *                                          &amp;min_width,
5143    *                                          &amp;natural_width);
5144    *     }
5145    * ]|
5146    *
5147    * will retrieve the minimum and natural width and height depending on the
5148    * preferred request mode of the #ClutterActor "child".
5149    *
5150    * The clutter_actor_get_preferred_size() function will implement this
5151    * check for you.
5152    *
5153    * Since: 0.8
5154    */
5155   obj_props[PROP_REQUEST_MODE] =
5156     g_param_spec_enum ("request-mode",
5157                        P_("Request Mode"),
5158                        P_("The actor's request mode"),
5159                        CLUTTER_TYPE_REQUEST_MODE,
5160                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5161                        CLUTTER_PARAM_READWRITE);
5162
5163   /**
5164    * ClutterActor:depth:
5165    *
5166    * The position of the actor on the Z axis
5167    *
5168    * Since: 0.6
5169    */
5170   obj_props[PROP_DEPTH] =
5171     g_param_spec_float ("depth",
5172                         P_("Depth"),
5173                         P_("Position on the Z axis"),
5174                         -G_MAXFLOAT, G_MAXFLOAT,
5175                         0.0,
5176                         CLUTTER_PARAM_READWRITE);
5177
5178   /**
5179    * ClutterActor:opacity:
5180    *
5181    * Opacity of an actor, between 0 (fully transparent) and
5182    * 255 (fully opaque)
5183    */
5184   obj_props[PROP_OPACITY] =
5185     g_param_spec_uint ("opacity",
5186                        P_("Opacity"),
5187                        P_("Opacity of an actor"),
5188                        0, 255,
5189                        255,
5190                        CLUTTER_PARAM_READWRITE);
5191
5192   /**
5193    * ClutterActor:offscreen-redirect:
5194    *
5195    * Determines the conditions in which the actor will be redirected
5196    * to an offscreen framebuffer while being painted. For example this
5197    * can be used to cache an actor in a framebuffer or for improved
5198    * handling of transparent actors. See
5199    * clutter_actor_set_offscreen_redirect() for details.
5200    *
5201    * Since: 1.8
5202    */
5203   obj_props[PROP_OFFSCREEN_REDIRECT] =
5204     g_param_spec_flags ("offscreen-redirect",
5205                         P_("Offscreen redirect"),
5206                         P_("Flags controlling when to flatten the actor into a single image"),
5207                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5208                         0,
5209                         CLUTTER_PARAM_READWRITE);
5210
5211   /**
5212    * ClutterActor:visible:
5213    *
5214    * Whether the actor is set to be visible or not
5215    *
5216    * See also #ClutterActor:mapped
5217    */
5218   obj_props[PROP_VISIBLE] =
5219     g_param_spec_boolean ("visible",
5220                           P_("Visible"),
5221                           P_("Whether the actor is visible or not"),
5222                           FALSE,
5223                           CLUTTER_PARAM_READWRITE);
5224
5225   /**
5226    * ClutterActor:mapped:
5227    *
5228    * Whether the actor is mapped (will be painted when the stage
5229    * to which it belongs is mapped)
5230    *
5231    * Since: 1.0
5232    */
5233   obj_props[PROP_MAPPED] =
5234     g_param_spec_boolean ("mapped",
5235                           P_("Mapped"),
5236                           P_("Whether the actor will be painted"),
5237                           FALSE,
5238                           CLUTTER_PARAM_READABLE);
5239
5240   /**
5241    * ClutterActor:realized:
5242    *
5243    * Whether the actor has been realized
5244    *
5245    * Since: 1.0
5246    */
5247   obj_props[PROP_REALIZED] =
5248     g_param_spec_boolean ("realized",
5249                           P_("Realized"),
5250                           P_("Whether the actor has been realized"),
5251                           FALSE,
5252                           CLUTTER_PARAM_READABLE);
5253
5254   /**
5255    * ClutterActor:reactive:
5256    *
5257    * Whether the actor is reactive to events or not
5258    *
5259    * Only reactive actors will emit event-related signals
5260    *
5261    * Since: 0.6
5262    */
5263   obj_props[PROP_REACTIVE] =
5264     g_param_spec_boolean ("reactive",
5265                           P_("Reactive"),
5266                           P_("Whether the actor is reactive to events"),
5267                           FALSE,
5268                           CLUTTER_PARAM_READWRITE);
5269
5270   /**
5271    * ClutterActor:has-clip:
5272    *
5273    * Whether the actor has the #ClutterActor:clip property set or not
5274    */
5275   obj_props[PROP_HAS_CLIP] =
5276     g_param_spec_boolean ("has-clip",
5277                           P_("Has Clip"),
5278                           P_("Whether the actor has a clip set"),
5279                           FALSE,
5280                           CLUTTER_PARAM_READABLE);
5281
5282   /**
5283    * ClutterActor:clip:
5284    *
5285    * The clip region for the actor, in actor-relative coordinates
5286    *
5287    * Every part of the actor outside the clip region will not be
5288    * painted
5289    */
5290   obj_props[PROP_CLIP] =
5291     g_param_spec_boxed ("clip",
5292                         P_("Clip"),
5293                         P_("The clip region for the actor"),
5294                         CLUTTER_TYPE_GEOMETRY,
5295                         CLUTTER_PARAM_READWRITE);
5296
5297   /**
5298    * ClutterActor:name:
5299    *
5300    * The name of the actor
5301    *
5302    * Since: 0.2
5303    */
5304   obj_props[PROP_NAME] =
5305     g_param_spec_string ("name",
5306                          P_("Name"),
5307                          P_("Name of the actor"),
5308                          NULL,
5309                          CLUTTER_PARAM_READWRITE);
5310
5311   /**
5312    * ClutterActor:scale-x:
5313    *
5314    * The horizontal scale of the actor
5315    *
5316    * Since: 0.6
5317    */
5318   obj_props[PROP_SCALE_X] =
5319     g_param_spec_double ("scale-x",
5320                          P_("Scale X"),
5321                          P_("Scale factor on the X axis"),
5322                          0.0, G_MAXDOUBLE,
5323                          1.0,
5324                          CLUTTER_PARAM_READWRITE);
5325
5326   /**
5327    * ClutterActor:scale-y:
5328    *
5329    * The vertical scale of the actor
5330    *
5331    * Since: 0.6
5332    */
5333   obj_props[PROP_SCALE_Y] =
5334     g_param_spec_double ("scale-y",
5335                          P_("Scale Y"),
5336                          P_("Scale factor on the Y axis"),
5337                          0.0, G_MAXDOUBLE,
5338                          1.0,
5339                          CLUTTER_PARAM_READWRITE);
5340
5341   /**
5342    * ClutterActor:scale-center-x:
5343    *
5344    * The horizontal center point for scaling
5345    *
5346    * Since: 1.0
5347    */
5348   obj_props[PROP_SCALE_CENTER_X] =
5349     g_param_spec_float ("scale-center-x",
5350                         P_("Scale Center X"),
5351                         P_("Horizontal scale center"),
5352                         -G_MAXFLOAT, G_MAXFLOAT,
5353                         0.0,
5354                         CLUTTER_PARAM_READWRITE);
5355
5356   /**
5357    * ClutterActor:scale-center-y:
5358    *
5359    * The vertical center point for scaling
5360    *
5361    * Since: 1.0
5362    */
5363   obj_props[PROP_SCALE_CENTER_Y] =
5364     g_param_spec_float ("scale-center-y",
5365                         P_("Scale Center Y"),
5366                         P_("Vertical scale center"),
5367                         -G_MAXFLOAT, G_MAXFLOAT,
5368                         0.0,
5369                         CLUTTER_PARAM_READWRITE);
5370
5371   /**
5372    * ClutterActor:scale-gravity:
5373    *
5374    * The center point for scaling expressed as a #ClutterGravity
5375    *
5376    * Since: 1.0
5377    */
5378   obj_props[PROP_SCALE_GRAVITY] =
5379     g_param_spec_enum ("scale-gravity",
5380                        P_("Scale Gravity"),
5381                        P_("The center of scaling"),
5382                        CLUTTER_TYPE_GRAVITY,
5383                        CLUTTER_GRAVITY_NONE,
5384                        CLUTTER_PARAM_READWRITE);
5385
5386   /**
5387    * ClutterActor:rotation-angle-x:
5388    *
5389    * The rotation angle on the X axis
5390    *
5391    * Since: 0.6
5392    */
5393   obj_props[PROP_ROTATION_ANGLE_X] =
5394     g_param_spec_double ("rotation-angle-x",
5395                          P_("Rotation Angle X"),
5396                          P_("The rotation angle on the X axis"),
5397                          -G_MAXDOUBLE, G_MAXDOUBLE,
5398                          0.0,
5399                          CLUTTER_PARAM_READWRITE);
5400
5401   /**
5402    * ClutterActor:rotation-angle-y:
5403    *
5404    * The rotation angle on the Y axis
5405    *
5406    * Since: 0.6
5407    */
5408   obj_props[PROP_ROTATION_ANGLE_Y] =
5409     g_param_spec_double ("rotation-angle-y",
5410                          P_("Rotation Angle Y"),
5411                          P_("The rotation angle on the Y axis"),
5412                          -G_MAXDOUBLE, G_MAXDOUBLE,
5413                          0.0,
5414                          CLUTTER_PARAM_READWRITE);
5415
5416   /**
5417    * ClutterActor:rotation-angle-z:
5418    *
5419    * The rotation angle on the Z axis
5420    *
5421    * Since: 0.6
5422    */
5423   obj_props[PROP_ROTATION_ANGLE_Z] =
5424     g_param_spec_double ("rotation-angle-z",
5425                          P_("Rotation Angle Z"),
5426                          P_("The rotation angle on the Z axis"),
5427                          -G_MAXDOUBLE, G_MAXDOUBLE,
5428                          0.0,
5429                          CLUTTER_PARAM_READWRITE);
5430
5431   /**
5432    * ClutterActor:rotation-center-x:
5433    *
5434    * The rotation center on the X axis.
5435    *
5436    * Since: 0.6
5437    */
5438   obj_props[PROP_ROTATION_CENTER_X] =
5439     g_param_spec_boxed ("rotation-center-x",
5440                         P_("Rotation Center X"),
5441                         P_("The rotation center on the X axis"),
5442                         CLUTTER_TYPE_VERTEX,
5443                         CLUTTER_PARAM_READWRITE);
5444
5445   /**
5446    * ClutterActor:rotation-center-y:
5447    *
5448    * The rotation center on the Y axis.
5449    *
5450    * Since: 0.6
5451    */
5452   obj_props[PROP_ROTATION_CENTER_Y] =
5453     g_param_spec_boxed ("rotation-center-y",
5454                         P_("Rotation Center Y"),
5455                         P_("The rotation center on the Y axis"),
5456                         CLUTTER_TYPE_VERTEX,
5457                         CLUTTER_PARAM_READWRITE);
5458
5459   /**
5460    * ClutterActor:rotation-center-z:
5461    *
5462    * The rotation center on the Z axis.
5463    *
5464    * Since: 0.6
5465    */
5466   obj_props[PROP_ROTATION_CENTER_Z] =
5467     g_param_spec_boxed ("rotation-center-z",
5468                         P_("Rotation Center Z"),
5469                         P_("The rotation center on the Z axis"),
5470                         CLUTTER_TYPE_VERTEX,
5471                         CLUTTER_PARAM_READWRITE);
5472
5473   /**
5474    * ClutterActor:rotation-center-z-gravity:
5475    *
5476    * The rotation center on the Z axis expressed as a #ClutterGravity.
5477    *
5478    * Since: 1.0
5479    */
5480   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5481     g_param_spec_enum ("rotation-center-z-gravity",
5482                        P_("Rotation Center Z Gravity"),
5483                        P_("Center point for rotation around the Z axis"),
5484                        CLUTTER_TYPE_GRAVITY,
5485                        CLUTTER_GRAVITY_NONE,
5486                        CLUTTER_PARAM_READWRITE);
5487
5488   /**
5489    * ClutterActor:anchor-x:
5490    *
5491    * The X coordinate of an actor's anchor point, relative to
5492    * the actor coordinate space, in pixels
5493    *
5494    * Since: 0.8
5495    */
5496   obj_props[PROP_ANCHOR_X] =
5497     g_param_spec_float ("anchor-x",
5498                         P_("Anchor X"),
5499                         P_("X coordinate of the anchor point"),
5500                         -G_MAXFLOAT, G_MAXFLOAT,
5501                         0,
5502                         CLUTTER_PARAM_READWRITE);
5503
5504   /**
5505    * ClutterActor:anchor-y:
5506    *
5507    * The Y coordinate of an actor's anchor point, relative to
5508    * the actor coordinate space, in pixels
5509    *
5510    * Since: 0.8
5511    */
5512   obj_props[PROP_ANCHOR_Y] =
5513     g_param_spec_float ("anchor-y",
5514                         P_("Anchor Y"),
5515                         P_("Y coordinate of the anchor point"),
5516                         -G_MAXFLOAT, G_MAXFLOAT,
5517                         0,
5518                         CLUTTER_PARAM_READWRITE);
5519
5520   /**
5521    * ClutterActor:anchor-gravity:
5522    *
5523    * The anchor point expressed as a #ClutterGravity
5524    *
5525    * Since: 1.0
5526    */
5527   obj_props[PROP_ANCHOR_GRAVITY] =
5528     g_param_spec_enum ("anchor-gravity",
5529                        P_("Anchor Gravity"),
5530                        P_("The anchor point as a ClutterGravity"),
5531                        CLUTTER_TYPE_GRAVITY,
5532                        CLUTTER_GRAVITY_NONE,
5533                        CLUTTER_PARAM_READWRITE);
5534
5535   /**
5536    * ClutterActor:show-on-set-parent:
5537    *
5538    * If %TRUE, the actor is automatically shown when parented.
5539    *
5540    * Calling clutter_actor_hide() on an actor which has not been
5541    * parented will set this property to %FALSE as a side effect.
5542    *
5543    * Since: 0.8
5544    */
5545   obj_props[PROP_SHOW_ON_SET_PARENT] =
5546     g_param_spec_boolean ("show-on-set-parent",
5547                           P_("Show on set parent"),
5548                           P_("Whether the actor is shown when parented"),
5549                           TRUE,
5550                           CLUTTER_PARAM_READWRITE);
5551
5552   /**
5553    * ClutterActor:clip-to-allocation:
5554    *
5555    * Whether the clip region should track the allocated area
5556    * of the actor.
5557    *
5558    * This property is ignored if a clip area has been explicitly
5559    * set using clutter_actor_set_clip().
5560    *
5561    * Since: 1.0
5562    */
5563   obj_props[PROP_CLIP_TO_ALLOCATION] =
5564     g_param_spec_boolean ("clip-to-allocation",
5565                           P_("Clip to Allocation"),
5566                           P_("Sets the clip region to track the actor's allocation"),
5567                           FALSE,
5568                           CLUTTER_PARAM_READWRITE);
5569
5570   /**
5571    * ClutterActor:text-direction:
5572    *
5573    * The direction of the text inside a #ClutterActor.
5574    *
5575    * Since: 1.0
5576    */
5577   obj_props[PROP_TEXT_DIRECTION] =
5578     g_param_spec_enum ("text-direction",
5579                        P_("Text Direction"),
5580                        P_("Direction of the text"),
5581                        CLUTTER_TYPE_TEXT_DIRECTION,
5582                        CLUTTER_TEXT_DIRECTION_LTR,
5583                        CLUTTER_PARAM_READWRITE);
5584
5585   /**
5586    * ClutterActor:has-pointer:
5587    *
5588    * Whether the actor contains the pointer of a #ClutterInputDevice
5589    * or not.
5590    *
5591    * Since: 1.2
5592    */
5593   obj_props[PROP_HAS_POINTER] =
5594     g_param_spec_boolean ("has-pointer",
5595                           P_("Has Pointer"),
5596                           P_("Whether the actor contains the pointer of an input device"),
5597                           FALSE,
5598                           CLUTTER_PARAM_READABLE);
5599
5600   /**
5601    * ClutterActor:actions:
5602    *
5603    * Adds a #ClutterAction to the actor
5604    *
5605    * Since: 1.4
5606    */
5607   obj_props[PROP_ACTIONS] =
5608     g_param_spec_object ("actions",
5609                          P_("Actions"),
5610                          P_("Adds an action to the actor"),
5611                          CLUTTER_TYPE_ACTION,
5612                          CLUTTER_PARAM_WRITABLE);
5613
5614   /**
5615    * ClutterActor:constraints:
5616    *
5617    * Adds a #ClutterConstraint to the actor
5618    *
5619    * Since: 1.4
5620    */
5621   obj_props[PROP_CONSTRAINTS] =
5622     g_param_spec_object ("constraints",
5623                          P_("Constraints"),
5624                          P_("Adds a constraint to the actor"),
5625                          CLUTTER_TYPE_CONSTRAINT,
5626                          CLUTTER_PARAM_WRITABLE);
5627
5628   /**
5629    * ClutterActor:effect:
5630    *
5631    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5632    *
5633    * Since: 1.4
5634    */
5635   obj_props[PROP_EFFECT] =
5636     g_param_spec_object ("effect",
5637                          P_("Effect"),
5638                          P_("Add an effect to be applied on the actor"),
5639                          CLUTTER_TYPE_EFFECT,
5640                          CLUTTER_PARAM_WRITABLE);
5641
5642   /**
5643    * ClutterActor:layout-manager:
5644    *
5645    * A delegate object for controlling the layout of the children of
5646    * an actor.
5647    *
5648    * Since: 1.10
5649    */
5650   obj_props[PROP_LAYOUT_MANAGER] =
5651     g_param_spec_object ("layout-manager",
5652                          P_("Layout Manager"),
5653                          P_("The object controlling the layout of an actor's children"),
5654                          CLUTTER_TYPE_LAYOUT_MANAGER,
5655                          CLUTTER_PARAM_READWRITE);
5656
5657
5658   /**
5659    * ClutterActor:x-align:
5660    *
5661    * The alignment of an actor on the X axis, if the actor has been given
5662    * extra space for its allocation.
5663    *
5664    * Since: 1.10
5665    */
5666   obj_props[PROP_X_ALIGN] =
5667     g_param_spec_enum ("x-align",
5668                        P_("X Alignment"),
5669                        P_("The alignment of the actor on the X axis within its allocation"),
5670                        CLUTTER_TYPE_ACTOR_ALIGN,
5671                        CLUTTER_ACTOR_ALIGN_FILL,
5672                        CLUTTER_PARAM_READWRITE);
5673
5674   /**
5675    * ClutterActor:y-align:
5676    *
5677    * The alignment of an actor on the Y axis, if the actor has been given
5678    * extra space for its allocation.
5679    *
5680    * Since: 1.10
5681    */
5682   obj_props[PROP_Y_ALIGN] =
5683     g_param_spec_enum ("y-align",
5684                        P_("Y Alignment"),
5685                        P_("The alignment of the actor on the Y axis within its allocation"),
5686                        CLUTTER_TYPE_ACTOR_ALIGN,
5687                        CLUTTER_ACTOR_ALIGN_FILL,
5688                        CLUTTER_PARAM_READWRITE);
5689
5690   /**
5691    * ClutterActor:margin-top:
5692    *
5693    * The margin (in pixels) from the top of the actor.
5694    *
5695    * This property adds a margin to the actor's preferred size; the margin
5696    * will be automatically taken into account when allocating the actor.
5697    *
5698    * Since: 1.10
5699    */
5700   obj_props[PROP_MARGIN_TOP] =
5701     g_param_spec_float ("margin-top",
5702                         P_("Margin Top"),
5703                         P_("Extra space at the top"),
5704                         0.0, G_MAXFLOAT,
5705                         0.0,
5706                         CLUTTER_PARAM_READWRITE);
5707
5708   /**
5709    * ClutterActor:margin-bottom:
5710    *
5711    * The margin (in pixels) from the bottom of the actor.
5712    *
5713    * This property adds a margin to the actor's preferred size; the margin
5714    * will be automatically taken into account when allocating the actor.
5715    *
5716    * Since: 1.10
5717    */
5718   obj_props[PROP_MARGIN_BOTTOM] =
5719     g_param_spec_float ("margin-bottom",
5720                         P_("Margin Bottom"),
5721                         P_("Extra space at the bottom"),
5722                         0.0, G_MAXFLOAT,
5723                         0.0,
5724                         CLUTTER_PARAM_READWRITE);
5725
5726   /**
5727    * ClutterActor:margin-left:
5728    *
5729    * The margin (in pixels) from the left of the actor.
5730    *
5731    * This property adds a margin to the actor's preferred size; the margin
5732    * will be automatically taken into account when allocating the actor.
5733    *
5734    * Since: 1.10
5735    */
5736   obj_props[PROP_MARGIN_LEFT] =
5737     g_param_spec_float ("margin-left",
5738                         P_("Margin Left"),
5739                         P_("Extra space at the left"),
5740                         0.0, G_MAXFLOAT,
5741                         0.0,
5742                         CLUTTER_PARAM_READWRITE);
5743
5744   /**
5745    * ClutterActor:margin-right:
5746    *
5747    * The margin (in pixels) from the right of the actor.
5748    *
5749    * This property adds a margin to the actor's preferred size; the margin
5750    * will be automatically taken into account when allocating the actor.
5751    *
5752    * Since: 1.10
5753    */
5754   obj_props[PROP_MARGIN_RIGHT] =
5755     g_param_spec_float ("margin-right",
5756                         P_("Margin Right"),
5757                         P_("Extra space at the right"),
5758                         0.0, G_MAXFLOAT,
5759                         0.0,
5760                         CLUTTER_PARAM_READWRITE);
5761
5762   /**
5763    * ClutterActor:background-color-set:
5764    *
5765    * Whether the #ClutterActor:background-color property has been set.
5766    *
5767    * Since: 1.10
5768    */
5769   obj_props[PROP_BACKGROUND_COLOR_SET] =
5770     g_param_spec_boolean ("background-color-set",
5771                           P_("Background Color Set"),
5772                           P_("Whether the background color is set"),
5773                           FALSE,
5774                           CLUTTER_PARAM_READABLE);
5775
5776   /**
5777    * ClutterActor:background-color:
5778    *
5779    * Paints a solid fill of the actor's allocation using the specified
5780    * color.
5781    *
5782    * Since: 1.10
5783    */
5784   obj_props[PROP_BACKGROUND_COLOR] =
5785     clutter_param_spec_color ("background-color",
5786                               P_("Background color"),
5787                               P_("The actor's background color"),
5788                               CLUTTER_COLOR_Transparent,
5789                               CLUTTER_PARAM_READWRITE);
5790
5791   /**
5792    * ClutterActor:first-child:
5793    *
5794    * The actor's first child.
5795    *
5796    * Since: 1.10
5797    */
5798   obj_props[PROP_FIRST_CHILD] =
5799     g_param_spec_object ("first-child",
5800                          P_("First Child"),
5801                          P_("The actor's first child"),
5802                          CLUTTER_TYPE_ACTOR,
5803                          CLUTTER_PARAM_READABLE);
5804
5805   /**
5806    * ClutterActor:last-child:
5807    *
5808    * The actor's last child.
5809    *
5810    * Since: 1.10
5811    */
5812   obj_props[PROP_LAST_CHILD] =
5813     g_param_spec_object ("last-child",
5814                          P_("Last Child"),
5815                          P_("The actor's last child"),
5816                          CLUTTER_TYPE_ACTOR,
5817                          CLUTTER_PARAM_READABLE);
5818
5819   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
5820
5821   /**
5822    * ClutterActor::destroy:
5823    * @actor: the #ClutterActor which emitted the signal
5824    *
5825    * The ::destroy signal notifies that all references held on the
5826    * actor which emitted it should be released.
5827    *
5828    * The ::destroy signal should be used by all holders of a reference
5829    * on @actor.
5830    *
5831    * This signal might result in the finalization of the #ClutterActor
5832    * if all references are released.
5833    *
5834    * Composite actors and actors implementing the #ClutterContainer
5835    * interface should override the default implementation of the
5836    * class handler of this signal and call clutter_actor_destroy() on
5837    * their children. When overriding the default class handler, it is
5838    * required to chain up to the parent's implementation.
5839    *
5840    * Since: 0.2
5841    */
5842   actor_signals[DESTROY] =
5843     g_signal_new (I_("destroy"),
5844                   G_TYPE_FROM_CLASS (object_class),
5845                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
5846                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
5847                   NULL, NULL,
5848                   _clutter_marshal_VOID__VOID,
5849                   G_TYPE_NONE, 0);
5850   /**
5851    * ClutterActor::show:
5852    * @actor: the object which received the signal
5853    *
5854    * The ::show signal is emitted when an actor is visible and
5855    * rendered on the stage.
5856    *
5857    * Since: 0.2
5858    */
5859   actor_signals[SHOW] =
5860     g_signal_new (I_("show"),
5861                   G_TYPE_FROM_CLASS (object_class),
5862                   G_SIGNAL_RUN_FIRST,
5863                   G_STRUCT_OFFSET (ClutterActorClass, show),
5864                   NULL, NULL,
5865                   _clutter_marshal_VOID__VOID,
5866                   G_TYPE_NONE, 0);
5867   /**
5868    * ClutterActor::hide:
5869    * @actor: the object which received the signal
5870    *
5871    * The ::hide signal is emitted when an actor is no longer rendered
5872    * on the stage.
5873    *
5874    * Since: 0.2
5875    */
5876   actor_signals[HIDE] =
5877     g_signal_new (I_("hide"),
5878                   G_TYPE_FROM_CLASS (object_class),
5879                   G_SIGNAL_RUN_FIRST,
5880                   G_STRUCT_OFFSET (ClutterActorClass, hide),
5881                   NULL, NULL,
5882                   _clutter_marshal_VOID__VOID,
5883                   G_TYPE_NONE, 0);
5884   /**
5885    * ClutterActor::parent-set:
5886    * @actor: the object which received the signal
5887    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
5888    *
5889    * This signal is emitted when the parent of the actor changes.
5890    *
5891    * Since: 0.2
5892    */
5893   actor_signals[PARENT_SET] =
5894     g_signal_new (I_("parent-set"),
5895                   G_TYPE_FROM_CLASS (object_class),
5896                   G_SIGNAL_RUN_LAST,
5897                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
5898                   NULL, NULL,
5899                   _clutter_marshal_VOID__OBJECT,
5900                   G_TYPE_NONE, 1,
5901                   CLUTTER_TYPE_ACTOR);
5902
5903   /**
5904    * ClutterActor::queue-redraw:
5905    * @actor: the actor we're bubbling the redraw request through
5906    * @origin: the actor which initiated the redraw request
5907    *
5908    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
5909    * is called on @origin.
5910    *
5911    * The default implementation for #ClutterActor chains up to the
5912    * parent actor and queues a redraw on the parent, thus "bubbling"
5913    * the redraw queue up through the actor graph. The default
5914    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
5915    * in a main loop idle handler.
5916    *
5917    * Note that the @origin actor may be the stage, or a container; it
5918    * does not have to be a leaf node in the actor graph.
5919    *
5920    * Toolkits embedding a #ClutterStage which require a redraw and
5921    * relayout cycle can stop the emission of this signal using the
5922    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
5923    * themselves, like:
5924    *
5925    * |[
5926    *   static void
5927    *   on_redraw_complete (gpointer data)
5928    *   {
5929    *     ClutterStage *stage = data;
5930    *
5931    *     /&ast; execute the Clutter drawing pipeline &ast;/
5932    *     clutter_stage_ensure_redraw (stage);
5933    *   }
5934    *
5935    *   static void
5936    *   on_stage_queue_redraw (ClutterStage *stage)
5937    *   {
5938    *     /&ast; this prevents the default handler to run &ast;/
5939    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
5940    *
5941    *     /&ast; queue a redraw with the host toolkit and call
5942    *      &ast; a function when the redraw has been completed
5943    *      &ast;/
5944    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
5945    *   }
5946    * ]|
5947    *
5948    * <note><para>This signal is emitted before the Clutter paint
5949    * pipeline is executed. If you want to know when the pipeline has
5950    * been completed you should connect to the ::paint signal on the
5951    * Stage with g_signal_connect_after().</para></note>
5952    *
5953    * Since: 1.0
5954    */
5955   actor_signals[QUEUE_REDRAW] =
5956     g_signal_new (I_("queue-redraw"),
5957                   G_TYPE_FROM_CLASS (object_class),
5958                   G_SIGNAL_RUN_LAST,
5959                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
5960                   NULL, NULL,
5961                   _clutter_marshal_VOID__OBJECT,
5962                   G_TYPE_NONE, 1,
5963                   CLUTTER_TYPE_ACTOR);
5964
5965   /**
5966    * ClutterActor::queue-relayout
5967    * @actor: the actor being queued for relayout
5968    *
5969    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
5970    * is called on an actor.
5971    *
5972    * The default implementation for #ClutterActor chains up to the
5973    * parent actor and queues a relayout on the parent, thus "bubbling"
5974    * the relayout queue up through the actor graph.
5975    *
5976    * The main purpose of this signal is to allow relayout to be propagated
5977    * properly in the procense of #ClutterClone actors. Applications will
5978    * not normally need to connect to this signal.
5979    *
5980    * Since: 1.2
5981    */
5982   actor_signals[QUEUE_RELAYOUT] =
5983     g_signal_new (I_("queue-relayout"),
5984                   G_TYPE_FROM_CLASS (object_class),
5985                   G_SIGNAL_RUN_LAST,
5986                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
5987                   NULL, NULL,
5988                   _clutter_marshal_VOID__VOID,
5989                   G_TYPE_NONE, 0);
5990
5991   /**
5992    * ClutterActor::event:
5993    * @actor: the actor which received the event
5994    * @event: a #ClutterEvent
5995    *
5996    * The ::event signal is emitted each time an event is received
5997    * by the @actor. This signal will be emitted on every actor,
5998    * following the hierarchy chain, until it reaches the top-level
5999    * container (the #ClutterStage).
6000    *
6001    * Return value: %TRUE if the event has been handled by the actor,
6002    *   or %FALSE to continue the emission.
6003    *
6004    * Since: 0.6
6005    */
6006   actor_signals[EVENT] =
6007     g_signal_new (I_("event"),
6008                   G_TYPE_FROM_CLASS (object_class),
6009                   G_SIGNAL_RUN_LAST,
6010                   G_STRUCT_OFFSET (ClutterActorClass, event),
6011                   _clutter_boolean_handled_accumulator, NULL,
6012                   _clutter_marshal_BOOLEAN__BOXED,
6013                   G_TYPE_BOOLEAN, 1,
6014                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6015   /**
6016    * ClutterActor::button-press-event:
6017    * @actor: the actor which received the event
6018    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6019    *
6020    * The ::button-press-event signal is emitted each time a mouse button
6021    * is pressed on @actor.
6022    *
6023    * Return value: %TRUE if the event has been handled by the actor,
6024    *   or %FALSE to continue the emission.
6025    *
6026    * Since: 0.6
6027    */
6028   actor_signals[BUTTON_PRESS_EVENT] =
6029     g_signal_new (I_("button-press-event"),
6030                   G_TYPE_FROM_CLASS (object_class),
6031                   G_SIGNAL_RUN_LAST,
6032                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6033                   _clutter_boolean_handled_accumulator, NULL,
6034                   _clutter_marshal_BOOLEAN__BOXED,
6035                   G_TYPE_BOOLEAN, 1,
6036                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6037   /**
6038    * ClutterActor::button-release-event:
6039    * @actor: the actor which received the event
6040    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6041    *
6042    * The ::button-release-event signal is emitted each time a mouse button
6043    * is released on @actor.
6044    *
6045    * Return value: %TRUE if the event has been handled by the actor,
6046    *   or %FALSE to continue the emission.
6047    *
6048    * Since: 0.6
6049    */
6050   actor_signals[BUTTON_RELEASE_EVENT] =
6051     g_signal_new (I_("button-release-event"),
6052                   G_TYPE_FROM_CLASS (object_class),
6053                   G_SIGNAL_RUN_LAST,
6054                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6055                   _clutter_boolean_handled_accumulator, NULL,
6056                   _clutter_marshal_BOOLEAN__BOXED,
6057                   G_TYPE_BOOLEAN, 1,
6058                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6059   /**
6060    * ClutterActor::scroll-event:
6061    * @actor: the actor which received the event
6062    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6063    *
6064    * The ::scroll-event signal is emitted each time the mouse is
6065    * scrolled on @actor
6066    *
6067    * Return value: %TRUE if the event has been handled by the actor,
6068    *   or %FALSE to continue the emission.
6069    *
6070    * Since: 0.6
6071    */
6072   actor_signals[SCROLL_EVENT] =
6073     g_signal_new (I_("scroll-event"),
6074                   G_TYPE_FROM_CLASS (object_class),
6075                   G_SIGNAL_RUN_LAST,
6076                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6077                   _clutter_boolean_handled_accumulator, NULL,
6078                   _clutter_marshal_BOOLEAN__BOXED,
6079                   G_TYPE_BOOLEAN, 1,
6080                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6081   /**
6082    * ClutterActor::key-press-event:
6083    * @actor: the actor which received the event
6084    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6085    *
6086    * The ::key-press-event signal is emitted each time a keyboard button
6087    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6088    *
6089    * Return value: %TRUE if the event has been handled by the actor,
6090    *   or %FALSE to continue the emission.
6091    *
6092    * Since: 0.6
6093    */
6094   actor_signals[KEY_PRESS_EVENT] =
6095     g_signal_new (I_("key-press-event"),
6096                   G_TYPE_FROM_CLASS (object_class),
6097                   G_SIGNAL_RUN_LAST,
6098                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6099                   _clutter_boolean_handled_accumulator, NULL,
6100                   _clutter_marshal_BOOLEAN__BOXED,
6101                   G_TYPE_BOOLEAN, 1,
6102                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6103   /**
6104    * ClutterActor::key-release-event:
6105    * @actor: the actor which received the event
6106    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6107    *
6108    * The ::key-release-event signal is emitted each time a keyboard button
6109    * is released while @actor has key focus (see
6110    * clutter_stage_set_key_focus()).
6111    *
6112    * Return value: %TRUE if the event has been handled by the actor,
6113    *   or %FALSE to continue the emission.
6114    *
6115    * Since: 0.6
6116    */
6117   actor_signals[KEY_RELEASE_EVENT] =
6118     g_signal_new (I_("key-release-event"),
6119                   G_TYPE_FROM_CLASS (object_class),
6120                   G_SIGNAL_RUN_LAST,
6121                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6122                   _clutter_boolean_handled_accumulator, NULL,
6123                   _clutter_marshal_BOOLEAN__BOXED,
6124                   G_TYPE_BOOLEAN, 1,
6125                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6126   /**
6127    * ClutterActor::motion-event:
6128    * @actor: the actor which received the event
6129    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6130    *
6131    * The ::motion-event signal is emitted each time the mouse pointer is
6132    * moved over @actor.
6133    *
6134    * Return value: %TRUE if the event has been handled by the actor,
6135    *   or %FALSE to continue the emission.
6136    *
6137    * Since: 0.6
6138    */
6139   actor_signals[MOTION_EVENT] =
6140     g_signal_new (I_("motion-event"),
6141                   G_TYPE_FROM_CLASS (object_class),
6142                   G_SIGNAL_RUN_LAST,
6143                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6144                   _clutter_boolean_handled_accumulator, NULL,
6145                   _clutter_marshal_BOOLEAN__BOXED,
6146                   G_TYPE_BOOLEAN, 1,
6147                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6148
6149   /**
6150    * ClutterActor::key-focus-in:
6151    * @actor: the actor which now has key focus
6152    *
6153    * The ::key-focus-in signal is emitted when @actor receives key focus.
6154    *
6155    * Since: 0.6
6156    */
6157   actor_signals[KEY_FOCUS_IN] =
6158     g_signal_new (I_("key-focus-in"),
6159                   G_TYPE_FROM_CLASS (object_class),
6160                   G_SIGNAL_RUN_LAST,
6161                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6162                   NULL, NULL,
6163                   _clutter_marshal_VOID__VOID,
6164                   G_TYPE_NONE, 0);
6165
6166   /**
6167    * ClutterActor::key-focus-out:
6168    * @actor: the actor which now has key focus
6169    *
6170    * The ::key-focus-out signal is emitted when @actor loses key focus.
6171    *
6172    * Since: 0.6
6173    */
6174   actor_signals[KEY_FOCUS_OUT] =
6175     g_signal_new (I_("key-focus-out"),
6176                   G_TYPE_FROM_CLASS (object_class),
6177                   G_SIGNAL_RUN_LAST,
6178                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6179                   NULL, NULL,
6180                   _clutter_marshal_VOID__VOID,
6181                   G_TYPE_NONE, 0);
6182
6183   /**
6184    * ClutterActor::enter-event:
6185    * @actor: the actor which the pointer has entered.
6186    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6187    *
6188    * The ::enter-event signal is emitted when the pointer enters the @actor
6189    *
6190    * Return value: %TRUE if the event has been handled by the actor,
6191    *   or %FALSE to continue the emission.
6192    *
6193    * Since: 0.6
6194    */
6195   actor_signals[ENTER_EVENT] =
6196     g_signal_new (I_("enter-event"),
6197                   G_TYPE_FROM_CLASS (object_class),
6198                   G_SIGNAL_RUN_LAST,
6199                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6200                   _clutter_boolean_handled_accumulator, NULL,
6201                   _clutter_marshal_BOOLEAN__BOXED,
6202                   G_TYPE_BOOLEAN, 1,
6203                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6204
6205   /**
6206    * ClutterActor::leave-event:
6207    * @actor: the actor which the pointer has left
6208    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6209    *
6210    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6211    *
6212    * Return value: %TRUE if the event has been handled by the actor,
6213    *   or %FALSE to continue the emission.
6214    *
6215    * Since: 0.6
6216    */
6217   actor_signals[LEAVE_EVENT] =
6218     g_signal_new (I_("leave-event"),
6219                   G_TYPE_FROM_CLASS (object_class),
6220                   G_SIGNAL_RUN_LAST,
6221                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6222                   _clutter_boolean_handled_accumulator, NULL,
6223                   _clutter_marshal_BOOLEAN__BOXED,
6224                   G_TYPE_BOOLEAN, 1,
6225                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6226
6227   /**
6228    * ClutterActor::captured-event:
6229    * @actor: the actor which received the signal
6230    * @event: a #ClutterEvent
6231    *
6232    * The ::captured-event signal is emitted when an event is captured
6233    * by Clutter. This signal will be emitted starting from the top-level
6234    * container (the #ClutterStage) to the actor which received the event
6235    * going down the hierarchy. This signal can be used to intercept every
6236    * event before the specialized events (like
6237    * ClutterActor::button-press-event or ::key-released-event) are
6238    * emitted.
6239    *
6240    * Return value: %TRUE if the event has been handled by the actor,
6241    *   or %FALSE to continue the emission.
6242    *
6243    * Since: 0.6
6244    */
6245   actor_signals[CAPTURED_EVENT] =
6246     g_signal_new (I_("captured-event"),
6247                   G_TYPE_FROM_CLASS (object_class),
6248                   G_SIGNAL_RUN_LAST,
6249                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6250                   _clutter_boolean_handled_accumulator, NULL,
6251                   _clutter_marshal_BOOLEAN__BOXED,
6252                   G_TYPE_BOOLEAN, 1,
6253                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6254
6255   /**
6256    * ClutterActor::paint:
6257    * @actor: the #ClutterActor that received the signal
6258    *
6259    * The ::paint signal is emitted each time an actor is being painted.
6260    *
6261    * Subclasses of #ClutterActor should override the class signal handler
6262    * and paint themselves in that function.
6263    *
6264    * It is possible to connect a handler to the ::paint signal in order
6265    * to set up some custom aspect of a paint.
6266    *
6267    * Since: 0.8
6268    */
6269   actor_signals[PAINT] =
6270     g_signal_new (I_("paint"),
6271                   G_TYPE_FROM_CLASS (object_class),
6272                   G_SIGNAL_RUN_LAST,
6273                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6274                   NULL, NULL,
6275                   _clutter_marshal_VOID__VOID,
6276                   G_TYPE_NONE, 0);
6277   /**
6278    * ClutterActor::realize:
6279    * @actor: the #ClutterActor that received the signal
6280    *
6281    * The ::realize signal is emitted each time an actor is being
6282    * realized.
6283    *
6284    * Since: 0.8
6285    */
6286   actor_signals[REALIZE] =
6287     g_signal_new (I_("realize"),
6288                   G_TYPE_FROM_CLASS (object_class),
6289                   G_SIGNAL_RUN_LAST,
6290                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6291                   NULL, NULL,
6292                   _clutter_marshal_VOID__VOID,
6293                   G_TYPE_NONE, 0);
6294   /**
6295    * ClutterActor::unrealize:
6296    * @actor: the #ClutterActor that received the signal
6297    *
6298    * The ::unrealize signal is emitted each time an actor is being
6299    * unrealized.
6300    *
6301    * Since: 0.8
6302    */
6303   actor_signals[UNREALIZE] =
6304     g_signal_new (I_("unrealize"),
6305                   G_TYPE_FROM_CLASS (object_class),
6306                   G_SIGNAL_RUN_LAST,
6307                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6308                   NULL, NULL,
6309                   _clutter_marshal_VOID__VOID,
6310                   G_TYPE_NONE, 0);
6311
6312   /**
6313    * ClutterActor::pick:
6314    * @actor: the #ClutterActor that received the signal
6315    * @color: the #ClutterColor to be used when picking
6316    *
6317    * The ::pick signal is emitted each time an actor is being painted
6318    * in "pick mode". The pick mode is used to identify the actor during
6319    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6320    * The actor should paint its shape using the passed @pick_color.
6321    *
6322    * Subclasses of #ClutterActor should override the class signal handler
6323    * and paint themselves in that function.
6324    *
6325    * It is possible to connect a handler to the ::pick signal in order
6326    * to set up some custom aspect of a paint in pick mode.
6327    *
6328    * Since: 1.0
6329    */
6330   actor_signals[PICK] =
6331     g_signal_new (I_("pick"),
6332                   G_TYPE_FROM_CLASS (object_class),
6333                   G_SIGNAL_RUN_LAST,
6334                   G_STRUCT_OFFSET (ClutterActorClass, pick),
6335                   NULL, NULL,
6336                   _clutter_marshal_VOID__BOXED,
6337                   G_TYPE_NONE, 1,
6338                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6339
6340   /**
6341    * ClutterActor::allocation-changed:
6342    * @actor: the #ClutterActor that emitted the signal
6343    * @box: a #ClutterActorBox with the new allocation
6344    * @flags: #ClutterAllocationFlags for the allocation
6345    *
6346    * The ::allocation-changed signal is emitted when the
6347    * #ClutterActor:allocation property changes. Usually, application
6348    * code should just use the notifications for the :allocation property
6349    * but if you want to track the allocation flags as well, for instance
6350    * to know whether the absolute origin of @actor changed, then you might
6351    * want use this signal instead.
6352    *
6353    * Since: 1.0
6354    */
6355   actor_signals[ALLOCATION_CHANGED] =
6356     g_signal_new (I_("allocation-changed"),
6357                   G_TYPE_FROM_CLASS (object_class),
6358                   G_SIGNAL_RUN_LAST,
6359                   0,
6360                   NULL, NULL,
6361                   _clutter_marshal_VOID__BOXED_FLAGS,
6362                   G_TYPE_NONE, 2,
6363                   CLUTTER_TYPE_ACTOR_BOX,
6364                   CLUTTER_TYPE_ALLOCATION_FLAGS);
6365 }
6366
6367 static void
6368 clutter_actor_init (ClutterActor *self)
6369 {
6370   ClutterActorPrivate *priv;
6371
6372   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6373
6374   priv->id = _clutter_context_acquire_id (self);
6375   priv->pick_id = -1;
6376
6377   priv->opacity = 0xff;
6378   priv->show_on_set_parent = TRUE;
6379
6380   priv->needs_width_request = TRUE;
6381   priv->needs_height_request = TRUE;
6382   priv->needs_allocation = TRUE;
6383
6384   priv->cached_width_age = 1;
6385   priv->cached_height_age = 1;
6386
6387   priv->opacity_override = -1;
6388   priv->enable_model_view_transform = TRUE;
6389
6390   /* Initialize an empty paint volume to start with */
6391   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6392   priv->last_paint_volume_valid = TRUE;
6393
6394   priv->transform_valid = FALSE;
6395 }
6396
6397 /**
6398  * clutter_actor_new:
6399  *
6400  * Creates a new #ClutterActor.
6401  *
6402  * A newly created actor has a floating reference, which will be sunk
6403  * when it is added to another actor.
6404  *
6405  * Return value: (transfer full): the newly created #ClutterActor
6406  *
6407  * Since: 1.10
6408  */
6409 ClutterActor *
6410 clutter_actor_new (void)
6411 {
6412   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6413 }
6414
6415 /**
6416  * clutter_actor_destroy:
6417  * @self: a #ClutterActor
6418  *
6419  * Destroys an actor.  When an actor is destroyed, it will break any
6420  * references it holds to other objects.  If the actor is inside a
6421  * container, the actor will be removed.
6422  *
6423  * When you destroy a container, its children will be destroyed as well.
6424  *
6425  * Note: you cannot destroy the #ClutterStage returned by
6426  * clutter_stage_get_default().
6427  */
6428 void
6429 clutter_actor_destroy (ClutterActor *self)
6430 {
6431   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6432
6433   g_object_ref (self);
6434
6435   /* avoid recursion while destroying */
6436   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6437     {
6438       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6439
6440       g_object_run_dispose (G_OBJECT (self));
6441
6442       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6443     }
6444
6445   g_object_unref (self);
6446 }
6447
6448 void
6449 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6450                                     ClutterPaintVolume *clip)
6451 {
6452   ClutterActorPrivate *priv = self->priv;
6453   ClutterPaintVolume *pv;
6454   gboolean clipped;
6455
6456   /* If we've been explicitly passed a clip volume then there's
6457    * nothing more to calculate, but otherwise the only thing we know
6458    * is that the change is constrained to the given actor.
6459    *
6460    * The idea is that if we know the paint volume for where the actor
6461    * was last drawn (in eye coordinates) and we also have the paint
6462    * volume for where it will be drawn next (in actor coordinates)
6463    * then if we queue a redraw for both these volumes that will cover
6464    * everything that needs to be redrawn to clear the old view and
6465    * show the latest view of the actor.
6466    *
6467    * Don't clip this redraw if we don't know what position we had for
6468    * the previous redraw since we don't know where to set the clip so
6469    * it will clear the actor as it is currently.
6470    */
6471   if (clip)
6472     {
6473       _clutter_actor_set_queue_redraw_clip (self, clip);
6474       clipped = TRUE;
6475     }
6476   else if (G_LIKELY (priv->last_paint_volume_valid))
6477     {
6478       pv = _clutter_actor_get_paint_volume_mutable (self);
6479       if (pv)
6480         {
6481           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6482
6483           /* make sure we redraw the actors old position... */
6484           _clutter_actor_set_queue_redraw_clip (stage,
6485                                                 &priv->last_paint_volume);
6486           _clutter_actor_signal_queue_redraw (stage, stage);
6487           _clutter_actor_set_queue_redraw_clip (stage, NULL);
6488
6489           /* XXX: Ideally the redraw signal would take a clip volume
6490            * argument, but that would be an ABI break. Until we can
6491            * break the ABI we pass the argument out-of-band
6492            */
6493
6494           /* setup the clip for the actors new position... */
6495           _clutter_actor_set_queue_redraw_clip (self, pv);
6496           clipped = TRUE;
6497         }
6498       else
6499         clipped = FALSE;
6500     }
6501   else
6502     clipped = FALSE;
6503
6504   _clutter_actor_signal_queue_redraw (self, self);
6505
6506   /* Just in case anyone is manually firing redraw signals without
6507    * using the public queue_redraw() API we are careful to ensure that
6508    * our out-of-band clip member is cleared before returning...
6509    *
6510    * Note: A NULL clip denotes a full-stage, un-clipped redraw
6511    */
6512   if (G_LIKELY (clipped))
6513     _clutter_actor_set_queue_redraw_clip (self, NULL);
6514
6515   priv->queue_redraw_entry = NULL;
6516 }
6517
6518 static void
6519 _clutter_actor_get_allocation_clip (ClutterActor *self,
6520                                     ClutterActorBox *clip)
6521 {
6522   ClutterActorBox allocation;
6523
6524   /* XXX: we don't care if we get an out of date allocation here
6525    * because clutter_actor_queue_redraw_with_clip knows to ignore
6526    * the clip if the actor's allocation is invalid.
6527    *
6528    * This is noted because clutter_actor_get_allocation_box does some
6529    * unnecessary work to support buggy code with a comment suggesting
6530    * that it could be changed later which would be good for this use
6531    * case!
6532    */
6533   clutter_actor_get_allocation_box (self, &allocation);
6534
6535   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6536    * actor's own coordinate space but the allocation is in parent
6537    * coordinates */
6538   clip->x1 = 0;
6539   clip->y1 = 0;
6540   clip->x2 = allocation.x2 - allocation.x1;
6541   clip->y2 = allocation.y2 - allocation.y1;
6542 }
6543
6544 void
6545 _clutter_actor_queue_redraw_full (ClutterActor       *self,
6546                                   ClutterRedrawFlags  flags,
6547                                   ClutterPaintVolume *volume,
6548                                   ClutterEffect      *effect)
6549 {
6550   ClutterActorPrivate *priv = self->priv;
6551   ClutterPaintVolume allocation_pv;
6552   ClutterPaintVolume *pv;
6553   gboolean should_free_pv;
6554   ClutterActor *stage;
6555
6556   /* Here's an outline of the actor queue redraw mechanism:
6557    *
6558    * The process starts in one of the following two functions which
6559    * are wrappers for this function:
6560    * clutter_actor_queue_redraw
6561    * _clutter_actor_queue_redraw_with_clip
6562    *
6563    * additionally, an effect can queue a redraw by wrapping this
6564    * function in clutter_effect_queue_rerun
6565    *
6566    * This functions queues an entry in a list associated with the
6567    * stage which is a list of actors that queued a redraw while
6568    * updating the timelines, performing layouting and processing other
6569    * mainloop sources before the next paint starts.
6570    *
6571    * We aim to minimize the processing done at this point because
6572    * there is a good chance other events will happen while updating
6573    * the scenegraph that would invalidate any expensive work we might
6574    * otherwise try to do here. For example we don't try and resolve
6575    * the screen space bounding box of an actor at this stage so as to
6576    * minimize how much of the screen redraw because it's possible
6577    * something else will happen which will force a full redraw anyway.
6578    *
6579    * When all updates are complete and we come to paint the stage then
6580    * we iterate this list and actually emit the "queue-redraw" signals
6581    * for each of the listed actors which will bubble up to the stage
6582    * for each actor and at that point we will transform the actors
6583    * paint volume into screen coordinates to determine the clip region
6584    * for what needs to be redrawn in the next paint.
6585    *
6586    * Besides minimizing redundant work another reason for this
6587    * deferred design is that it's more likely we will be able to
6588    * determine the paint volume of an actor once we've finished
6589    * updating the scenegraph because its allocation should be up to
6590    * date. NB: If we can't determine an actors paint volume then we
6591    * can't automatically queue a clipped redraw which can make a big
6592    * difference to performance.
6593    *
6594    * So the control flow goes like this:
6595    * One of clutter_actor_queue_redraw,
6596    *        _clutter_actor_queue_redraw_with_clip
6597    *     or clutter_effect_queue_rerun
6598    *
6599    * then control moves to:
6600    *   _clutter_stage_queue_actor_redraw
6601    *
6602    * later during _clutter_stage_do_update, once relayouting is done
6603    * and the scenegraph has been updated we will call:
6604    * _clutter_stage_finish_queue_redraws
6605    *
6606    * _clutter_stage_finish_queue_redraws will call
6607    * _clutter_actor_finish_queue_redraw for each listed actor.
6608    * Note: actors *are* allowed to queue further redraws during this
6609    * process (considering clone actors or texture_new_from_actor which
6610    * respond to their source queueing a redraw by queuing a redraw
6611    * themselves). We repeat the process until the list is empty.
6612    *
6613    * This will result in the "queue-redraw" signal being fired for
6614    * each actor which will pass control to the default signal handler:
6615    * clutter_actor_real_queue_redraw
6616    *
6617    * This will bubble up to the stages handler:
6618    * clutter_stage_real_queue_redraw
6619    *
6620    * clutter_stage_real_queue_redraw will transform the actors paint
6621    * volume into screen space and add it as a clip region for the next
6622    * paint.
6623    */
6624
6625   /* ignore queueing a redraw for actors being destroyed */
6626   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6627     return;
6628
6629   stage = _clutter_actor_get_stage_internal (self);
6630
6631   /* Ignore queueing a redraw for actors not descended from a stage */
6632   if (stage == NULL)
6633     return;
6634
6635   /* ignore queueing a redraw on stages that are being destroyed */
6636   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6637     return;
6638
6639   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6640     {
6641       ClutterActorBox allocation_clip;
6642       ClutterVertex origin;
6643
6644       /* If the actor doesn't have a valid allocation then we will
6645        * queue a full stage redraw. */
6646       if (priv->needs_allocation)
6647         {
6648           /* NB: NULL denotes an undefined clip which will result in a
6649            * full redraw... */
6650           _clutter_actor_set_queue_redraw_clip (self, NULL);
6651           _clutter_actor_signal_queue_redraw (self, self);
6652           return;
6653         }
6654
6655       _clutter_paint_volume_init_static (&allocation_pv, self);
6656       pv = &allocation_pv;
6657
6658       _clutter_actor_get_allocation_clip (self, &allocation_clip);
6659
6660       origin.x = allocation_clip.x1;
6661       origin.y = allocation_clip.y1;
6662       origin.z = 0;
6663       clutter_paint_volume_set_origin (pv, &origin);
6664       clutter_paint_volume_set_width (pv,
6665                                       allocation_clip.x2 - allocation_clip.x1);
6666       clutter_paint_volume_set_height (pv,
6667                                        allocation_clip.y2 -
6668                                        allocation_clip.y1);
6669       should_free_pv = TRUE;
6670     }
6671   else
6672     {
6673       pv = volume;
6674       should_free_pv = FALSE;
6675     }
6676
6677   self->priv->queue_redraw_entry =
6678     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6679                                        priv->queue_redraw_entry,
6680                                        self,
6681                                        pv);
6682
6683   if (should_free_pv)
6684     clutter_paint_volume_free (pv);
6685
6686   /* If this is the first redraw queued then we can directly use the
6687      effect parameter */
6688   if (!priv->is_dirty)
6689     priv->effect_to_redraw = effect;
6690   /* Otherwise we need to merge it with the existing effect parameter */
6691   else if (effect != NULL)
6692     {
6693       /* If there's already an effect then we need to use whichever is
6694          later in the chain of actors. Otherwise a full redraw has
6695          already been queued on the actor so we need to ignore the
6696          effect parameter */
6697       if (priv->effect_to_redraw != NULL)
6698         {
6699           if (priv->effects == NULL)
6700             g_warning ("Redraw queued with an effect that is "
6701                        "not applied to the actor");
6702           else
6703             {
6704               const GList *l;
6705
6706               for (l = _clutter_meta_group_peek_metas (priv->effects);
6707                    l != NULL;
6708                    l = l->next)
6709                 {
6710                   if (l->data == priv->effect_to_redraw ||
6711                       l->data == effect)
6712                     priv->effect_to_redraw = l->data;
6713                 }
6714             }
6715         }
6716     }
6717   else
6718     {
6719       /* If no effect is specified then we need to redraw the whole
6720          actor */
6721       priv->effect_to_redraw = NULL;
6722     }
6723
6724   priv->is_dirty = TRUE;
6725 }
6726
6727 /**
6728  * clutter_actor_queue_redraw:
6729  * @self: A #ClutterActor
6730  *
6731  * Queues up a redraw of an actor and any children. The redraw occurs
6732  * once the main loop becomes idle (after the current batch of events
6733  * has been processed, roughly).
6734  *
6735  * Applications rarely need to call this, as redraws are handled
6736  * automatically by modification functions.
6737  *
6738  * This function will not do anything if @self is not visible, or
6739  * if the actor is inside an invisible part of the scenegraph.
6740  *
6741  * Also be aware that painting is a NOP for actors with an opacity of
6742  * 0
6743  *
6744  * When you are implementing a custom actor you must queue a redraw
6745  * whenever some private state changes that will affect painting or
6746  * picking of your actor.
6747  */
6748 void
6749 clutter_actor_queue_redraw (ClutterActor *self)
6750 {
6751   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6752
6753   _clutter_actor_queue_redraw_full (self,
6754                                     0, /* flags */
6755                                     NULL, /* clip volume */
6756                                     NULL /* effect */);
6757 }
6758
6759 /*< private >
6760  * _clutter_actor_queue_redraw_with_clip:
6761  * @self: A #ClutterActor
6762  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
6763  *   this queue redraw.
6764  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
6765  *   redrawn or %NULL if you are just using a @flag to state your
6766  *   desired clipping.
6767  *
6768  * Queues up a clipped redraw of an actor and any children. The redraw
6769  * occurs once the main loop becomes idle (after the current batch of
6770  * events has been processed, roughly).
6771  *
6772  * If no flags are given the clip volume is defined by @volume
6773  * specified in actor coordinates and tells Clutter that only content
6774  * within this volume has been changed so Clutter can optionally
6775  * optimize the redraw.
6776  *
6777  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
6778  * should be %NULL and this tells Clutter to use the actor's current
6779  * allocation as a clip box. This flag can only be used for 2D actors,
6780  * because any actor with depth may be projected outside its
6781  * allocation.
6782  *
6783  * Applications rarely need to call this, as redraws are handled
6784  * automatically by modification functions.
6785  *
6786  * This function will not do anything if @self is not visible, or if
6787  * the actor is inside an invisible part of the scenegraph.
6788  *
6789  * Also be aware that painting is a NOP for actors with an opacity of
6790  * 0
6791  *
6792  * When you are implementing a custom actor you must queue a redraw
6793  * whenever some private state changes that will affect painting or
6794  * picking of your actor.
6795  */
6796 void
6797 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
6798                                        ClutterRedrawFlags  flags,
6799                                        ClutterPaintVolume *volume)
6800 {
6801   _clutter_actor_queue_redraw_full (self,
6802                                     flags, /* flags */
6803                                     volume, /* clip volume */
6804                                     NULL /* effect */);
6805 }
6806
6807 static void
6808 _clutter_actor_queue_only_relayout (ClutterActor *self)
6809 {
6810   ClutterActorPrivate *priv = self->priv;
6811
6812   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6813     return;
6814
6815   if (priv->needs_width_request &&
6816       priv->needs_height_request &&
6817       priv->needs_allocation)
6818     return; /* save some cpu cycles */
6819
6820 #if CLUTTER_ENABLE_DEBUG
6821   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
6822     {
6823       g_warning ("The actor '%s' is currently inside an allocation "
6824                  "cycle; calling clutter_actor_queue_relayout() is "
6825                  "not recommended",
6826                  _clutter_actor_get_debug_name (self));
6827     }
6828 #endif /* CLUTTER_ENABLE_DEBUG */
6829
6830   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
6831 }
6832
6833 /**
6834  * clutter_actor_queue_redraw_with_clip:
6835  * @self: a #ClutterActor
6836  * @clip: (allow-none): a rectangular clip region, or %NULL
6837  *
6838  * Queues a redraw on @self limited to a specific, actor-relative
6839  * rectangular area.
6840  *
6841  * If @clip is %NULL this function is equivalent to
6842  * clutter_actor_queue_redraw().
6843  *
6844  * Since: 1.10
6845  */
6846 void
6847 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
6848                                       const cairo_rectangle_int_t *clip)
6849 {
6850   ClutterPaintVolume volume;
6851   ClutterVertex origin;
6852
6853   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6854
6855   if (clip == NULL)
6856     {
6857       clutter_actor_queue_redraw (self);
6858       return;
6859     }
6860
6861   _clutter_paint_volume_init_static (&volume, self);
6862
6863   origin.x = clip->x;
6864   origin.y = clip->y;
6865   origin.z = 0.0f;
6866
6867   clutter_paint_volume_set_origin (&volume, &origin);
6868   clutter_paint_volume_set_width (&volume, clip->width);
6869   clutter_paint_volume_set_height (&volume, clip->height);
6870
6871   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
6872
6873   clutter_paint_volume_free (&volume);
6874 }
6875
6876 /**
6877  * clutter_actor_queue_relayout:
6878  * @self: A #ClutterActor
6879  *
6880  * Indicates that the actor's size request or other layout-affecting
6881  * properties may have changed. This function is used inside #ClutterActor
6882  * subclass implementations, not by applications directly.
6883  *
6884  * Queueing a new layout automatically queues a redraw as well.
6885  *
6886  * Since: 0.8
6887  */
6888 void
6889 clutter_actor_queue_relayout (ClutterActor *self)
6890 {
6891   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6892
6893   _clutter_actor_queue_only_relayout (self);
6894   clutter_actor_queue_redraw (self);
6895 }
6896
6897 /**
6898  * clutter_actor_get_preferred_size:
6899  * @self: a #ClutterActor
6900  * @min_width_p: (out) (allow-none): return location for the minimum
6901  *   width, or %NULL
6902  * @min_height_p: (out) (allow-none): return location for the minimum
6903  *   height, or %NULL
6904  * @natural_width_p: (out) (allow-none): return location for the natural
6905  *   width, or %NULL
6906  * @natural_height_p: (out) (allow-none): return location for the natural
6907  *   height, or %NULL
6908  *
6909  * Computes the preferred minimum and natural size of an actor, taking into
6910  * account the actor's geometry management (either height-for-width
6911  * or width-for-height).
6912  *
6913  * The width and height used to compute the preferred height and preferred
6914  * width are the actor's natural ones.
6915  *
6916  * If you need to control the height for the preferred width, or the width for
6917  * the preferred height, you should use clutter_actor_get_preferred_width()
6918  * and clutter_actor_get_preferred_height(), and check the actor's preferred
6919  * geometry management using the #ClutterActor:request-mode property.
6920  *
6921  * Since: 0.8
6922  */
6923 void
6924 clutter_actor_get_preferred_size (ClutterActor *self,
6925                                   gfloat       *min_width_p,
6926                                   gfloat       *min_height_p,
6927                                   gfloat       *natural_width_p,
6928                                   gfloat       *natural_height_p)
6929 {
6930   ClutterActorPrivate *priv;
6931   gfloat min_width, min_height;
6932   gfloat natural_width, natural_height;
6933
6934   g_return_if_fail (CLUTTER_IS_ACTOR (self));
6935
6936   priv = self->priv;
6937
6938   min_width = min_height = 0;
6939   natural_width = natural_height = 0;
6940
6941   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
6942     {
6943       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
6944       clutter_actor_get_preferred_width (self, -1,
6945                                          &min_width,
6946                                          &natural_width);
6947       clutter_actor_get_preferred_height (self, natural_width,
6948                                           &min_height,
6949                                           &natural_height);
6950     }
6951   else
6952     {
6953       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
6954       clutter_actor_get_preferred_height (self, -1,
6955                                           &min_height,
6956                                           &natural_height);
6957       clutter_actor_get_preferred_width (self, natural_height,
6958                                          &min_width,
6959                                          &natural_width);
6960     }
6961
6962   if (min_width_p)
6963     *min_width_p = min_width;
6964
6965   if (min_height_p)
6966     *min_height_p = min_height;
6967
6968   if (natural_width_p)
6969     *natural_width_p = natural_width;
6970
6971   if (natural_height_p)
6972     *natural_height_p = natural_height;
6973 }
6974
6975 /*< private >
6976  * effective_align:
6977  * @align: a #ClutterActorAlign
6978  * @direction: a #ClutterTextDirection
6979  *
6980  * Retrieves the correct alignment depending on the text direction
6981  *
6982  * Return value: the effective alignment
6983  */
6984 static ClutterActorAlign
6985 effective_align (ClutterActorAlign    align,
6986                  ClutterTextDirection direction)
6987 {
6988   ClutterActorAlign res;
6989
6990   switch (align)
6991     {
6992     case CLUTTER_ACTOR_ALIGN_START:
6993       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
6994           ? CLUTTER_ACTOR_ALIGN_END
6995           : CLUTTER_ACTOR_ALIGN_START;
6996       break;
6997
6998     case CLUTTER_ACTOR_ALIGN_END:
6999       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7000           ? CLUTTER_ACTOR_ALIGN_START
7001           : CLUTTER_ACTOR_ALIGN_END;
7002       break;
7003
7004     default:
7005       res = align;
7006       break;
7007     }
7008
7009   return res;
7010 }
7011
7012 static inline void
7013 adjust_for_margin (float  margin_start,
7014                    float  margin_end,
7015                    float *minimum_size,
7016                    float *natural_size,
7017                    float *allocated_start,
7018                    float *allocated_end)
7019 {
7020   *minimum_size -= (margin_start + margin_end);
7021   *natural_size -= (margin_start + margin_end);
7022   *allocated_start += margin_start;
7023   *allocated_end -= margin_end;
7024 }
7025
7026 static inline void
7027 adjust_for_alignment (ClutterActorAlign  alignment,
7028                       float              natural_size,
7029                       float             *allocated_start,
7030                       float             *allocated_end)
7031 {
7032   float allocated_size = *allocated_end - *allocated_start;
7033
7034   switch (alignment)
7035     {
7036     case CLUTTER_ACTOR_ALIGN_FILL:
7037       /* do nothing */
7038       break;
7039
7040     case CLUTTER_ACTOR_ALIGN_START:
7041       /* keep start */
7042       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7043       break;
7044
7045     case CLUTTER_ACTOR_ALIGN_END:
7046       if (allocated_size > natural_size)
7047         {
7048           *allocated_start += (allocated_size - natural_size);
7049           *allocated_end = *allocated_start + natural_size;
7050         }
7051       break;
7052
7053     case CLUTTER_ACTOR_ALIGN_CENTER:
7054       if (allocated_size > natural_size)
7055         {
7056           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7057           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7058         }
7059       break;
7060     }
7061 }
7062
7063 /*< private >
7064  * clutter_actor_adjust_width:
7065  * @self: a #ClutterActor
7066  * @minimum_width: (inout): the actor's preferred minimum width, which
7067  *   will be adjusted depending on the margin
7068  * @natural_width: (inout): the actor's preferred natural width, which
7069  *   will be adjusted depending on the margin
7070  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7071  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7072  *
7073  * Adjusts the preferred and allocated position and size of an actor,
7074  * depending on the margin and alignment properties.
7075  */
7076 static void
7077 clutter_actor_adjust_width (ClutterActor *self,
7078                             gfloat       *minimum_width,
7079                             gfloat       *natural_width,
7080                             gfloat       *adjusted_x1,
7081                             gfloat       *adjusted_x2)
7082 {
7083   ClutterTextDirection text_dir;
7084   const ClutterLayoutInfo *info;
7085
7086   info = _clutter_actor_get_layout_info_or_defaults (self);
7087   text_dir = clutter_actor_get_text_direction (self);
7088
7089   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7090
7091   /* this will tweak natural_width to remove the margin, so that
7092    * adjust_for_alignment() will use the correct size
7093    */
7094   adjust_for_margin (info->margin.left, info->margin.right,
7095                      minimum_width, natural_width,
7096                      adjusted_x1, adjusted_x2);
7097
7098   adjust_for_alignment (effective_align (info->x_align, text_dir),
7099                         *natural_width,
7100                         adjusted_x1, adjusted_x2);
7101 }
7102
7103 /*< private >
7104  * clutter_actor_adjust_height:
7105  * @self: a #ClutterActor
7106  * @minimum_height: (inout): the actor's preferred minimum height, which
7107  *   will be adjusted depending on the margin
7108  * @natural_height: (inout): the actor's preferred natural height, which
7109  *   will be adjusted depending on the margin
7110  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7111  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7112  *
7113  * Adjusts the preferred and allocated position and size of an actor,
7114  * depending on the margin and alignment properties.
7115  */
7116 static void
7117 clutter_actor_adjust_height (ClutterActor *self,
7118                              gfloat       *minimum_height,
7119                              gfloat       *natural_height,
7120                              gfloat       *adjusted_y1,
7121                              gfloat       *adjusted_y2)
7122 {
7123   const ClutterLayoutInfo *info;
7124
7125   info = _clutter_actor_get_layout_info_or_defaults (self);
7126
7127   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7128
7129   /* this will tweak natural_height to remove the margin, so that
7130    * adjust_for_alignment() will use the correct size
7131    */
7132   adjust_for_margin (info->margin.top, info->margin.bottom,
7133                      minimum_height, natural_height,
7134                      adjusted_y1,
7135                      adjusted_y2);
7136
7137   /* we don't use effective_align() here, because text direction
7138    * only affects the horizontal axis
7139    */
7140   adjust_for_alignment (info->y_align,
7141                         *natural_height,
7142                         adjusted_y1,
7143                         adjusted_y2);
7144
7145 }
7146
7147 /* looks for a cached size request for this for_size. If not
7148  * found, returns the oldest entry so it can be overwritten */
7149 static gboolean
7150 _clutter_actor_get_cached_size_request (gfloat         for_size,
7151                                         SizeRequest   *cached_size_requests,
7152                                         SizeRequest  **result)
7153 {
7154   guint i;
7155
7156   *result = &cached_size_requests[0];
7157
7158   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7159     {
7160       SizeRequest *sr;
7161
7162       sr = &cached_size_requests[i];
7163
7164       if (sr->age > 0 &&
7165           sr->for_size == for_size)
7166         {
7167           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7168           *result = sr;
7169           return TRUE;
7170         }
7171       else if (sr->age < (*result)->age)
7172         {
7173           *result = sr;
7174         }
7175     }
7176
7177   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7178
7179   return FALSE;
7180 }
7181
7182 /**
7183  * clutter_actor_get_preferred_width:
7184  * @self: A #ClutterActor
7185  * @for_height: available height when computing the preferred width,
7186  *   or a negative value to indicate that no height is defined
7187  * @min_width_p: (out) (allow-none): return location for minimum width,
7188  *   or %NULL
7189  * @natural_width_p: (out) (allow-none): return location for the natural
7190  *   width, or %NULL
7191  *
7192  * Computes the requested minimum and natural widths for an actor,
7193  * optionally depending on the specified height, or if they are
7194  * already computed, returns the cached values.
7195  *
7196  * An actor may not get its request - depending on the layout
7197  * manager that's in effect.
7198  *
7199  * A request should not incorporate the actor's scale or anchor point;
7200  * those transformations do not affect layout, only rendering.
7201  *
7202  * Since: 0.8
7203  */
7204 void
7205 clutter_actor_get_preferred_width (ClutterActor *self,
7206                                    gfloat        for_height,
7207                                    gfloat       *min_width_p,
7208                                    gfloat       *natural_width_p)
7209 {
7210   float request_min_width, request_natural_width;
7211   SizeRequest *cached_size_request;
7212   const ClutterLayoutInfo *info;
7213   ClutterActorPrivate *priv;
7214   gboolean found_in_cache;
7215
7216   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7217
7218   priv = self->priv;
7219
7220   info = _clutter_actor_get_layout_info_or_defaults (self);
7221
7222   /* we shortcircuit the case of a fixed size set using set_width() */
7223   if (priv->min_width_set && priv->natural_width_set)
7224     {
7225       if (min_width_p != NULL)
7226         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7227
7228       if (natural_width_p != NULL)
7229         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7230
7231       return;
7232     }
7233
7234   /* the remaining cases are:
7235    *
7236    *   - either min_width or natural_width have been set
7237    *   - neither min_width or natural_width have been set
7238    *
7239    * in both cases, we go through the cache (and through the actor in case
7240    * of cache misses) and determine the authoritative value depending on
7241    * the *_set flags.
7242    */
7243
7244   if (!priv->needs_width_request)
7245     {
7246       found_in_cache =
7247         _clutter_actor_get_cached_size_request (for_height,
7248                                                 priv->width_requests,
7249                                                 &cached_size_request);
7250     }
7251   else
7252     {
7253       /* if the actor needs a width request we use the first slot */
7254       found_in_cache = FALSE;
7255       cached_size_request = &priv->width_requests[0];
7256     }
7257
7258   if (!found_in_cache)
7259     {
7260       gfloat minimum_width, natural_width;
7261       ClutterActorClass *klass;
7262
7263       minimum_width = natural_width = 0;
7264
7265       /* adjust for the margin */
7266       if (for_height >= 0)
7267         {
7268           for_height -= (info->margin.top + info->margin.bottom);
7269           if (for_height < 0)
7270             for_height = 0;
7271         }
7272
7273       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7274
7275       klass = CLUTTER_ACTOR_GET_CLASS (self);
7276       klass->get_preferred_width (self, for_height,
7277                                   &minimum_width,
7278                                   &natural_width);
7279
7280       /* adjust for the margin */
7281       minimum_width += (info->margin.left + info->margin.right);
7282       natural_width += (info->margin.left + info->margin.right);
7283
7284       /* Due to accumulated float errors, it's better not to warn
7285        * on this, but just fix it.
7286        */
7287       if (natural_width < minimum_width)
7288         natural_width = minimum_width;
7289
7290       cached_size_request->min_size = minimum_width;
7291       cached_size_request->natural_size = natural_width;
7292       cached_size_request->for_size = for_height;
7293       cached_size_request->age = priv->cached_width_age;
7294
7295       priv->cached_width_age += 1;
7296       priv->needs_width_request = FALSE;
7297     }
7298
7299   if (!priv->min_width_set)
7300     request_min_width = cached_size_request->min_size;
7301   else
7302     request_min_width = info->min_width;
7303
7304   if (!priv->natural_width_set)
7305     request_natural_width = cached_size_request->natural_size;
7306   else
7307     request_natural_width = info->natural_width;
7308
7309   if (min_width_p)
7310     *min_width_p = request_min_width;
7311
7312   if (natural_width_p)
7313     *natural_width_p = request_natural_width;
7314 }
7315
7316 /**
7317  * clutter_actor_get_preferred_height:
7318  * @self: A #ClutterActor
7319  * @for_width: available width to assume in computing desired height,
7320  *   or a negative value to indicate that no width is defined
7321  * @min_height_p: (out) (allow-none): return location for minimum height,
7322  *   or %NULL
7323  * @natural_height_p: (out) (allow-none): return location for natural
7324  *   height, or %NULL
7325  *
7326  * Computes the requested minimum and natural heights for an actor,
7327  * or if they are already computed, returns the cached values.
7328  *
7329  * An actor may not get its request - depending on the layout
7330  * manager that's in effect.
7331  *
7332  * A request should not incorporate the actor's scale or anchor point;
7333  * those transformations do not affect layout, only rendering.
7334  *
7335  * Since: 0.8
7336  */
7337 void
7338 clutter_actor_get_preferred_height (ClutterActor *self,
7339                                     gfloat        for_width,
7340                                     gfloat       *min_height_p,
7341                                     gfloat       *natural_height_p)
7342 {
7343   float request_min_height, request_natural_height;
7344   SizeRequest *cached_size_request;
7345   const ClutterLayoutInfo *info;
7346   ClutterActorPrivate *priv;
7347   gboolean found_in_cache;
7348
7349   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7350
7351   priv = self->priv;
7352
7353   info = _clutter_actor_get_layout_info_or_defaults (self);
7354
7355   /* we shortcircuit the case of a fixed size set using set_height() */
7356   if (priv->min_height_set && priv->natural_height_set)
7357     {
7358       if (min_height_p != NULL)
7359         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7360
7361       if (natural_height_p != NULL)
7362         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7363
7364       return;
7365     }
7366
7367   /* the remaining cases are:
7368    *
7369    *   - either min_height or natural_height have been set
7370    *   - neither min_height or natural_height have been set
7371    *
7372    * in both cases, we go through the cache (and through the actor in case
7373    * of cache misses) and determine the authoritative value depending on
7374    * the *_set flags.
7375    */
7376
7377   if (!priv->needs_height_request)
7378     {
7379       found_in_cache =
7380         _clutter_actor_get_cached_size_request (for_width,
7381                                                 priv->height_requests,
7382                                                 &cached_size_request);
7383     }
7384   else
7385     {
7386       found_in_cache = FALSE;
7387       cached_size_request = &priv->height_requests[0];
7388     }
7389
7390   if (!found_in_cache)
7391     {
7392       gfloat minimum_height, natural_height;
7393       ClutterActorClass *klass;
7394
7395       minimum_height = natural_height = 0;
7396
7397       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7398
7399       /* adjust for margin */
7400       if (for_width >= 0)
7401         {
7402           for_width -= (info->margin.left + info->margin.right);
7403           if (for_width < 0)
7404             for_width = 0;
7405         }
7406
7407       klass = CLUTTER_ACTOR_GET_CLASS (self);
7408       klass->get_preferred_height (self, for_width,
7409                                    &minimum_height,
7410                                    &natural_height);
7411
7412       /* adjust for margin */
7413       minimum_height += (info->margin.top + info->margin.bottom);
7414       natural_height += (info->margin.top + info->margin.bottom);
7415
7416       /* Due to accumulated float errors, it's better not to warn
7417        * on this, but just fix it.
7418        */
7419       if (natural_height < minimum_height)
7420         natural_height = minimum_height;
7421
7422       cached_size_request->min_size = minimum_height;
7423       cached_size_request->natural_size = natural_height;
7424       cached_size_request->for_size = for_width;
7425       cached_size_request->age = priv->cached_height_age;
7426
7427       priv->cached_height_age += 1;
7428       priv->needs_height_request = FALSE;
7429     }
7430
7431   if (!priv->min_height_set)
7432     request_min_height = cached_size_request->min_size;
7433   else
7434     request_min_height = info->min_height;
7435
7436   if (!priv->natural_height_set)
7437     request_natural_height = cached_size_request->natural_size;
7438   else
7439     request_natural_height = info->natural_height;
7440
7441   if (min_height_p)
7442     *min_height_p = request_min_height;
7443
7444   if (natural_height_p)
7445     *natural_height_p = request_natural_height;
7446 }
7447
7448 /**
7449  * clutter_actor_get_allocation_box:
7450  * @self: A #ClutterActor
7451  * @box: (out): the function fills this in with the actor's allocation
7452  *
7453  * Gets the layout box an actor has been assigned. The allocation can
7454  * only be assumed valid inside a paint() method; anywhere else, it
7455  * may be out-of-date.
7456  *
7457  * An allocation does not incorporate the actor's scale or anchor point;
7458  * those transformations do not affect layout, only rendering.
7459  *
7460  * <note>Do not call any of the clutter_actor_get_allocation_*() family
7461  * of functions inside the implementation of the get_preferred_width()
7462  * or get_preferred_height() virtual functions.</note>
7463  *
7464  * Since: 0.8
7465  */
7466 void
7467 clutter_actor_get_allocation_box (ClutterActor    *self,
7468                                   ClutterActorBox *box)
7469 {
7470   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7471
7472   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7473    * which limits calling get_allocation to inside paint() basically; or
7474    * we can 2) force a layout, which could be expensive if someone calls
7475    * get_allocation somewhere silly; or we can 3) just return the latest
7476    * value, allowing it to be out-of-date, and assume people know what
7477    * they are doing.
7478    *
7479    * The least-surprises approach that keeps existing code working is
7480    * likely to be 2). People can end up doing some inefficient things,
7481    * though, and in general code that requires 2) is probably broken.
7482    */
7483
7484   /* this implements 2) */
7485   if (G_UNLIKELY (self->priv->needs_allocation))
7486     {
7487       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7488
7489       /* do not queue a relayout on an unparented actor */
7490       if (stage)
7491         _clutter_stage_maybe_relayout (stage);
7492     }
7493
7494   /* commenting out the code above and just keeping this assigment
7495    * implements 3)
7496    */
7497   *box = self->priv->allocation;
7498 }
7499
7500 /**
7501  * clutter_actor_get_allocation_geometry:
7502  * @self: A #ClutterActor
7503  * @geom: (out): allocation geometry in pixels
7504  *
7505  * Gets the layout box an actor has been assigned.  The allocation can
7506  * only be assumed valid inside a paint() method; anywhere else, it
7507  * may be out-of-date.
7508  *
7509  * An allocation does not incorporate the actor's scale or anchor point;
7510  * those transformations do not affect layout, only rendering.
7511  *
7512  * The returned rectangle is in pixels.
7513  *
7514  * Since: 0.8
7515  */
7516 void
7517 clutter_actor_get_allocation_geometry (ClutterActor    *self,
7518                                        ClutterGeometry *geom)
7519 {
7520   ClutterActorBox box;
7521
7522   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7523   g_return_if_fail (geom != NULL);
7524
7525   clutter_actor_get_allocation_box (self, &box);
7526
7527   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7528   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7529   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7530   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7531 }
7532
7533 static void
7534 clutter_actor_update_constraints (ClutterActor    *self,
7535                                   ClutterActorBox *allocation)
7536 {
7537   ClutterActorPrivate *priv = self->priv;
7538   const GList *constraints, *l;
7539
7540   if (priv->constraints == NULL)
7541     return;
7542
7543   constraints = _clutter_meta_group_peek_metas (priv->constraints);
7544   for (l = constraints; l != NULL; l = l->next)
7545     {
7546       ClutterConstraint *constraint = l->data;
7547       ClutterActorMeta *meta = l->data;
7548
7549       if (clutter_actor_meta_get_enabled (meta))
7550         {
7551           _clutter_constraint_update_allocation (constraint,
7552                                                  self,
7553                                                  allocation);
7554         }
7555     }
7556 }
7557
7558 /*< private >
7559  * clutter_actor_adjust_allocation:
7560  * @self: a #ClutterActor
7561  * @allocation: (inout): the allocation to adjust
7562  *
7563  * Adjusts the passed allocation box taking into account the actor's
7564  * layout information, like alignment, expansion, and margin.
7565  */
7566 static void
7567 clutter_actor_adjust_allocation (ClutterActor    *self,
7568                                  ClutterActorBox *allocation)
7569 {
7570   ClutterActorBox adj_allocation;
7571   float alloc_width, alloc_height;
7572   float min_width, min_height;
7573   float nat_width, nat_height;
7574   ClutterRequestMode req_mode;
7575
7576   adj_allocation = *allocation;
7577
7578   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7579
7580   /* we want to hit the cache, so we use the public API */
7581   req_mode = clutter_actor_get_request_mode (self);
7582
7583   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7584     {
7585       clutter_actor_get_preferred_width (self, -1,
7586                                          &min_width,
7587                                          &nat_width);
7588       clutter_actor_get_preferred_height (self, alloc_width,
7589                                           &min_height,
7590                                           &nat_height);
7591     }
7592   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7593     {
7594       clutter_actor_get_preferred_height (self, -1,
7595                                           &min_height,
7596                                           &nat_height);
7597       clutter_actor_get_preferred_height (self, alloc_height,
7598                                           &min_width,
7599                                           &nat_width);
7600     }
7601
7602 #ifdef CLUTTER_ENABLE_DEBUG
7603   /* warn about underallocations */
7604   if (_clutter_diagnostic_enabled () &&
7605       (floorf (min_width - alloc_width) > 0 ||
7606        floorf (min_height - alloc_height) > 0))
7607     {
7608       ClutterActor *parent = clutter_actor_get_parent (self);
7609
7610       /* the only actors that are allowed to be underallocated are the Stage,
7611        * as it doesn't have an implicit size, and Actors that specifically
7612        * told us that they want to opt-out from layout control mechanisms
7613        * through the NO_LAYOUT escape hatch.
7614        */
7615       if (parent != NULL &&
7616           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7617         {
7618           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7619                      "of %.2f x %.2f from its parent actor '%s', but its "
7620                      "requested minimum size is of %.2f x %.2f",
7621                      _clutter_actor_get_debug_name (self),
7622                      alloc_width, alloc_height,
7623                      _clutter_actor_get_debug_name (parent),
7624                      min_width, min_height);
7625         }
7626     }
7627 #endif
7628
7629   clutter_actor_adjust_width (self,
7630                               &min_width,
7631                               &nat_width,
7632                               &adj_allocation.x1,
7633                               &adj_allocation.x2);
7634
7635   clutter_actor_adjust_height (self,
7636                                &min_height,
7637                                &nat_height,
7638                                &adj_allocation.y1,
7639                                &adj_allocation.y2);
7640
7641   /* we maintain the invariant that an allocation cannot be adjusted
7642    * to be outside the parent-given box
7643    */
7644   if (adj_allocation.x1 < allocation->x1 ||
7645       adj_allocation.y1 < allocation->y1 ||
7646       adj_allocation.x2 > allocation->x2 ||
7647       adj_allocation.y2 > allocation->y2)
7648     {
7649       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7650                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7651                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7652                  _clutter_actor_get_debug_name (self),
7653                  adj_allocation.x1, adj_allocation.y1,
7654                  adj_allocation.x2 - adj_allocation.x1,
7655                  adj_allocation.y2 - adj_allocation.y1,
7656                  allocation->x1, allocation->y1,
7657                  allocation->x2 - allocation->x1,
7658                  allocation->y2 - allocation->y1);
7659       return;
7660     }
7661
7662   *allocation = adj_allocation;
7663 }
7664
7665 /**
7666  * clutter_actor_allocate:
7667  * @self: A #ClutterActor
7668  * @box: new allocation of the actor, in parent-relative coordinates
7669  * @flags: flags that control the allocation
7670  *
7671  * Called by the parent of an actor to assign the actor its size.
7672  * Should never be called by applications (except when implementing
7673  * a container or layout manager).
7674  *
7675  * Actors can know from their allocation box whether they have moved
7676  * with respect to their parent actor. The @flags parameter describes
7677  * additional information about the allocation, for instance whether
7678  * the parent has moved with respect to the stage, for example because
7679  * a grandparent's origin has moved.
7680  *
7681  * Since: 0.8
7682  */
7683 void
7684 clutter_actor_allocate (ClutterActor           *self,
7685                         const ClutterActorBox  *box,
7686                         ClutterAllocationFlags  flags)
7687 {
7688   ClutterActorPrivate *priv;
7689   ClutterActorClass *klass;
7690   ClutterActorBox old_allocation, real_allocation;
7691   gboolean origin_changed, child_moved, size_changed;
7692   gboolean stage_allocation_changed;
7693
7694   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7695   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
7696     {
7697       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
7698                  "which isn't a descendent of the stage!\n",
7699                  self, _clutter_actor_get_debug_name (self));
7700       return;
7701     }
7702
7703   priv = self->priv;
7704
7705   old_allocation = priv->allocation;
7706   real_allocation = *box;
7707
7708   /* constraints are allowed to modify the allocation only here; we do
7709    * this prior to all the other checks so that we can bail out if the
7710    * allocation did not change
7711    */
7712   clutter_actor_update_constraints (self, &real_allocation);
7713
7714   /* adjust the allocation depending on the align/margin properties */
7715   clutter_actor_adjust_allocation (self, &real_allocation);
7716
7717   if (real_allocation.x2 < real_allocation.x1 ||
7718       real_allocation.y2 < real_allocation.y1)
7719     {
7720       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
7721                  _clutter_actor_get_debug_name (self),
7722                  real_allocation.x2 - real_allocation.x1,
7723                  real_allocation.y2 - real_allocation.y1);
7724     }
7725
7726   /* we allow 0-sized actors, but not negative-sized ones */
7727   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
7728   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
7729
7730   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
7731
7732   child_moved = (real_allocation.x1 != old_allocation.x1 ||
7733                  real_allocation.y1 != old_allocation.y1);
7734
7735   size_changed = (real_allocation.x2 != old_allocation.x2 ||
7736                   real_allocation.y2 != old_allocation.y2);
7737
7738   if (origin_changed || child_moved || size_changed)
7739     stage_allocation_changed = TRUE;
7740   else
7741     stage_allocation_changed = FALSE;
7742
7743   /* If we get an allocation "out of the blue"
7744    * (we did not queue relayout), then we want to
7745    * ignore it. But if we have needs_allocation set,
7746    * we want to guarantee that allocate() virtual
7747    * method is always called, i.e. that queue_relayout()
7748    * always results in an allocate() invocation on
7749    * an actor.
7750    *
7751    * The optimization here is to avoid re-allocating
7752    * actors that did not queue relayout and were
7753    * not moved.
7754    */
7755   if (!priv->needs_allocation && !stage_allocation_changed)
7756     {
7757       CLUTTER_NOTE (LAYOUT, "No allocation needed");
7758       return;
7759     }
7760
7761   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
7762    * clutter_actor_allocate(), it indicates whether the parent has its
7763    * absolute origin moved; when passed in to ClutterActor::allocate()
7764    * virtual method though, it indicates whether the child has its
7765    * absolute origin moved.  So we set it when child_moved is TRUE
7766    */
7767   if (child_moved)
7768     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
7769
7770   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7771
7772   klass = CLUTTER_ACTOR_GET_CLASS (self);
7773   klass->allocate (self, &real_allocation, flags);
7774
7775   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
7776
7777   if (stage_allocation_changed)
7778     clutter_actor_queue_redraw (self);
7779 }
7780
7781 /**
7782  * clutter_actor_set_allocation:
7783  * @self: a #ClutterActor
7784  * @box: a #ClutterActorBox
7785  * @flags: allocation flags
7786  *
7787  * Stores the allocation of @self as defined by @box.
7788  *
7789  * This function can only be called from within the implementation of
7790  * the #ClutterActorClass.allocate() virtual function.
7791  *
7792  * The allocation should have been adjusted to take into account constraints,
7793  * alignment, and margin properties. If you are implementing a #ClutterActor
7794  * subclass that provides its own layout management policy for its children
7795  * instead of using a #ClutterLayoutManager delegate, you should not call
7796  * this function on the children of @self; instead, you should call
7797  * clutter_actor_allocate(), which will adjust the allocation box for
7798  * you.
7799  *
7800  * This function should only be used by subclasses of #ClutterActor
7801  * that wish to store their allocation but cannot chain up to the
7802  * parent's implementation; the default implementation of the
7803  * #ClutterActorClass.allocate() virtual function will call this
7804  * function.
7805  *
7806  * It is important to note that, while chaining up was the recommended
7807  * behaviour for #ClutterActor subclasses prior to the introduction of
7808  * this function, it is recommended to call clutter_actor_set_allocation()
7809  * instead.
7810  *
7811  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
7812  * to handle the allocation of its children, this function will call
7813  * the clutter_layout_manager_allocate() function only if the
7814  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
7815  * expected that the subclass will call clutter_layout_manager_allocate()
7816  * by itself. For instance, the following code:
7817  *
7818  * |[
7819  * static void
7820  * my_actor_allocate (ClutterActor *actor,
7821  *                    const ClutterActorBox *allocation,
7822  *                    ClutterAllocationFlags flags)
7823  * {
7824  *   ClutterActorBox new_alloc;
7825  *   ClutterAllocationFlags new_flags;
7826  *
7827  *   adjust_allocation (allocation, &amp;new_alloc);
7828  *
7829  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
7830  *
7831  *   /&ast; this will use the layout manager set on the actor &ast;/
7832  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
7833  * }
7834  * ]|
7835  *
7836  * is equivalent to this:
7837  *
7838  * |[
7839  * static void
7840  * my_actor_allocate (ClutterActor *actor,
7841  *                    const ClutterActorBox *allocation,
7842  *                    ClutterAllocationFlags flags)
7843  * {
7844  *   ClutterLayoutManager *layout;
7845  *   ClutterActorBox new_alloc;
7846  *
7847  *   adjust_allocation (allocation, &amp;new_alloc);
7848  *
7849  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
7850  *
7851  *   layout = clutter_actor_get_layout_manager (actor);
7852  *   clutter_layout_manager_allocate (layout,
7853  *                                    CLUTTER_CONTAINER (actor),
7854  *                                    &amp;new_alloc,
7855  *                                    flags);
7856  * }
7857  * ]|
7858  *
7859  * Since: 1.10
7860  */
7861 void
7862 clutter_actor_set_allocation (ClutterActor           *self,
7863                               const ClutterActorBox  *box,
7864                               ClutterAllocationFlags  flags)
7865 {
7866   ClutterActorPrivate *priv;
7867   gboolean changed;
7868
7869   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7870   g_return_if_fail (box != NULL);
7871
7872   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
7873     {
7874       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
7875                   "can only be called from within the implementation of "
7876                   "the ClutterActor::allocate() virtual function.");
7877       return;
7878     }
7879
7880   priv = self->priv;
7881
7882   g_object_freeze_notify (G_OBJECT (self));
7883
7884   changed = clutter_actor_set_allocation_internal (self, box, flags);
7885
7886   /* we allocate our children before we notify changes in our geometry,
7887    * so that people connecting to properties will be able to get valid
7888    * data out of the sub-tree of the scene graph that has this actor at
7889    * the root.
7890    */
7891   clutter_actor_maybe_layout_children (self, box, flags);
7892
7893   if (changed)
7894     g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
7895                    &priv->allocation,
7896                    priv->allocation_flags);
7897
7898   g_object_thaw_notify (G_OBJECT (self));
7899 }
7900
7901 /**
7902  * clutter_actor_set_geometry:
7903  * @self: A #ClutterActor
7904  * @geometry: A #ClutterGeometry
7905  *
7906  * Sets the actor's fixed position and forces its minimum and natural
7907  * size, in pixels. This means the untransformed actor will have the
7908  * given geometry. This is the same as calling clutter_actor_set_position()
7909  * and clutter_actor_set_size().
7910  *
7911  * Deprecated: 1.10: Use clutter_actor_set_position() and
7912  *   clutter_actor_set_size() instead.
7913  */
7914 void
7915 clutter_actor_set_geometry (ClutterActor          *self,
7916                             const ClutterGeometry *geometry)
7917 {
7918   g_object_freeze_notify (G_OBJECT (self));
7919
7920   clutter_actor_set_position (self, geometry->x, geometry->y);
7921   clutter_actor_set_size (self, geometry->width, geometry->height);
7922
7923   g_object_thaw_notify (G_OBJECT (self));
7924 }
7925
7926 /**
7927  * clutter_actor_get_geometry:
7928  * @self: A #ClutterActor
7929  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
7930  *
7931  * Gets the size and position of an actor relative to its parent
7932  * actor. This is the same as calling clutter_actor_get_position() and
7933  * clutter_actor_get_size(). It tries to "do what you mean" and get the
7934  * requested size and position if the actor's allocation is invalid.
7935  *
7936  * Deprecated: 1.10: Use clutter_actor_get_position() and
7937  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
7938  *   instead.
7939  */
7940 void
7941 clutter_actor_get_geometry (ClutterActor    *self,
7942                             ClutterGeometry *geometry)
7943 {
7944   gfloat x, y, width, height;
7945
7946   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7947   g_return_if_fail (geometry != NULL);
7948
7949   clutter_actor_get_position (self, &x, &y);
7950   clutter_actor_get_size (self, &width, &height);
7951
7952   geometry->x = (int) x;
7953   geometry->y = (int) y;
7954   geometry->width = (int) width;
7955   geometry->height = (int) height;
7956 }
7957
7958 /**
7959  * clutter_actor_set_position:
7960  * @self: A #ClutterActor
7961  * @x: New left position of actor in pixels.
7962  * @y: New top position of actor in pixels.
7963  *
7964  * Sets the actor's fixed position in pixels relative to any parent
7965  * actor.
7966  *
7967  * If a layout manager is in use, this position will override the
7968  * layout manager and force a fixed position.
7969  */
7970 void
7971 clutter_actor_set_position (ClutterActor *self,
7972                             gfloat        x,
7973                             gfloat        y)
7974 {
7975   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7976
7977   g_object_freeze_notify (G_OBJECT (self));
7978
7979   clutter_actor_set_x (self, x);
7980   clutter_actor_set_y (self, y);
7981
7982   g_object_thaw_notify (G_OBJECT (self));
7983 }
7984
7985 /**
7986  * clutter_actor_get_fixed_position_set:
7987  * @self: A #ClutterActor
7988  *
7989  * Checks whether an actor has a fixed position set (and will thus be
7990  * unaffected by any layout manager).
7991  *
7992  * Return value: %TRUE if the fixed position is set on the actor
7993  *
7994  * Since: 0.8
7995  */
7996 gboolean
7997 clutter_actor_get_fixed_position_set (ClutterActor *self)
7998 {
7999   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8000
8001   return self->priv->position_set;
8002 }
8003
8004 /**
8005  * clutter_actor_set_fixed_position_set:
8006  * @self: A #ClutterActor
8007  * @is_set: whether to use fixed position
8008  *
8009  * Sets whether an actor has a fixed position set (and will thus be
8010  * unaffected by any layout manager).
8011  *
8012  * Since: 0.8
8013  */
8014 void
8015 clutter_actor_set_fixed_position_set (ClutterActor *self,
8016                                       gboolean      is_set)
8017 {
8018   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8019
8020   if (self->priv->position_set == (is_set != FALSE))
8021     return;
8022
8023   self->priv->position_set = is_set != FALSE;
8024   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8025
8026   clutter_actor_queue_relayout (self);
8027 }
8028
8029 /**
8030  * clutter_actor_move_by:
8031  * @self: A #ClutterActor
8032  * @dx: Distance to move Actor on X axis.
8033  * @dy: Distance to move Actor on Y axis.
8034  *
8035  * Moves an actor by the specified distance relative to its current
8036  * position in pixels.
8037  *
8038  * This function modifies the fixed position of an actor and thus removes
8039  * it from any layout management. Another way to move an actor is with an
8040  * anchor point, see clutter_actor_set_anchor_point().
8041  *
8042  * Since: 0.2
8043  */
8044 void
8045 clutter_actor_move_by (ClutterActor *self,
8046                        gfloat        dx,
8047                        gfloat        dy)
8048 {
8049   const ClutterLayoutInfo *info;
8050   gfloat x, y;
8051
8052   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8053
8054   info = _clutter_actor_get_layout_info_or_defaults (self);
8055   x = info->fixed_x;
8056   y = info->fixed_y;
8057
8058   clutter_actor_set_position (self, x + dx, y + dy);
8059 }
8060
8061 static void
8062 clutter_actor_set_min_width (ClutterActor *self,
8063                              gfloat        min_width)
8064 {
8065   ClutterActorPrivate *priv = self->priv;
8066   ClutterActorBox old = { 0, };
8067   ClutterLayoutInfo *info;
8068
8069   /* if we are setting the size on a top-level actor and the
8070    * backend only supports static top-levels (e.g. framebuffers)
8071    * then we ignore the passed value and we override it with
8072    * the stage implementation's preferred size.
8073    */
8074   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8075       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8076     return;
8077
8078   info = _clutter_actor_get_layout_info (self);
8079
8080   if (priv->min_width_set && min_width == info->min_width)
8081     return;
8082
8083   g_object_freeze_notify (G_OBJECT (self));
8084
8085   clutter_actor_store_old_geometry (self, &old);
8086
8087   info->min_width = min_width;
8088   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8089   clutter_actor_set_min_width_set (self, TRUE);
8090
8091   clutter_actor_notify_if_geometry_changed (self, &old);
8092
8093   g_object_thaw_notify (G_OBJECT (self));
8094
8095   clutter_actor_queue_relayout (self);
8096 }
8097
8098 static void
8099 clutter_actor_set_min_height (ClutterActor *self,
8100                               gfloat        min_height)
8101
8102 {
8103   ClutterActorPrivate *priv = self->priv;
8104   ClutterActorBox old = { 0, };
8105   ClutterLayoutInfo *info;
8106
8107   /* if we are setting the size on a top-level actor and the
8108    * backend only supports static top-levels (e.g. framebuffers)
8109    * then we ignore the passed value and we override it with
8110    * the stage implementation's preferred size.
8111    */
8112   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8113       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8114     return;
8115
8116   info = _clutter_actor_get_layout_info (self);
8117
8118   if (priv->min_height_set && min_height == info->min_height)
8119     return;
8120
8121   g_object_freeze_notify (G_OBJECT (self));
8122
8123   clutter_actor_store_old_geometry (self, &old);
8124
8125   info->min_height = min_height;
8126   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8127   clutter_actor_set_min_height_set (self, TRUE);
8128
8129   clutter_actor_notify_if_geometry_changed (self, &old);
8130
8131   g_object_thaw_notify (G_OBJECT (self));
8132
8133   clutter_actor_queue_relayout (self);
8134 }
8135
8136 static void
8137 clutter_actor_set_natural_width (ClutterActor *self,
8138                                  gfloat        natural_width)
8139 {
8140   ClutterActorPrivate *priv = self->priv;
8141   ClutterActorBox old = { 0, };
8142   ClutterLayoutInfo *info;
8143
8144   /* if we are setting the size on a top-level actor and the
8145    * backend only supports static top-levels (e.g. framebuffers)
8146    * then we ignore the passed value and we override it with
8147    * the stage implementation's preferred size.
8148    */
8149   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8150       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8151     return;
8152
8153   info = _clutter_actor_get_layout_info (self);
8154
8155   if (priv->natural_width_set && natural_width == info->natural_width)
8156     return;
8157
8158   g_object_freeze_notify (G_OBJECT (self));
8159
8160   clutter_actor_store_old_geometry (self, &old);
8161
8162   info->natural_width = natural_width;
8163   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8164   clutter_actor_set_natural_width_set (self, TRUE);
8165
8166   clutter_actor_notify_if_geometry_changed (self, &old);
8167
8168   g_object_thaw_notify (G_OBJECT (self));
8169
8170   clutter_actor_queue_relayout (self);
8171 }
8172
8173 static void
8174 clutter_actor_set_natural_height (ClutterActor *self,
8175                                   gfloat        natural_height)
8176 {
8177   ClutterActorPrivate *priv = self->priv;
8178   ClutterActorBox old = { 0, };
8179   ClutterLayoutInfo *info;
8180
8181   /* if we are setting the size on a top-level actor and the
8182    * backend only supports static top-levels (e.g. framebuffers)
8183    * then we ignore the passed value and we override it with
8184    * the stage implementation's preferred size.
8185    */
8186   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8187       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8188     return;
8189
8190   info = _clutter_actor_get_layout_info (self);
8191
8192   if (priv->natural_height_set && natural_height == info->natural_height)
8193     return;
8194
8195   g_object_freeze_notify (G_OBJECT (self));
8196
8197   clutter_actor_store_old_geometry (self, &old);
8198
8199   info->natural_height = natural_height;
8200   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8201   clutter_actor_set_natural_height_set (self, TRUE);
8202
8203   clutter_actor_notify_if_geometry_changed (self, &old);
8204
8205   g_object_thaw_notify (G_OBJECT (self));
8206
8207   clutter_actor_queue_relayout (self);
8208 }
8209
8210 static void
8211 clutter_actor_set_min_width_set (ClutterActor *self,
8212                                  gboolean      use_min_width)
8213 {
8214   ClutterActorPrivate *priv = self->priv;
8215   ClutterActorBox old = { 0, };
8216
8217   if (priv->min_width_set == (use_min_width != FALSE))
8218     return;
8219
8220   clutter_actor_store_old_geometry (self, &old);
8221
8222   priv->min_width_set = use_min_width != FALSE;
8223   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8224
8225   clutter_actor_notify_if_geometry_changed (self, &old);
8226
8227   clutter_actor_queue_relayout (self);
8228 }
8229
8230 static void
8231 clutter_actor_set_min_height_set (ClutterActor *self,
8232                                   gboolean      use_min_height)
8233 {
8234   ClutterActorPrivate *priv = self->priv;
8235   ClutterActorBox old = { 0, };
8236
8237   if (priv->min_height_set == (use_min_height != FALSE))
8238     return;
8239
8240   clutter_actor_store_old_geometry (self, &old);
8241
8242   priv->min_height_set = use_min_height != FALSE;
8243   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8244
8245   clutter_actor_notify_if_geometry_changed (self, &old);
8246
8247   clutter_actor_queue_relayout (self);
8248 }
8249
8250 static void
8251 clutter_actor_set_natural_width_set (ClutterActor *self,
8252                                      gboolean      use_natural_width)
8253 {
8254   ClutterActorPrivate *priv = self->priv;
8255   ClutterActorBox old = { 0, };
8256
8257   if (priv->natural_width_set == (use_natural_width != FALSE))
8258     return;
8259
8260   clutter_actor_store_old_geometry (self, &old);
8261
8262   priv->natural_width_set = use_natural_width != FALSE;
8263   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8264
8265   clutter_actor_notify_if_geometry_changed (self, &old);
8266
8267   clutter_actor_queue_relayout (self);
8268 }
8269
8270 static void
8271 clutter_actor_set_natural_height_set (ClutterActor *self,
8272                                       gboolean      use_natural_height)
8273 {
8274   ClutterActorPrivate *priv = self->priv;
8275   ClutterActorBox old = { 0, };
8276
8277   if (priv->natural_height_set == (use_natural_height != FALSE))
8278     return;
8279
8280   clutter_actor_store_old_geometry (self, &old);
8281
8282   priv->natural_height_set = use_natural_height != FALSE;
8283   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8284
8285   clutter_actor_notify_if_geometry_changed (self, &old);
8286
8287   clutter_actor_queue_relayout (self);
8288 }
8289
8290 /**
8291  * clutter_actor_set_request_mode:
8292  * @self: a #ClutterActor
8293  * @mode: the request mode
8294  *
8295  * Sets the geometry request mode of @self.
8296  *
8297  * The @mode determines the order for invoking
8298  * clutter_actor_get_preferred_width() and
8299  * clutter_actor_get_preferred_height()
8300  *
8301  * Since: 1.2
8302  */
8303 void
8304 clutter_actor_set_request_mode (ClutterActor       *self,
8305                                 ClutterRequestMode  mode)
8306 {
8307   ClutterActorPrivate *priv;
8308
8309   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8310
8311   priv = self->priv;
8312
8313   if (priv->request_mode == mode)
8314     return;
8315
8316   priv->request_mode = mode;
8317
8318   priv->needs_width_request = TRUE;
8319   priv->needs_height_request = TRUE;
8320
8321   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8322
8323   clutter_actor_queue_relayout (self);
8324 }
8325
8326 /**
8327  * clutter_actor_get_request_mode:
8328  * @self: a #ClutterActor
8329  *
8330  * Retrieves the geometry request mode of @self
8331  *
8332  * Return value: the request mode for the actor
8333  *
8334  * Since: 1.2
8335  */
8336 ClutterRequestMode
8337 clutter_actor_get_request_mode (ClutterActor *self)
8338 {
8339   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8340                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8341
8342   return self->priv->request_mode;
8343 }
8344
8345 /* variant of set_width() without checks and without notification
8346  * freeze+thaw, for internal usage only
8347  */
8348 static inline void
8349 clutter_actor_set_width_internal (ClutterActor *self,
8350                                   gfloat        width)
8351 {
8352   if (width >= 0)
8353     {
8354       /* the Stage will use the :min-width to control the minimum
8355        * width to be resized to, so we should not be setting it
8356        * along with the :natural-width
8357        */
8358       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8359         clutter_actor_set_min_width (self, width);
8360
8361       clutter_actor_set_natural_width (self, width);
8362     }
8363   else
8364     {
8365       /* we only unset the :natural-width for the Stage */
8366       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8367         clutter_actor_set_min_width_set (self, FALSE);
8368
8369       clutter_actor_set_natural_width_set (self, FALSE);
8370     }
8371 }
8372
8373 /* variant of set_height() without checks and without notification
8374  * freeze+thaw, for internal usage only
8375  */
8376 static inline void
8377 clutter_actor_set_height_internal (ClutterActor *self,
8378                                    gfloat        height)
8379 {
8380   if (height >= 0)
8381     {
8382       /* see the comment above in set_width_internal() */
8383       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8384         clutter_actor_set_min_height (self, height);
8385
8386       clutter_actor_set_natural_height (self, height);
8387     }
8388   else
8389     {
8390       /* see the comment above in set_width_internal() */
8391       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8392         clutter_actor_set_min_height_set (self, FALSE);
8393
8394       clutter_actor_set_natural_height_set (self, FALSE);
8395     }
8396 }
8397
8398 /**
8399  * clutter_actor_set_size:
8400  * @self: A #ClutterActor
8401  * @width: New width of actor in pixels, or -1
8402  * @height: New height of actor in pixels, or -1
8403  *
8404  * Sets the actor's size request in pixels. This overrides any
8405  * "normal" size request the actor would have. For example
8406  * a text actor might normally request the size of the text;
8407  * this function would force a specific size instead.
8408  *
8409  * If @width and/or @height are -1 the actor will use its
8410  * "normal" size request instead of overriding it, i.e.
8411  * you can "unset" the size with -1.
8412  *
8413  * This function sets or unsets both the minimum and natural size.
8414  */
8415 void
8416 clutter_actor_set_size (ClutterActor *self,
8417                         gfloat        width,
8418                         gfloat        height)
8419 {
8420   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8421
8422   g_object_freeze_notify (G_OBJECT (self));
8423
8424   clutter_actor_set_width_internal (self, width);
8425   clutter_actor_set_height_internal (self, height);
8426
8427   g_object_thaw_notify (G_OBJECT (self));
8428 }
8429
8430 /**
8431  * clutter_actor_get_size:
8432  * @self: A #ClutterActor
8433  * @width: (out) (allow-none): return location for the width, or %NULL.
8434  * @height: (out) (allow-none): return location for the height, or %NULL.
8435  *
8436  * This function tries to "do what you mean" and return
8437  * the size an actor will have. If the actor has a valid
8438  * allocation, the allocation will be returned; otherwise,
8439  * the actors natural size request will be returned.
8440  *
8441  * If you care whether you get the request vs. the allocation, you
8442  * should probably call a different function like
8443  * clutter_actor_get_allocation_box() or
8444  * clutter_actor_get_preferred_width().
8445  *
8446  * Since: 0.2
8447  */
8448 void
8449 clutter_actor_get_size (ClutterActor *self,
8450                         gfloat       *width,
8451                         gfloat       *height)
8452 {
8453   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8454
8455   if (width)
8456     *width = clutter_actor_get_width (self);
8457
8458   if (height)
8459     *height = clutter_actor_get_height (self);
8460 }
8461
8462 /**
8463  * clutter_actor_get_position:
8464  * @self: a #ClutterActor
8465  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8466  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8467  *
8468  * This function tries to "do what you mean" and tell you where the
8469  * actor is, prior to any transformations. Retrieves the fixed
8470  * position of an actor in pixels, if one has been set; otherwise, if
8471  * the allocation is valid, returns the actor's allocated position;
8472  * otherwise, returns 0,0.
8473  *
8474  * The returned position is in pixels.
8475  *
8476  * Since: 0.6
8477  */
8478 void
8479 clutter_actor_get_position (ClutterActor *self,
8480                             gfloat       *x,
8481                             gfloat       *y)
8482 {
8483   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8484
8485   if (x)
8486     *x = clutter_actor_get_x (self);
8487
8488   if (y)
8489     *y = clutter_actor_get_y (self);
8490 }
8491
8492 /**
8493  * clutter_actor_get_transformed_position:
8494  * @self: A #ClutterActor
8495  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8496  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8497  *
8498  * Gets the absolute position of an actor, in pixels relative to the stage.
8499  *
8500  * Since: 0.8
8501  */
8502 void
8503 clutter_actor_get_transformed_position (ClutterActor *self,
8504                                         gfloat       *x,
8505                                         gfloat       *y)
8506 {
8507   ClutterVertex v1;
8508   ClutterVertex v2;
8509
8510   v1.x = v1.y = v1.z = 0;
8511   clutter_actor_apply_transform_to_point (self, &v1, &v2);
8512
8513   if (x)
8514     *x = v2.x;
8515
8516   if (y)
8517     *y = v2.y;
8518 }
8519
8520 /**
8521  * clutter_actor_get_transformed_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  * Gets the absolute size of an actor in pixels, taking into account the
8527  * scaling factors.
8528  *
8529  * If the actor has a valid allocation, the allocated size will be used.
8530  * If the actor has not a valid allocation then the preferred size will
8531  * be transformed and returned.
8532  *
8533  * If you want the transformed allocation, see
8534  * clutter_actor_get_abs_allocation_vertices() instead.
8535  *
8536  * <note>When the actor (or one of its ancestors) is rotated around the
8537  * X or Y axis, it no longer appears as on the stage as a rectangle, but
8538  * as a generic quadrangle; in that case this function returns the size
8539  * of the smallest rectangle that encapsulates the entire quad. Please
8540  * note that in this case no assumptions can be made about the relative
8541  * position of this envelope to the absolute position of the actor, as
8542  * returned by clutter_actor_get_transformed_position(); if you need this
8543  * information, you need to use clutter_actor_get_abs_allocation_vertices()
8544  * to get the coords of the actual quadrangle.</note>
8545  *
8546  * Since: 0.8
8547  */
8548 void
8549 clutter_actor_get_transformed_size (ClutterActor *self,
8550                                     gfloat       *width,
8551                                     gfloat       *height)
8552 {
8553   ClutterActorPrivate *priv;
8554   ClutterVertex v[4];
8555   gfloat x_min, x_max, y_min, y_max;
8556   gint i;
8557
8558   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8559
8560   priv = self->priv;
8561
8562   /* if the actor hasn't been allocated yet, get the preferred
8563    * size and transform that
8564    */
8565   if (priv->needs_allocation)
8566     {
8567       gfloat natural_width, natural_height;
8568       ClutterActorBox box;
8569
8570       /* Make a fake allocation to transform.
8571        *
8572        * NB: _clutter_actor_transform_and_project_box expects a box in
8573        * the actor's coordinate space... */
8574
8575       box.x1 = 0;
8576       box.y1 = 0;
8577
8578       natural_width = natural_height = 0;
8579       clutter_actor_get_preferred_size (self, NULL, NULL,
8580                                         &natural_width,
8581                                         &natural_height);
8582
8583       box.x2 = natural_width;
8584       box.y2 = natural_height;
8585
8586       _clutter_actor_transform_and_project_box (self, &box, v);
8587     }
8588   else
8589     clutter_actor_get_abs_allocation_vertices (self, v);
8590
8591   x_min = x_max = v[0].x;
8592   y_min = y_max = v[0].y;
8593
8594   for (i = 1; i < G_N_ELEMENTS (v); ++i)
8595     {
8596       if (v[i].x < x_min)
8597         x_min = v[i].x;
8598
8599       if (v[i].x > x_max)
8600         x_max = v[i].x;
8601
8602       if (v[i].y < y_min)
8603         y_min = v[i].y;
8604
8605       if (v[i].y > y_max)
8606         y_max = v[i].y;
8607     }
8608
8609   if (width)
8610     *width  = x_max - x_min;
8611
8612   if (height)
8613     *height = y_max - y_min;
8614 }
8615
8616 /**
8617  * clutter_actor_get_width:
8618  * @self: A #ClutterActor
8619  *
8620  * Retrieves the width of a #ClutterActor.
8621  *
8622  * If the actor has a valid allocation, this function will return the
8623  * width of the allocated area given to the actor.
8624  *
8625  * If the actor does not have a valid allocation, this function will
8626  * return the actor's natural width, that is the preferred width of
8627  * the actor.
8628  *
8629  * If you care whether you get the preferred width or the width that
8630  * has been assigned to the actor, you should probably call a different
8631  * function like clutter_actor_get_allocation_box() to retrieve the
8632  * allocated size or clutter_actor_get_preferred_width() to retrieve the
8633  * preferred width.
8634  *
8635  * If an actor has a fixed width, for instance a width that has been
8636  * assigned using clutter_actor_set_width(), the width returned will
8637  * be the same value.
8638  *
8639  * Return value: the width of the actor, in pixels
8640  */
8641 gfloat
8642 clutter_actor_get_width (ClutterActor *self)
8643 {
8644   ClutterActorPrivate *priv;
8645
8646   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8647
8648   priv = self->priv;
8649
8650   if (priv->needs_allocation)
8651     {
8652       gfloat natural_width = 0;
8653
8654       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8655         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8656       else
8657         {
8658           gfloat natural_height = 0;
8659
8660           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8661           clutter_actor_get_preferred_width (self, natural_height,
8662                                              NULL,
8663                                              &natural_width);
8664         }
8665
8666       return natural_width;
8667     }
8668   else
8669     return priv->allocation.x2 - priv->allocation.x1;
8670 }
8671
8672 /**
8673  * clutter_actor_get_height:
8674  * @self: A #ClutterActor
8675  *
8676  * Retrieves the height of a #ClutterActor.
8677  *
8678  * If the actor has a valid allocation, this function will return the
8679  * height of the allocated area given to the actor.
8680  *
8681  * If the actor does not have a valid allocation, this function will
8682  * return the actor's natural height, that is the preferred height of
8683  * the actor.
8684  *
8685  * If you care whether you get the preferred height or the height that
8686  * has been assigned to the actor, you should probably call a different
8687  * function like clutter_actor_get_allocation_box() to retrieve the
8688  * allocated size or clutter_actor_get_preferred_height() to retrieve the
8689  * preferred height.
8690  *
8691  * If an actor has a fixed height, for instance a height that has been
8692  * assigned using clutter_actor_set_height(), the height returned will
8693  * be the same value.
8694  *
8695  * Return value: the height of the actor, in pixels
8696  */
8697 gfloat
8698 clutter_actor_get_height (ClutterActor *self)
8699 {
8700   ClutterActorPrivate *priv;
8701
8702   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8703
8704   priv = self->priv;
8705
8706   if (priv->needs_allocation)
8707     {
8708       gfloat natural_height = 0;
8709
8710       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8711         {
8712           gfloat natural_width = 0;
8713
8714           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8715           clutter_actor_get_preferred_height (self, natural_width,
8716                                               NULL, &natural_height);
8717         }
8718       else
8719         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8720
8721       return natural_height;
8722     }
8723   else
8724     return priv->allocation.y2 - priv->allocation.y1;
8725 }
8726
8727 /**
8728  * clutter_actor_set_width:
8729  * @self: A #ClutterActor
8730  * @width: Requested new width for the actor, in pixels, or -1
8731  *
8732  * Forces a width on an actor, causing the actor's preferred width
8733  * and height (if any) to be ignored.
8734  *
8735  * If @width is -1 the actor will use its preferred width request
8736  * instead of overriding it, i.e. you can "unset" the width with -1.
8737  *
8738  * This function sets both the minimum and natural size of the actor.
8739  *
8740  * since: 0.2
8741  */
8742 void
8743 clutter_actor_set_width (ClutterActor *self,
8744                          gfloat        width)
8745 {
8746   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8747
8748   g_object_freeze_notify (G_OBJECT (self));
8749
8750   clutter_actor_set_width_internal (self, width);
8751
8752   g_object_thaw_notify (G_OBJECT (self));
8753 }
8754
8755 /**
8756  * clutter_actor_set_height:
8757  * @self: A #ClutterActor
8758  * @height: Requested new height for the actor, in pixels, or -1
8759  *
8760  * Forces a height on an actor, causing the actor's preferred width
8761  * and height (if any) to be ignored.
8762  *
8763  * If @height is -1 the actor will use its preferred height instead of
8764  * overriding it, i.e. you can "unset" the height with -1.
8765  *
8766  * This function sets both the minimum and natural size of the actor.
8767  *
8768  * since: 0.2
8769  */
8770 void
8771 clutter_actor_set_height (ClutterActor *self,
8772                           gfloat        height)
8773 {
8774   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8775
8776   g_object_freeze_notify (G_OBJECT (self));
8777
8778   clutter_actor_set_height_internal (self, height);
8779
8780   g_object_thaw_notify (G_OBJECT (self));
8781 }
8782
8783 /**
8784  * clutter_actor_set_x:
8785  * @self: a #ClutterActor
8786  * @x: the actor's position on the X axis
8787  *
8788  * Sets the actor's X coordinate, relative to its parent, in pixels.
8789  *
8790  * Overrides any layout manager and forces a fixed position for
8791  * the actor.
8792  *
8793  * Since: 0.6
8794  */
8795 void
8796 clutter_actor_set_x (ClutterActor *self,
8797                      gfloat        x)
8798 {
8799   ClutterActorBox old = { 0, };
8800   ClutterActorPrivate *priv;
8801   ClutterLayoutInfo *info;
8802
8803   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8804
8805   priv = self->priv;
8806
8807   info = _clutter_actor_get_layout_info (self);
8808
8809   if (priv->position_set && info->fixed_x == x)
8810     return;
8811
8812   clutter_actor_store_old_geometry (self, &old);
8813
8814   info->fixed_x = x;
8815   clutter_actor_set_fixed_position_set (self, TRUE);
8816
8817   clutter_actor_notify_if_geometry_changed (self, &old);
8818
8819   clutter_actor_queue_relayout (self);
8820 }
8821
8822 /**
8823  * clutter_actor_set_y:
8824  * @self: a #ClutterActor
8825  * @y: the actor's position on the Y axis
8826  *
8827  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
8828  *
8829  * Overrides any layout manager and forces a fixed position for
8830  * the actor.
8831  *
8832  * Since: 0.6
8833  */
8834 void
8835 clutter_actor_set_y (ClutterActor *self,
8836                      gfloat        y)
8837 {
8838   ClutterActorBox old = { 0, };
8839   ClutterActorPrivate *priv;
8840   ClutterLayoutInfo *info;
8841
8842   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8843
8844   priv = self->priv;
8845
8846   info = _clutter_actor_get_layout_info (self);
8847
8848   if (priv->position_set && info->fixed_y == y)
8849     return;
8850
8851   clutter_actor_store_old_geometry (self, &old);
8852
8853   info->fixed_y = y;
8854   clutter_actor_set_fixed_position_set (self, TRUE);
8855
8856   clutter_actor_notify_if_geometry_changed (self, &old);
8857
8858   clutter_actor_queue_relayout (self);
8859 }
8860
8861 /**
8862  * clutter_actor_get_x:
8863  * @self: A #ClutterActor
8864  *
8865  * Retrieves the X coordinate of a #ClutterActor.
8866  *
8867  * This function tries to "do what you mean", by returning the
8868  * correct value depending on the actor's state.
8869  *
8870  * If the actor has a valid allocation, this function will return
8871  * the X coordinate of the origin of the allocation box.
8872  *
8873  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
8874  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8875  * function will return that coordinate.
8876  *
8877  * If both the allocation and a fixed position are missing, this function
8878  * will return 0.
8879  *
8880  * Return value: the X coordinate, in pixels, ignoring any
8881  *   transformation (i.e. scaling, rotation)
8882  */
8883 gfloat
8884 clutter_actor_get_x (ClutterActor *self)
8885 {
8886   ClutterActorPrivate *priv;
8887
8888   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8889
8890   priv = self->priv;
8891
8892   if (priv->needs_allocation)
8893     {
8894       if (priv->position_set)
8895         {
8896           const ClutterLayoutInfo *info;
8897
8898           info = _clutter_actor_get_layout_info_or_defaults (self);
8899
8900           return info->fixed_x;
8901         }
8902       else
8903         return 0;
8904     }
8905   else
8906     return priv->allocation.x1;
8907 }
8908
8909 /**
8910  * clutter_actor_get_y:
8911  * @self: A #ClutterActor
8912  *
8913  * Retrieves the Y coordinate of a #ClutterActor.
8914  *
8915  * This function tries to "do what you mean", by returning the
8916  * correct value depending on the actor's state.
8917  *
8918  * If the actor has a valid allocation, this function will return
8919  * the Y coordinate of the origin of the allocation box.
8920  *
8921  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
8922  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
8923  * function will return that coordinate.
8924  *
8925  * If both the allocation and a fixed position are missing, this function
8926  * will return 0.
8927  *
8928  * Return value: the Y coordinate, in pixels, ignoring any
8929  *   transformation (i.e. scaling, rotation)
8930  */
8931 gfloat
8932 clutter_actor_get_y (ClutterActor *self)
8933 {
8934   ClutterActorPrivate *priv;
8935
8936   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8937
8938   priv = self->priv;
8939
8940   if (priv->needs_allocation)
8941     {
8942       if (priv->position_set)
8943         {
8944           const ClutterLayoutInfo *info;
8945
8946           info = _clutter_actor_get_layout_info_or_defaults (self);
8947
8948           return info->fixed_y;
8949         }
8950       else
8951         return 0;
8952     }
8953   else
8954     return priv->allocation.y1;
8955 }
8956
8957 /**
8958  * clutter_actor_set_scale:
8959  * @self: A #ClutterActor
8960  * @scale_x: double factor to scale actor by horizontally.
8961  * @scale_y: double factor to scale actor by vertically.
8962  *
8963  * Scales an actor with the given factors. The scaling is relative to
8964  * the scale center and the anchor point. The scale center is
8965  * unchanged by this function and defaults to 0,0.
8966  *
8967  * Since: 0.2
8968  */
8969 void
8970 clutter_actor_set_scale (ClutterActor *self,
8971                          gdouble       scale_x,
8972                          gdouble       scale_y)
8973 {
8974   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8975
8976   g_object_freeze_notify (G_OBJECT (self));
8977
8978   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
8979   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
8980
8981   g_object_thaw_notify (G_OBJECT (self));
8982 }
8983
8984 /**
8985  * clutter_actor_set_scale_full:
8986  * @self: A #ClutterActor
8987  * @scale_x: double factor to scale actor by horizontally.
8988  * @scale_y: double factor to scale actor by vertically.
8989  * @center_x: X coordinate of the center of the scale.
8990  * @center_y: Y coordinate of the center of the scale
8991  *
8992  * Scales an actor with the given factors around the given center
8993  * point. The center point is specified in pixels relative to the
8994  * anchor point (usually the top left corner of the actor).
8995  *
8996  * Since: 1.0
8997  */
8998 void
8999 clutter_actor_set_scale_full (ClutterActor *self,
9000                               gdouble       scale_x,
9001                               gdouble       scale_y,
9002                               gfloat        center_x,
9003                               gfloat        center_y)
9004 {
9005   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9006
9007   g_object_freeze_notify (G_OBJECT (self));
9008
9009   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9010   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9011   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9012   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9013
9014   g_object_thaw_notify (G_OBJECT (self));
9015 }
9016
9017 /**
9018  * clutter_actor_set_scale_with_gravity:
9019  * @self: A #ClutterActor
9020  * @scale_x: double factor to scale actor by horizontally.
9021  * @scale_y: double factor to scale actor by vertically.
9022  * @gravity: the location of the scale center expressed as a compass
9023  * direction.
9024  *
9025  * Scales an actor with the given factors around the given
9026  * center point. The center point is specified as one of the compass
9027  * directions in #ClutterGravity. For example, setting it to north
9028  * will cause the top of the actor to remain unchanged and the rest of
9029  * the actor to expand left, right and downwards.
9030  *
9031  * Since: 1.0
9032  */
9033 void
9034 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9035                                       gdouble         scale_x,
9036                                       gdouble         scale_y,
9037                                       ClutterGravity  gravity)
9038 {
9039   ClutterTransformInfo *info;
9040   GObject *obj;
9041
9042   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9043
9044   obj = G_OBJECT (self);
9045
9046   g_object_freeze_notify (obj);
9047
9048   info = _clutter_actor_get_transform_info (self);
9049   info->scale_x = scale_x;
9050   info->scale_y = scale_y;
9051
9052   if (gravity == CLUTTER_GRAVITY_NONE)
9053     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9054   else
9055     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9056
9057   self->priv->transform_valid = FALSE;
9058
9059   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9060   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9061   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9062   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9063   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9064
9065   clutter_actor_queue_redraw (self);
9066
9067   g_object_thaw_notify (obj);
9068 }
9069
9070 /**
9071  * clutter_actor_get_scale:
9072  * @self: A #ClutterActor
9073  * @scale_x: (out) (allow-none): Location to store horizonal
9074  *   scale factor, or %NULL.
9075  * @scale_y: (out) (allow-none): Location to store vertical
9076  *   scale factor, or %NULL.
9077  *
9078  * Retrieves an actors scale factors.
9079  *
9080  * Since: 0.2
9081  */
9082 void
9083 clutter_actor_get_scale (ClutterActor *self,
9084                          gdouble      *scale_x,
9085                          gdouble      *scale_y)
9086 {
9087   const ClutterTransformInfo *info;
9088
9089   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9090
9091   info = _clutter_actor_get_transform_info_or_defaults (self);
9092
9093   if (scale_x)
9094     *scale_x = info->scale_x;
9095
9096   if (scale_y)
9097     *scale_y = info->scale_y;
9098 }
9099
9100 /**
9101  * clutter_actor_get_scale_center:
9102  * @self: A #ClutterActor
9103  * @center_x: (out) (allow-none): Location to store the X position
9104  *   of the scale center, or %NULL.
9105  * @center_y: (out) (allow-none): Location to store the Y position
9106  *   of the scale center, or %NULL.
9107  *
9108  * Retrieves the scale center coordinate in pixels relative to the top
9109  * left corner of the actor. If the scale center was specified using a
9110  * #ClutterGravity this will calculate the pixel offset using the
9111  * current size of the actor.
9112  *
9113  * Since: 1.0
9114  */
9115 void
9116 clutter_actor_get_scale_center (ClutterActor *self,
9117                                 gfloat       *center_x,
9118                                 gfloat       *center_y)
9119 {
9120   const ClutterTransformInfo *info;
9121
9122   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9123
9124   info = _clutter_actor_get_transform_info_or_defaults (self);
9125
9126   clutter_anchor_coord_get_units (self, &info->scale_center,
9127                                   center_x,
9128                                   center_y,
9129                                   NULL);
9130 }
9131
9132 /**
9133  * clutter_actor_get_scale_gravity:
9134  * @self: A #ClutterActor
9135  *
9136  * Retrieves the scale center as a compass direction. If the scale
9137  * center was specified in pixels or units this will return
9138  * %CLUTTER_GRAVITY_NONE.
9139  *
9140  * Return value: the scale gravity
9141  *
9142  * Since: 1.0
9143  */
9144 ClutterGravity
9145 clutter_actor_get_scale_gravity (ClutterActor *self)
9146 {
9147   const ClutterTransformInfo *info;
9148
9149   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9150
9151   info = _clutter_actor_get_transform_info_or_defaults (self);
9152
9153   return clutter_anchor_coord_get_gravity (&info->scale_center);
9154 }
9155
9156 /**
9157  * clutter_actor_set_opacity:
9158  * @self: A #ClutterActor
9159  * @opacity: New opacity value for the actor.
9160  *
9161  * Sets the actor's opacity, with zero being completely transparent and
9162  * 255 (0xff) being fully opaque.
9163  */
9164 void
9165 clutter_actor_set_opacity (ClutterActor *self,
9166                            guint8        opacity)
9167 {
9168   ClutterActorPrivate *priv;
9169
9170   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9171
9172   priv = self->priv;
9173
9174   if (priv->opacity != opacity)
9175     {
9176       priv->opacity = opacity;
9177
9178       /* Queue a redraw from the flatten effect so that it can use
9179          its cached image if available instead of having to redraw the
9180          actual actor. If it doesn't end up using the FBO then the
9181          effect is still able to continue the paint anyway. If there
9182          is no flatten effect yet then this is equivalent to queueing
9183          a full redraw */
9184       _clutter_actor_queue_redraw_full (self,
9185                                         0, /* flags */
9186                                         NULL, /* clip */
9187                                         priv->flatten_effect);
9188
9189       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9190     }
9191 }
9192
9193 /*
9194  * clutter_actor_get_paint_opacity_internal:
9195  * @self: a #ClutterActor
9196  *
9197  * Retrieves the absolute opacity of the actor, as it appears on the stage
9198  *
9199  * This function does not do type checks
9200  *
9201  * Return value: the absolute opacity of the actor
9202  */
9203 static guint8
9204 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9205 {
9206   ClutterActorPrivate *priv = self->priv;
9207   ClutterActor *parent;
9208
9209   /* override the top-level opacity to always be 255; even in
9210    * case of ClutterStage:use-alpha being TRUE we want the rest
9211    * of the scene to be painted
9212    */
9213   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9214     return 255;
9215
9216   if (priv->opacity_override >= 0)
9217     return priv->opacity_override;
9218
9219   parent = priv->parent;
9220
9221   /* Factor in the actual actors opacity with parents */
9222   if (parent != NULL)
9223     {
9224       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9225
9226       if (opacity != 0xff)
9227         return (opacity * priv->opacity) / 0xff;
9228     }
9229
9230   return priv->opacity;
9231
9232 }
9233
9234 /**
9235  * clutter_actor_get_paint_opacity:
9236  * @self: A #ClutterActor
9237  *
9238  * Retrieves the absolute opacity of the actor, as it appears on the stage.
9239  *
9240  * This function traverses the hierarchy chain and composites the opacity of
9241  * the actor with that of its parents.
9242  *
9243  * This function is intended for subclasses to use in the paint virtual
9244  * function, to paint themselves with the correct opacity.
9245  *
9246  * Return value: The actor opacity value.
9247  *
9248  * Since: 0.8
9249  */
9250 guint8
9251 clutter_actor_get_paint_opacity (ClutterActor *self)
9252 {
9253   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9254
9255   return clutter_actor_get_paint_opacity_internal (self);
9256 }
9257
9258 /**
9259  * clutter_actor_get_opacity:
9260  * @self: a #ClutterActor
9261  *
9262  * Retrieves the opacity value of an actor, as set by
9263  * clutter_actor_set_opacity().
9264  *
9265  * For retrieving the absolute opacity of the actor inside a paint
9266  * virtual function, see clutter_actor_get_paint_opacity().
9267  *
9268  * Return value: the opacity of the actor
9269  */
9270 guint8
9271 clutter_actor_get_opacity (ClutterActor *self)
9272 {
9273   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9274
9275   return self->priv->opacity;
9276 }
9277
9278 /**
9279  * clutter_actor_set_offscreen_redirect:
9280  * @self: A #ClutterActor
9281  * @redirect: New offscreen redirect flags for the actor.
9282  *
9283  * Defines the circumstances where the actor should be redirected into
9284  * an offscreen image. The offscreen image is used to flatten the
9285  * actor into a single image while painting for two main reasons.
9286  * Firstly, when the actor is painted a second time without any of its
9287  * contents changing it can simply repaint the cached image without
9288  * descending further down the actor hierarchy. Secondly, it will make
9289  * the opacity look correct even if there are overlapping primitives
9290  * in the actor.
9291  *
9292  * Caching the actor could in some cases be a performance win and in
9293  * some cases be a performance lose so it is important to determine
9294  * which value is right for an actor before modifying this value. For
9295  * example, there is never any reason to flatten an actor that is just
9296  * a single texture (such as a #ClutterTexture) because it is
9297  * effectively already cached in an image so the offscreen would be
9298  * redundant. Also if the actor contains primitives that are far apart
9299  * with a large transparent area in the middle (such as a large
9300  * CluterGroup with a small actor in the top left and a small actor in
9301  * the bottom right) then the cached image will contain the entire
9302  * image of the large area and the paint will waste time blending all
9303  * of the transparent pixels in the middle.
9304  *
9305  * The default method of implementing opacity on a container simply
9306  * forwards on the opacity to all of the children. If the children are
9307  * overlapping then it will appear as if they are two separate glassy
9308  * objects and there will be a break in the color where they
9309  * overlap. By redirecting to an offscreen buffer it will be as if the
9310  * two opaque objects are combined into one and then made transparent
9311  * which is usually what is expected.
9312  *
9313  * The image below demonstrates the difference between redirecting and
9314  * not. The image shows two Clutter groups, each containing a red and
9315  * a green rectangle which overlap. The opacity on the group is set to
9316  * 128 (which is 50%). When the offscreen redirect is not used, the
9317  * red rectangle can be seen through the blue rectangle as if the two
9318  * rectangles were separately transparent. When the redirect is used
9319  * the group as a whole is transparent instead so the red rectangle is
9320  * not visible where they overlap.
9321  *
9322  * <figure id="offscreen-redirect">
9323  *   <title>Sample of using an offscreen redirect for transparency</title>
9324  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
9325  * </figure>
9326  *
9327  * The default value for this property is 0, so we effectively will
9328  * never redirect an actor offscreen by default. This means that there
9329  * are times that transparent actors may look glassy as described
9330  * above. The reason this is the default is because there is a
9331  * performance trade off between quality and performance here. In many
9332  * cases the default form of glassy opacity looks good enough, but if
9333  * it's not you will need to set the
9334  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9335  * redirection for opacity.
9336  *
9337  * Custom actors that don't contain any overlapping primitives are
9338  * recommended to override the has_overlaps() virtual to return %FALSE
9339  * for maximum efficiency.
9340  *
9341  * Since: 1.8
9342  */
9343 void
9344 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9345                                       ClutterOffscreenRedirect redirect)
9346 {
9347   ClutterActorPrivate *priv;
9348
9349   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9350
9351   priv = self->priv;
9352
9353   if (priv->offscreen_redirect != redirect)
9354     {
9355       priv->offscreen_redirect = redirect;
9356
9357       /* Queue a redraw from the effect so that it can use its cached
9358          image if available instead of having to redraw the actual
9359          actor. If it doesn't end up using the FBO then the effect is
9360          still able to continue the paint anyway. If there is no
9361          effect then this is equivalent to queuing a full redraw */
9362       _clutter_actor_queue_redraw_full (self,
9363                                         0, /* flags */
9364                                         NULL, /* clip */
9365                                         priv->flatten_effect);
9366
9367       g_object_notify_by_pspec (G_OBJECT (self),
9368                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
9369     }
9370 }
9371
9372 /**
9373  * clutter_actor_get_offscreen_redirect:
9374  * @self: a #ClutterActor
9375  *
9376  * Retrieves whether to redirect the actor to an offscreen buffer, as
9377  * set by clutter_actor_set_offscreen_redirect().
9378  *
9379  * Return value: the value of the offscreen-redirect property of the actor
9380  *
9381  * Since: 1.8
9382  */
9383 ClutterOffscreenRedirect
9384 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9385 {
9386   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9387
9388   return self->priv->offscreen_redirect;
9389 }
9390
9391 /**
9392  * clutter_actor_set_name:
9393  * @self: A #ClutterActor
9394  * @name: Textual tag to apply to actor
9395  *
9396  * Sets the given name to @self. The name can be used to identify
9397  * a #ClutterActor.
9398  */
9399 void
9400 clutter_actor_set_name (ClutterActor *self,
9401                         const gchar  *name)
9402 {
9403   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9404
9405   g_free (self->priv->name);
9406   self->priv->name = g_strdup (name);
9407
9408   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9409 }
9410
9411 /**
9412  * clutter_actor_get_name:
9413  * @self: A #ClutterActor
9414  *
9415  * Retrieves the name of @self.
9416  *
9417  * Return value: the name of the actor, or %NULL. The returned string is
9418  *   owned by the actor and should not be modified or freed.
9419  */
9420 const gchar *
9421 clutter_actor_get_name (ClutterActor *self)
9422 {
9423   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9424
9425   return self->priv->name;
9426 }
9427
9428 /**
9429  * clutter_actor_get_gid:
9430  * @self: A #ClutterActor
9431  *
9432  * Retrieves the unique id for @self.
9433  *
9434  * Return value: Globally unique value for this object instance.
9435  *
9436  * Since: 0.6
9437  *
9438  * Deprecated: 1.8: The id is not used any longer.
9439  */
9440 guint32
9441 clutter_actor_get_gid (ClutterActor *self)
9442 {
9443   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9444
9445   return self->priv->id;
9446 }
9447
9448 /**
9449  * clutter_actor_set_depth:
9450  * @self: a #ClutterActor
9451  * @depth: Z co-ord
9452  *
9453  * Sets the Z coordinate of @self to @depth.
9454  *
9455  * The unit used by @depth is dependant on the perspective setup. See
9456  * also clutter_stage_set_perspective().
9457  */
9458 void
9459 clutter_actor_set_depth (ClutterActor *self,
9460                          gfloat        depth)
9461 {
9462   ClutterActorPrivate *priv;
9463
9464   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9465
9466   priv = self->priv;
9467
9468   if (priv->z != depth)
9469     {
9470       /* Sets Z value - XXX 2.0: should we invert? */
9471       priv->z = depth;
9472
9473       priv->transform_valid = FALSE;
9474
9475       /* FIXME - remove this crap; sadly, there are still containers
9476        * in Clutter that depend on this utter brain damage
9477        */
9478       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9479
9480       clutter_actor_queue_redraw (self);
9481
9482       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9483     }
9484 }
9485
9486 /**
9487  * clutter_actor_get_depth:
9488  * @self: a #ClutterActor
9489  *
9490  * Retrieves the depth of @self.
9491  *
9492  * Return value: the depth of the actor
9493  */
9494 gfloat
9495 clutter_actor_get_depth (ClutterActor *self)
9496 {
9497   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
9498
9499   return self->priv->z;
9500 }
9501
9502 /**
9503  * clutter_actor_set_rotation:
9504  * @self: a #ClutterActor
9505  * @axis: the axis of rotation
9506  * @angle: the angle of rotation
9507  * @x: X coordinate of the rotation center
9508  * @y: Y coordinate of the rotation center
9509  * @z: Z coordinate of the rotation center
9510  *
9511  * Sets the rotation angle of @self around the given axis.
9512  *
9513  * The rotation center coordinates used depend on the value of @axis:
9514  * <itemizedlist>
9515  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
9516  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
9517  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
9518  * </itemizedlist>
9519  *
9520  * The rotation coordinates are relative to the anchor point of the
9521  * actor, set using clutter_actor_set_anchor_point(). If no anchor
9522  * point is set, the upper left corner is assumed as the origin.
9523  *
9524  * Since: 0.8
9525  */
9526 void
9527 clutter_actor_set_rotation (ClutterActor      *self,
9528                             ClutterRotateAxis  axis,
9529                             gdouble            angle,
9530                             gfloat             x,
9531                             gfloat             y,
9532                             gfloat             z)
9533 {
9534   ClutterVertex v;
9535
9536   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9537
9538   v.x = x;
9539   v.y = y;
9540   v.z = z;
9541
9542   g_object_freeze_notify (G_OBJECT (self));
9543
9544   clutter_actor_set_rotation_angle_internal (self, axis, angle);
9545   clutter_actor_set_rotation_center_internal (self, axis, &v);
9546
9547   g_object_thaw_notify (G_OBJECT (self));
9548 }
9549
9550 /**
9551  * clutter_actor_set_z_rotation_from_gravity:
9552  * @self: a #ClutterActor
9553  * @angle: the angle of rotation
9554  * @gravity: the center point of the rotation
9555  *
9556  * Sets the rotation angle of @self around the Z axis using the center
9557  * point specified as a compass point. For example to rotate such that
9558  * the center of the actor remains static you can use
9559  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
9560  * will move accordingly.
9561  *
9562  * Since: 1.0
9563  */
9564 void
9565 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
9566                                            gdouble         angle,
9567                                            ClutterGravity  gravity)
9568 {
9569   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9570
9571   if (gravity == CLUTTER_GRAVITY_NONE)
9572     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
9573   else
9574     {
9575       GObject *obj = G_OBJECT (self);
9576       ClutterTransformInfo *info;
9577
9578       info = _clutter_actor_get_transform_info (self);
9579
9580       g_object_freeze_notify (obj);
9581
9582       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
9583
9584       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
9585       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
9586       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
9587
9588       g_object_thaw_notify (obj);
9589     }
9590 }
9591
9592 /**
9593  * clutter_actor_get_rotation:
9594  * @self: a #ClutterActor
9595  * @axis: the axis of rotation
9596  * @x: (out): return value for the X coordinate of the center of rotation
9597  * @y: (out): return value for the Y coordinate of the center of rotation
9598  * @z: (out): return value for the Z coordinate of the center of rotation
9599  *
9600  * Retrieves the angle and center of rotation on the given axis,
9601  * set using clutter_actor_set_rotation().
9602  *
9603  * Return value: the angle of rotation
9604  *
9605  * Since: 0.8
9606  */
9607 gdouble
9608 clutter_actor_get_rotation (ClutterActor      *self,
9609                             ClutterRotateAxis  axis,
9610                             gfloat            *x,
9611                             gfloat            *y,
9612                             gfloat            *z)
9613 {
9614   const ClutterTransformInfo *info;
9615   const AnchorCoord *anchor_coord;
9616   gdouble retval = 0;
9617
9618   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9619
9620   info = _clutter_actor_get_transform_info_or_defaults (self);
9621
9622   switch (axis)
9623     {
9624     case CLUTTER_X_AXIS:
9625       anchor_coord = &info->rx_center;
9626       retval = info->rx_angle;
9627       break;
9628
9629     case CLUTTER_Y_AXIS:
9630       anchor_coord = &info->ry_center;
9631       retval = info->ry_angle;
9632       break;
9633
9634     case CLUTTER_Z_AXIS:
9635       anchor_coord = &info->rz_center;
9636       retval = info->rz_angle;
9637       break;
9638
9639     default:
9640       anchor_coord = NULL;
9641       retval = 0.0;
9642       break;
9643     }
9644
9645   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
9646
9647   return retval;
9648 }
9649
9650 /**
9651  * clutter_actor_get_z_rotation_gravity:
9652  * @self: A #ClutterActor
9653  *
9654  * Retrieves the center for the rotation around the Z axis as a
9655  * compass direction. If the center was specified in pixels or units
9656  * this will return %CLUTTER_GRAVITY_NONE.
9657  *
9658  * Return value: the Z rotation center
9659  *
9660  * Since: 1.0
9661  */
9662 ClutterGravity
9663 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
9664 {
9665   const ClutterTransformInfo *info;
9666
9667   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9668
9669   info = _clutter_actor_get_transform_info_or_defaults (self);
9670
9671   return clutter_anchor_coord_get_gravity (&info->rz_center);
9672 }
9673
9674 /**
9675  * clutter_actor_set_clip:
9676  * @self: A #ClutterActor
9677  * @xoff: X offset of the clip rectangle
9678  * @yoff: Y offset of the clip rectangle
9679  * @width: Width of the clip rectangle
9680  * @height: Height of the clip rectangle
9681  *
9682  * Sets clip area for @self. The clip area is always computed from the
9683  * upper left corner of the actor, even if the anchor point is set
9684  * otherwise.
9685  *
9686  * Since: 0.6
9687  */
9688 void
9689 clutter_actor_set_clip (ClutterActor *self,
9690                         gfloat        xoff,
9691                         gfloat        yoff,
9692                         gfloat        width,
9693                         gfloat        height)
9694 {
9695   ClutterActorPrivate *priv;
9696
9697   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9698
9699   priv = self->priv;
9700
9701   if (priv->has_clip &&
9702       priv->clip.x == xoff &&
9703       priv->clip.y == yoff &&
9704       priv->clip.width == width &&
9705       priv->clip.height == height)
9706     return;
9707
9708   priv->clip.x = xoff;
9709   priv->clip.y = yoff;
9710   priv->clip.width = width;
9711   priv->clip.height = height;
9712
9713   priv->has_clip = TRUE;
9714
9715   clutter_actor_queue_redraw (self);
9716
9717   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9718   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
9719 }
9720
9721 /**
9722  * clutter_actor_remove_clip:
9723  * @self: A #ClutterActor
9724  *
9725  * Removes clip area from @self.
9726  */
9727 void
9728 clutter_actor_remove_clip (ClutterActor *self)
9729 {
9730   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9731
9732   if (!self->priv->has_clip)
9733     return;
9734
9735   self->priv->has_clip = FALSE;
9736
9737   clutter_actor_queue_redraw (self);
9738
9739   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
9740 }
9741
9742 /**
9743  * clutter_actor_has_clip:
9744  * @self: a #ClutterActor
9745  *
9746  * Determines whether the actor has a clip area set or not.
9747  *
9748  * Return value: %TRUE if the actor has a clip area set.
9749  *
9750  * Since: 0.1.1
9751  */
9752 gboolean
9753 clutter_actor_has_clip (ClutterActor *self)
9754 {
9755   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9756
9757   return self->priv->has_clip;
9758 }
9759
9760 /**
9761  * clutter_actor_get_clip:
9762  * @self: a #ClutterActor
9763  * @xoff: (out) (allow-none): return location for the X offset of
9764  *   the clip rectangle, or %NULL
9765  * @yoff: (out) (allow-none): return location for the Y offset of
9766  *   the clip rectangle, or %NULL
9767  * @width: (out) (allow-none): return location for the width of
9768  *   the clip rectangle, or %NULL
9769  * @height: (out) (allow-none): return location for the height of
9770  *   the clip rectangle, or %NULL
9771  *
9772  * Gets the clip area for @self, if any is set
9773  *
9774  * Since: 0.6
9775  */
9776 void
9777 clutter_actor_get_clip (ClutterActor *self,
9778                         gfloat       *xoff,
9779                         gfloat       *yoff,
9780                         gfloat       *width,
9781                         gfloat       *height)
9782 {
9783   ClutterActorPrivate *priv;
9784
9785   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9786
9787   priv = self->priv;
9788
9789   if (!priv->has_clip)
9790     return;
9791
9792   if (xoff != NULL)
9793     *xoff = priv->clip.x;
9794
9795   if (yoff != NULL)
9796     *yoff = priv->clip.y;
9797
9798   if (width != NULL)
9799     *width = priv->clip.width;
9800
9801   if (height != NULL)
9802     *height = priv->clip.height;
9803 }
9804
9805 /**
9806  * clutter_actor_get_children:
9807  * @self: a #ClutterActor
9808  *
9809  * Retrieves the list of children of @self.
9810  *
9811  * Return value: (transfer container) (element-type ClutterActor): A newly
9812  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
9813  *   done.
9814  *
9815  * Since: 1.10
9816  */
9817 GList *
9818 clutter_actor_get_children (ClutterActor *self)
9819 {
9820   ClutterActor *iter;
9821   GList *res;
9822
9823   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9824
9825   /* we walk the list backward so that we can use prepend(),
9826    * which is O(1)
9827    */
9828   for (iter = self->priv->last_child, res = NULL;
9829        iter != NULL;
9830        iter = iter->priv->prev_sibling)
9831     {
9832       res = g_list_prepend (res, iter);
9833     }
9834
9835   return res;
9836 }
9837
9838 /*< private >
9839  * insert_child_at_depth:
9840  * @self: a #ClutterActor
9841  * @child: a #ClutterActor
9842  *
9843  * Inserts @child inside the list of children held by @self, using
9844  * the depth as the insertion criteria.
9845  *
9846  * This sadly makes the insertion not O(1), but we can keep the
9847  * list sorted so that the painters algorithm we use for painting
9848  * the children will work correctly.
9849  */
9850 static void
9851 insert_child_at_depth (ClutterActor *self,
9852                        ClutterActor *child,
9853                        gpointer      dummy G_GNUC_UNUSED)
9854 {
9855   ClutterActor *iter;
9856
9857   child->priv->parent = self;
9858
9859   /* special-case the first child */
9860   if (self->priv->n_children == 0)
9861     {
9862       self->priv->first_child = child;
9863       self->priv->last_child = child;
9864
9865       child->priv->next_sibling = NULL;
9866       child->priv->prev_sibling = NULL;
9867
9868       return;
9869     }
9870
9871   /* Find the right place to insert the child so that it will still be
9872      sorted and the child will be after all of the actors at the same
9873      dept */
9874   for (iter = self->priv->first_child;
9875        iter != NULL;
9876        iter = iter->priv->next_sibling)
9877     {
9878       if (iter->priv->z > child->priv->z)
9879         break;
9880     }
9881
9882   if (iter != NULL)
9883     {
9884       ClutterActor *tmp = iter->priv->prev_sibling;
9885
9886       if (tmp != NULL)
9887         tmp->priv->next_sibling = child;
9888
9889       /* Insert the node before the found one */
9890       child->priv->prev_sibling = iter->priv->prev_sibling;
9891       child->priv->next_sibling = iter;
9892       iter->priv->prev_sibling = child;
9893     }
9894   else
9895     {
9896       ClutterActor *tmp = self->priv->last_child;
9897
9898       if (tmp != NULL)
9899         tmp->priv->next_sibling = child;
9900
9901       /* insert the node at the end of the list */
9902       child->priv->prev_sibling = self->priv->last_child;
9903       child->priv->next_sibling = NULL;
9904     }
9905
9906   if (child->priv->prev_sibling == NULL)
9907     self->priv->first_child = child;
9908
9909   if (child->priv->next_sibling == NULL)
9910     self->priv->last_child = child;
9911 }
9912
9913 static void
9914 insert_child_at_index (ClutterActor *self,
9915                        ClutterActor *child,
9916                        gpointer      data_)
9917 {
9918   gint index_ = GPOINTER_TO_INT (data_);
9919
9920   child->priv->parent = self;
9921
9922   if (index_ == 0)
9923     {
9924       ClutterActor *tmp = self->priv->first_child;
9925
9926       if (tmp != NULL)
9927         tmp->priv->prev_sibling = child;
9928
9929       child->priv->prev_sibling = NULL;
9930       child->priv->next_sibling = tmp;
9931     }
9932   else if (index_ < 0 || index_ >= self->priv->n_children)
9933     {
9934       ClutterActor *tmp = self->priv->last_child;
9935
9936       if (tmp != NULL)
9937         tmp->priv->next_sibling = child;
9938
9939       child->priv->prev_sibling = tmp;
9940       child->priv->next_sibling = NULL;
9941     }
9942   else
9943     {
9944       ClutterActor *iter;
9945       int i;
9946
9947       for (iter = self->priv->first_child, i = 0;
9948            iter != NULL;
9949            iter = iter->priv->next_sibling, i += 1)
9950         {
9951           if (index_ == i)
9952             {
9953               ClutterActor *tmp = iter->priv->prev_sibling;
9954
9955               child->priv->prev_sibling = tmp;
9956               child->priv->next_sibling = iter;
9957
9958               iter->priv->prev_sibling = child;
9959
9960               if (tmp != NULL)
9961                 tmp->priv->next_sibling = child;
9962
9963               break;
9964             }
9965         }
9966     }
9967
9968   if (child->priv->prev_sibling == NULL)
9969     self->priv->first_child = child;
9970
9971   if (child->priv->next_sibling == NULL)
9972     self->priv->last_child = child;
9973 }
9974
9975 static void
9976 insert_child_above (ClutterActor *self,
9977                     ClutterActor *child,
9978                     gpointer      data)
9979 {
9980   ClutterActor *sibling = data;
9981
9982   child->priv->parent = self;
9983
9984   if (sibling == NULL)
9985     sibling = self->priv->last_child;
9986
9987   child->priv->prev_sibling = sibling;
9988
9989   if (sibling != NULL)
9990     {
9991       ClutterActor *tmp = sibling->priv->next_sibling;
9992
9993       child->priv->next_sibling = tmp;
9994
9995       if (tmp != NULL)
9996         tmp->priv->prev_sibling = child;
9997
9998       sibling->priv->next_sibling = child;
9999     }
10000   else
10001     child->priv->next_sibling = NULL;
10002
10003   if (child->priv->prev_sibling == NULL)
10004     self->priv->first_child = child;
10005
10006   if (child->priv->next_sibling == NULL)
10007     self->priv->last_child = child;
10008 }
10009
10010 static void
10011 insert_child_below (ClutterActor *self,
10012                     ClutterActor *child,
10013                     gpointer      data)
10014 {
10015   ClutterActor *sibling = data;
10016
10017   child->priv->parent = self;
10018
10019   if (sibling == NULL)
10020     sibling = self->priv->first_child;
10021
10022   child->priv->next_sibling = sibling;
10023
10024   if (sibling != NULL)
10025     {
10026       ClutterActor *tmp = sibling->priv->prev_sibling;
10027
10028       child->priv->prev_sibling = tmp;
10029
10030       if (tmp != NULL)
10031         tmp->priv->next_sibling = child;
10032
10033       sibling->priv->prev_sibling = child;
10034     }
10035   else
10036     child->priv->prev_sibling = NULL;
10037
10038   if (child->priv->prev_sibling == NULL)
10039     self->priv->first_child = child;
10040
10041   if (child->priv->next_sibling == NULL)
10042     self->priv->last_child = child;
10043 }
10044
10045 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10046                                            ClutterActor *child,
10047                                            gpointer      data);
10048
10049 typedef enum {
10050   ADD_CHILD_CREATE_META       = 1 << 0,
10051   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10052   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10053   ADD_CHILD_CHECK_STATE       = 1 << 3,
10054   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10055
10056   /* default flags for public API */
10057   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10058                                ADD_CHILD_EMIT_PARENT_SET |
10059                                ADD_CHILD_EMIT_ACTOR_ADDED |
10060                                ADD_CHILD_CHECK_STATE |
10061                                ADD_CHILD_NOTIFY_FIRST_LAST,
10062
10063   /* flags for legacy/deprecated API */
10064   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10065                                ADD_CHILD_CHECK_STATE |
10066                                ADD_CHILD_NOTIFY_FIRST_LAST
10067 } ClutterActorAddChildFlags;
10068
10069 /*< private >
10070  * clutter_actor_add_child_internal:
10071  * @self: a #ClutterActor
10072  * @child: a #ClutterActor
10073  * @flags: control flags for actions
10074  * @add_func: delegate function
10075  * @data: (closure): data to pass to @add_func
10076  *
10077  * Adds @child to the list of children of @self.
10078  *
10079  * The actual insertion inside the list is delegated to @add_func: this
10080  * function will just set up the state, perform basic checks, and emit
10081  * signals.
10082  *
10083  * The @flags argument is used to perform additional operations.
10084  */
10085 static inline void
10086 clutter_actor_add_child_internal (ClutterActor              *self,
10087                                   ClutterActor              *child,
10088                                   ClutterActorAddChildFlags  flags,
10089                                   ClutterActorAddChildFunc   add_func,
10090                                   gpointer                   data)
10091 {
10092   ClutterTextDirection text_dir;
10093   gboolean create_meta;
10094   gboolean emit_parent_set, emit_actor_added;
10095   gboolean check_state;
10096   gboolean notify_first_last;
10097   ClutterActor *old_first_child, *old_last_child;
10098
10099   if (child->priv->parent != NULL)
10100     {
10101       g_warning ("Cannot set a parent on an actor which has a parent. "
10102                  "You must use clutter_actor_remove_child() first.");
10103       return;
10104     }
10105
10106   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10107     {
10108       g_warning ("Cannot set a parent on a toplevel actor\n");
10109       return;
10110     }
10111
10112   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10113     {
10114       g_warning ("Cannot set a parent currently being destroyed");
10115       return;
10116     }
10117
10118   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10119   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10120   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10121   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10122   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10123
10124   old_first_child = self->priv->first_child;
10125   old_last_child = self->priv->last_child;
10126
10127   if (create_meta)
10128     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10129
10130   g_object_ref_sink (child);
10131   child->priv->parent = NULL;
10132   child->priv->next_sibling = NULL;
10133   child->priv->prev_sibling = NULL;
10134
10135   /* delegate the actual insertion */
10136   add_func (self, child, data);
10137
10138   g_assert (child->priv->parent == self);
10139
10140   self->priv->n_children += 1;
10141
10142   self->priv->age += 1;
10143
10144   /* if push_internal() has been called then we automatically set
10145    * the flag on the actor
10146    */
10147   if (self->priv->internal_child)
10148     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10149
10150   /* clutter_actor_reparent() will emit ::parent-set for us */
10151   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10152     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10153
10154   if (check_state)
10155     {
10156       /* If parent is mapped or realized, we need to also be mapped or
10157        * realized once we're inside the parent.
10158        */
10159       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10160
10161       /* propagate the parent's text direction to the child */
10162       text_dir = clutter_actor_get_text_direction (self);
10163       clutter_actor_set_text_direction (child, text_dir);
10164     }
10165
10166   if (child->priv->show_on_set_parent)
10167     clutter_actor_show (child);
10168
10169   if (CLUTTER_ACTOR_IS_MAPPED (child))
10170     clutter_actor_queue_redraw (child);
10171
10172   /* maintain the invariant that if an actor needs layout,
10173    * its parents do as well
10174    */
10175   if (child->priv->needs_width_request ||
10176       child->priv->needs_height_request ||
10177       child->priv->needs_allocation)
10178     {
10179       /* we work around the short-circuiting we do
10180        * in clutter_actor_queue_relayout() since we
10181        * want to force a relayout
10182        */
10183       child->priv->needs_width_request = TRUE;
10184       child->priv->needs_height_request = TRUE;
10185       child->priv->needs_allocation = TRUE;
10186
10187       clutter_actor_queue_relayout (child->priv->parent);
10188     }
10189
10190   if (emit_actor_added)
10191     g_signal_emit_by_name (self, "actor-added", child);
10192
10193   if (notify_first_last)
10194     {
10195       if (old_first_child != self->priv->first_child)
10196         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10197
10198       if (old_last_child != self->priv->last_child)
10199         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10200     }
10201 }
10202
10203 /**
10204  * clutter_actor_add_child:
10205  * @self: a #ClutterActor
10206  * @child: a #ClutterActor
10207  *
10208  * Adds @child to the children of @self.
10209  *
10210  * This function will acquire a reference on @child that will only
10211  * be released when calling clutter_actor_remove_child().
10212  *
10213  * This function will take into consideration the #ClutterActor:depth
10214  * of @child, and will keep the list of children sorted.
10215  *
10216  * This function will emit the #ClutterContainer::actor-added signal
10217  * on @self.
10218  *
10219  * Since: 1.10
10220  */
10221 void
10222 clutter_actor_add_child (ClutterActor *self,
10223                          ClutterActor *child)
10224 {
10225   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10226   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10227   g_return_if_fail (self != child);
10228   g_return_if_fail (child->priv->parent == NULL);
10229
10230   clutter_actor_add_child_internal (self, child,
10231                                     ADD_CHILD_DEFAULT_FLAGS,
10232                                     insert_child_at_depth,
10233                                     NULL);
10234 }
10235
10236 /**
10237  * clutter_actor_insert_child_at_index:
10238  * @self: a #ClutterActor
10239  * @child: a #ClutterActor
10240  * @index_: the index
10241  *
10242  * Inserts @child into the list of children of @self, using the
10243  * given @index_. If @index_ is greater than the number of children
10244  * in @self, or is less than 0, then the new child is added at the end.
10245  *
10246  * This function will acquire a reference on @child that will only
10247  * be released when calling clutter_actor_remove_child().
10248  *
10249  * This function will not take into consideration the #ClutterActor:depth
10250  * of @child.
10251  *
10252  * This function will emit the #ClutterContainer::actor-added signal
10253  * on @self.
10254  *
10255  * Since: 1.10
10256  */
10257 void
10258 clutter_actor_insert_child_at_index (ClutterActor *self,
10259                                      ClutterActor *child,
10260                                      gint          index_)
10261 {
10262   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10263   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10264   g_return_if_fail (self != child);
10265   g_return_if_fail (child->priv->parent == NULL);
10266
10267   clutter_actor_add_child_internal (self, child,
10268                                     ADD_CHILD_DEFAULT_FLAGS,
10269                                     insert_child_at_index,
10270                                     GINT_TO_POINTER (index_));
10271 }
10272
10273 /**
10274  * clutter_actor_insert_child_above:
10275  * @self: a #ClutterActor
10276  * @child: a #ClutterActor
10277  * @sibling: (allow-none): a child of @self, or %NULL
10278  *
10279  * Inserts @child into the list of children of @self, above another
10280  * child of @self or, if @sibling is %NULL, above all the children
10281  * of @self.
10282  *
10283  * This function will acquire a reference on @child that will only
10284  * be released when calling clutter_actor_remove_child().
10285  *
10286  * This function will not take into consideration the #ClutterActor:depth
10287  * of @child.
10288  *
10289  * This function will emit the #ClutterContainer::actor-added signal
10290  * on @self.
10291  *
10292  * Since: 1.10
10293  */
10294 void
10295 clutter_actor_insert_child_above (ClutterActor *self,
10296                                   ClutterActor *child,
10297                                   ClutterActor *sibling)
10298 {
10299   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10300   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10301   g_return_if_fail (self != child);
10302   g_return_if_fail (child != sibling);
10303   g_return_if_fail (child->priv->parent == NULL);
10304   g_return_if_fail (sibling == NULL ||
10305                     (CLUTTER_IS_ACTOR (sibling) &&
10306                      sibling->priv->parent == self));
10307
10308   clutter_actor_add_child_internal (self, child,
10309                                     ADD_CHILD_DEFAULT_FLAGS,
10310                                     insert_child_above,
10311                                     sibling);
10312 }
10313
10314 /**
10315  * clutter_actor_insert_child_below:
10316  * @self: a #ClutterActor
10317  * @child: a #ClutterActor
10318  * @sibling: (allow-none): a child of @self, or %NULL
10319  *
10320  * Inserts @child into the list of children of @self, below another
10321  * child of @self or, if @sibling is %NULL, below all the children
10322  * of @self.
10323  *
10324  * This function will acquire a reference on @child that will only
10325  * be released when calling clutter_actor_remove_child().
10326  *
10327  * This function will not take into consideration the #ClutterActor:depth
10328  * of @child.
10329  *
10330  * This function will emit the #ClutterContainer::actor-added signal
10331  * on @self.
10332  *
10333  * Since: 1.10
10334  */
10335 void
10336 clutter_actor_insert_child_below (ClutterActor *self,
10337                                   ClutterActor *child,
10338                                   ClutterActor *sibling)
10339 {
10340   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10341   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10342   g_return_if_fail (self != child);
10343   g_return_if_fail (child != sibling);
10344   g_return_if_fail (child->priv->parent == NULL);
10345   g_return_if_fail (sibling == NULL ||
10346                     (CLUTTER_IS_ACTOR (sibling) &&
10347                      sibling->priv->parent == self));
10348
10349   clutter_actor_add_child_internal (self, child,
10350                                     ADD_CHILD_DEFAULT_FLAGS,
10351                                     insert_child_below,
10352                                     sibling);
10353 }
10354
10355 /**
10356  * clutter_actor_set_parent:
10357  * @self: A #ClutterActor
10358  * @parent: A new #ClutterActor parent
10359  *
10360  * Sets the parent of @self to @parent.
10361  *
10362  * This function will result in @parent acquiring a reference on @self,
10363  * eventually by sinking its floating reference first. The reference
10364  * will be released by clutter_actor_unparent().
10365  *
10366  * This function should only be called by legacy #ClutterActor<!-- -->s
10367  * implementing the #ClutterContainer interface.
10368  *
10369  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10370  */
10371 void
10372 clutter_actor_set_parent (ClutterActor *self,
10373                           ClutterActor *parent)
10374 {
10375   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10376   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10377   g_return_if_fail (self != parent);
10378   g_return_if_fail (self->priv->parent == NULL);
10379
10380   /* as this function will be called inside ClutterContainer::add
10381    * implementations or when building up a composite actor, we have
10382    * to preserve the old behaviour, and not create child meta or
10383    * emit the ::actor-added signal, to avoid recursion or double
10384    * emissions
10385    */
10386   clutter_actor_add_child_internal (parent, self,
10387                                     ADD_CHILD_LEGACY_FLAGS,
10388                                     insert_child_at_depth,
10389                                     NULL);
10390 }
10391
10392 /**
10393  * clutter_actor_get_parent:
10394  * @self: A #ClutterActor
10395  *
10396  * Retrieves the parent of @self.
10397  *
10398  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10399  *  if no parent is set
10400  */
10401 ClutterActor *
10402 clutter_actor_get_parent (ClutterActor *self)
10403 {
10404   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10405
10406   return self->priv->parent;
10407 }
10408
10409 /**
10410  * clutter_actor_get_paint_visibility:
10411  * @self: A #ClutterActor
10412  *
10413  * Retrieves the 'paint' visibility of an actor recursively checking for non
10414  * visible parents.
10415  *
10416  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10417  *
10418  * Return Value: %TRUE if the actor is visibile and will be painted.
10419  *
10420  * Since: 0.8.4
10421  */
10422 gboolean
10423 clutter_actor_get_paint_visibility (ClutterActor *actor)
10424 {
10425   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10426
10427   return CLUTTER_ACTOR_IS_MAPPED (actor);
10428 }
10429
10430 /**
10431  * clutter_actor_remove_child:
10432  * @self: a #ClutterActor
10433  * @child: a #ClutterActor
10434  *
10435  * Removes @child from the children of @self.
10436  *
10437  * This function will release the reference added by
10438  * clutter_actor_add_child(), so if you want to keep using @child
10439  * you will have to acquire a referenced on it before calling this
10440  * function.
10441  *
10442  * This function will emit the #ClutterContainer::actor-removed
10443  * signal on @self.
10444  *
10445  * Since: 1.10
10446  */
10447 void
10448 clutter_actor_remove_child (ClutterActor *self,
10449                             ClutterActor *child)
10450 {
10451   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10452   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10453   g_return_if_fail (self != child);
10454   g_return_if_fail (child->priv->parent != NULL);
10455   g_return_if_fail (child->priv->parent == self);
10456
10457   clutter_actor_remove_child_internal (self, child,
10458                                        REMOVE_CHILD_DEFAULT_FLAGS);
10459 }
10460
10461 /**
10462  * clutter_actor_remove_all_children:
10463  * @self: a #ClutterActor
10464  *
10465  * Removes all children of @self.
10466  *
10467  * This function releases the reference added by inserting a child actor
10468  * in the list of children of @self.
10469  *
10470  * If the reference count of a child drops to zero, the child will be
10471  * destroyed. If you want to ensure the destruction of all the children
10472  * of @self, use clutter_actor_destroy_all_children().
10473  *
10474  * Since: 1.10
10475  */
10476 void
10477 clutter_actor_remove_all_children (ClutterActor *self)
10478 {
10479   ClutterActorIter iter;
10480
10481   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10482
10483   if (self->priv->n_children == 0)
10484     return;
10485
10486   clutter_actor_iter_init (&iter, self);
10487   while (clutter_actor_iter_next (&iter, NULL))
10488     clutter_actor_iter_remove (&iter);
10489
10490   /* sanity check */
10491   g_assert (self->priv->first_child == NULL);
10492   g_assert (self->priv->last_child == NULL);
10493   g_assert (self->priv->n_children == 0);
10494 }
10495
10496 /**
10497  * clutter_actor_destroy_all_children:
10498  * @self: a #ClutterActor
10499  *
10500  * Destroys all children of @self.
10501  *
10502  * This function releases the reference added by inserting a child
10503  * actor in the list of children of @self, and ensures that the
10504  * #ClutterActor::destroy signal is emitted on each child of the
10505  * actor.
10506  *
10507  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
10508  * when its reference count drops to 0; the default handler of the
10509  * #ClutterActor::destroy signal will destroy all the children of an
10510  * actor. This function ensures that all children are destroyed, instead
10511  * of just removed from @self, unlike clutter_actor_remove_all_children()
10512  * which will merely release the reference and remove each child.
10513  *
10514  * Unless you acquired an additional reference on each child of @self
10515  * prior to calling clutter_actor_remove_all_children() and want to reuse
10516  * the actors, you should use clutter_actor_destroy_all_children() in
10517  * order to make sure that children are destroyed and signal handlers
10518  * are disconnected even in cases where circular references prevent this
10519  * from automatically happening through reference counting alone.
10520  *
10521  * Since: 1.10
10522  */
10523 void
10524 clutter_actor_destroy_all_children (ClutterActor *self)
10525 {
10526   ClutterActorIter iter;
10527
10528   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10529
10530   if (self->priv->n_children == 0)
10531     return;
10532
10533   clutter_actor_iter_init (&iter, self);
10534   while (clutter_actor_iter_next (&iter, NULL))
10535     clutter_actor_iter_destroy (&iter);
10536
10537   /* sanity check */
10538   g_assert (self->priv->first_child == NULL);
10539   g_assert (self->priv->last_child == NULL);
10540   g_assert (self->priv->n_children == 0);
10541 }
10542
10543 typedef struct _InsertBetweenData {
10544   ClutterActor *prev_sibling;
10545   ClutterActor *next_sibling;
10546 } InsertBetweenData;
10547
10548 static void
10549 insert_child_between (ClutterActor *self,
10550                       ClutterActor *child,
10551                       gpointer      data_)
10552 {
10553   InsertBetweenData *data = data_;
10554   ClutterActor *prev_sibling = data->prev_sibling;
10555   ClutterActor *next_sibling = data->next_sibling;
10556
10557   child->priv->parent = self;
10558   child->priv->prev_sibling = prev_sibling;
10559   child->priv->next_sibling = next_sibling;
10560
10561   if (prev_sibling != NULL)
10562     prev_sibling->priv->next_sibling = child;
10563
10564   if (next_sibling != NULL)
10565     next_sibling->priv->prev_sibling = child;
10566
10567   if (child->priv->prev_sibling == NULL)
10568     self->priv->first_child = child;
10569
10570   if (child->priv->next_sibling == NULL)
10571     self->priv->last_child = child;
10572 }
10573
10574 /**
10575  * clutter_actor_replace_child:
10576  * @self: a #ClutterActor
10577  * @old_child: the child of @self to replace
10578  * @new_child: the #ClutterActor to replace @old_child
10579  *
10580  * Replaces @old_child with @new_child in the list of children of @self.
10581  *
10582  * Since: 1.10
10583  */
10584 void
10585 clutter_actor_replace_child (ClutterActor *self,
10586                              ClutterActor *old_child,
10587                              ClutterActor *new_child)
10588 {
10589   ClutterActor *prev_sibling, *next_sibling;
10590   InsertBetweenData clos;
10591
10592   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10593   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
10594   g_return_if_fail (old_child->priv->parent == self);
10595   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
10596   g_return_if_fail (old_child != new_child);
10597   g_return_if_fail (new_child != self);
10598   g_return_if_fail (new_child->priv->parent == NULL);
10599
10600   prev_sibling = old_child->priv->prev_sibling;
10601   next_sibling = old_child->priv->next_sibling;
10602   clutter_actor_remove_child_internal (self, old_child,
10603                                        REMOVE_CHILD_DEFAULT_FLAGS);
10604
10605   clos.prev_sibling = prev_sibling;
10606   clos.next_sibling = next_sibling;
10607   clutter_actor_add_child_internal (self, new_child,
10608                                     ADD_CHILD_DEFAULT_FLAGS,
10609                                     insert_child_between,
10610                                     &clos);
10611 }
10612
10613 /**
10614  * clutter_actor_unparent:
10615  * @self: a #ClutterActor
10616  *
10617  * Removes the parent of @self.
10618  *
10619  * This will cause the parent of @self to release the reference
10620  * acquired when calling clutter_actor_set_parent(), so if you
10621  * want to keep @self you will have to acquire a reference of
10622  * your own, through g_object_ref().
10623  *
10624  * This function should only be called by legacy #ClutterActor<!-- -->s
10625  * implementing the #ClutterContainer interface.
10626  *
10627  * Since: 0.1.1
10628  *
10629  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
10630  */
10631 void
10632 clutter_actor_unparent (ClutterActor *self)
10633 {
10634   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10635
10636   if (self->priv->parent == NULL)
10637     return;
10638
10639   clutter_actor_remove_child_internal (self->priv->parent, self,
10640                                        REMOVE_CHILD_LEGACY_FLAGS);
10641 }
10642
10643 /**
10644  * clutter_actor_reparent:
10645  * @self: a #ClutterActor
10646  * @new_parent: the new #ClutterActor parent
10647  *
10648  * Resets the parent actor of @self.
10649  *
10650  * This function is logically equivalent to calling clutter_actor_unparent()
10651  * and clutter_actor_set_parent(), but more efficiently implemented, as it
10652  * ensures the child is not finalized when unparented, and emits the
10653  * #ClutterActor::parent-set signal only once.
10654  *
10655  * In reality, calling this function is less useful than it sounds, as some
10656  * application code may rely on changes in the intermediate state between
10657  * removal and addition of the actor from its old parent to the @new_parent.
10658  * Thus, it is strongly encouraged to avoid using this function in application
10659  * code.
10660  *
10661  * Since: 0.2
10662  *
10663  * Deprecated: 1.10: Use clutter_actor_remove_child() and
10664  *   clutter_actor_add_child() instead; remember to take a reference on
10665  *   the actor being removed before calling clutter_actor_remove_child()
10666  *   to avoid the reference count dropping to zero and the actor being
10667  *   destroyed.
10668  */
10669 void
10670 clutter_actor_reparent (ClutterActor *self,
10671                         ClutterActor *new_parent)
10672 {
10673   ClutterActorPrivate *priv;
10674
10675   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10676   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
10677   g_return_if_fail (self != new_parent);
10678
10679   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10680     {
10681       g_warning ("Cannot set a parent on a toplevel actor");
10682       return;
10683     }
10684
10685   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
10686     {
10687       g_warning ("Cannot set a parent currently being destroyed");
10688       return;
10689     }
10690
10691   priv = self->priv;
10692
10693   if (priv->parent != new_parent)
10694     {
10695       ClutterActor *old_parent;
10696
10697       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10698
10699       old_parent = priv->parent;
10700
10701       g_object_ref (self);
10702
10703       if (old_parent != NULL)
10704         {
10705          /* go through the Container implementation if this is a regular
10706           * child and not an internal one
10707           */
10708          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10709            {
10710              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
10711
10712              /* this will have to call unparent() */
10713              clutter_container_remove_actor (parent, self);
10714            }
10715          else
10716            clutter_actor_remove_child_internal (old_parent, self,
10717                                                 REMOVE_CHILD_LEGACY_FLAGS);
10718         }
10719
10720       /* Note, will call set_parent() */
10721       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
10722         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
10723       else
10724         clutter_actor_add_child_internal (new_parent, self,
10725                                           ADD_CHILD_LEGACY_FLAGS,
10726                                           insert_child_at_depth,
10727                                           NULL);
10728
10729       /* we emit the ::parent-set signal once */
10730       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
10731
10732       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
10733
10734       /* the IN_REPARENT flag suspends state updates */
10735       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
10736
10737       g_object_unref (self);
10738    }
10739 }
10740
10741 /**
10742  * clutter_actor_contains:
10743  * @self: A #ClutterActor
10744  * @descendant: A #ClutterActor, possibly contained in @self
10745  *
10746  * Determines if @descendant is contained inside @self (either as an
10747  * immediate child, or as a deeper descendant). If @self and
10748  * @descendant point to the same actor then it will also return %TRUE.
10749  *
10750  * Return value: whether @descendent is contained within @self
10751  *
10752  * Since: 1.4
10753  */
10754 gboolean
10755 clutter_actor_contains (ClutterActor *self,
10756                         ClutterActor *descendant)
10757 {
10758   ClutterActor *actor;
10759
10760   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10761   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
10762
10763   for (actor = descendant; actor; actor = actor->priv->parent)
10764     if (actor == self)
10765       return TRUE;
10766
10767   return FALSE;
10768 }
10769
10770 /**
10771  * clutter_actor_set_child_above_sibling:
10772  * @self: a #ClutterActor
10773  * @child: a #ClutterActor child of @self
10774  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10775  *
10776  * Sets @child to be above @sibling in the list of children of @self.
10777  *
10778  * If @sibling is %NULL, @child will be the new last child of @self.
10779  *
10780  * This function is logically equivalent to removing @child and using
10781  * clutter_actor_insert_child_above(), but it will not emit signals
10782  * or change state on @child.
10783  *
10784  * Since: 1.10
10785  */
10786 void
10787 clutter_actor_set_child_above_sibling (ClutterActor *self,
10788                                        ClutterActor *child,
10789                                        ClutterActor *sibling)
10790 {
10791   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10792   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10793   g_return_if_fail (child->priv->parent == self);
10794   g_return_if_fail (child != sibling);
10795   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10796
10797   if (sibling != NULL)
10798     g_return_if_fail (sibling->priv->parent == self);
10799
10800   /* we don't want to change the state of child, or emit signals, or
10801    * regenerate ChildMeta instances here, but we still want to follow
10802    * the correct sequence of steps encoded in remove_child() and
10803    * add_child(), so that correctness is ensured, and we only go
10804    * through one known code path.
10805    */
10806   g_object_ref (child);
10807   clutter_actor_remove_child_internal (self, child, 0);
10808   clutter_actor_add_child_internal (self, child,
10809                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10810                                     insert_child_above,
10811                                     sibling);
10812
10813   clutter_actor_queue_relayout (self);
10814 }
10815
10816 /**
10817  * clutter_actor_set_child_below_sibling:
10818  * @self: a #ClutterActor
10819  * @child: a #ClutterActor child of @self
10820  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
10821  *
10822  * Sets @child to be below @sibling in the list of children of @self.
10823  *
10824  * If @sibling is %NULL, @child will be the new first child of @self.
10825  *
10826  * This function is logically equivalent to removing @self and using
10827  * clutter_actor_insert_child_below(), but it will not emit signals
10828  * or change state on @child.
10829  *
10830  * Since: 1.10
10831  */
10832 void
10833 clutter_actor_set_child_below_sibling (ClutterActor *self,
10834                                        ClutterActor *child,
10835                                        ClutterActor *sibling)
10836 {
10837   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10838   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10839   g_return_if_fail (child->priv->parent == self);
10840   g_return_if_fail (child != sibling);
10841   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
10842
10843   if (sibling != NULL)
10844     g_return_if_fail (sibling->priv->parent == self);
10845
10846   /* see the comment in set_child_above_sibling() */
10847   g_object_ref (child);
10848   clutter_actor_remove_child_internal (self, child, 0);
10849   clutter_actor_add_child_internal (self, child,
10850                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10851                                     insert_child_below,
10852                                     sibling);
10853
10854   clutter_actor_queue_relayout (self);
10855 }
10856
10857 /**
10858  * clutter_actor_set_child_at_index:
10859  * @self: a #ClutterActor
10860  * @child: a #ClutterActor child of @self
10861  * @index_: the new index for @child
10862  *
10863  * Changes the index of @child in the list of children of @self.
10864  *
10865  * This function is logically equivalent to removing @child and
10866  * calling clutter_actor_insert_child_at_index(), but it will not
10867  * emit signals or change state on @child.
10868  *
10869  * Since: 1.10
10870  */
10871 void
10872 clutter_actor_set_child_at_index (ClutterActor *self,
10873                                   ClutterActor *child,
10874                                   gint          index_)
10875 {
10876   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10877   g_return_if_fail (CLUTTER_IS_ACTOR (child));
10878   g_return_if_fail (child->priv->parent == self);
10879   g_return_if_fail (index_ <= self->priv->n_children);
10880
10881   g_object_ref (child);
10882   clutter_actor_remove_child_internal (self, child, 0);
10883   clutter_actor_add_child_internal (self, child,
10884                                     ADD_CHILD_NOTIFY_FIRST_LAST,
10885                                     insert_child_at_index,
10886                                     GINT_TO_POINTER (index_));
10887
10888   clutter_actor_queue_relayout (self);
10889 }
10890
10891 /**
10892  * clutter_actor_raise:
10893  * @self: A #ClutterActor
10894  * @below: (allow-none): A #ClutterActor to raise above.
10895  *
10896  * Puts @self above @below.
10897  *
10898  * Both actors must have the same parent, and the parent must implement
10899  * the #ClutterContainer interface
10900  *
10901  * This function calls clutter_container_raise_child() internally.
10902  *
10903  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
10904  */
10905 void
10906 clutter_actor_raise (ClutterActor *self,
10907                      ClutterActor *below)
10908 {
10909   ClutterActor *parent;
10910
10911   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10912
10913   parent = clutter_actor_get_parent (self);
10914   if (parent == NULL)
10915     {
10916       g_warning ("%s: Actor '%s' is not inside a container",
10917                  G_STRFUNC,
10918                  _clutter_actor_get_debug_name (self));
10919       return;
10920     }
10921
10922   if (below != NULL)
10923     {
10924       if (parent != clutter_actor_get_parent (below))
10925         {
10926           g_warning ("%s Actor '%s' is not in the same container as "
10927                      "actor '%s'",
10928                      G_STRFUNC,
10929                      _clutter_actor_get_debug_name (self),
10930                      _clutter_actor_get_debug_name (below));
10931           return;
10932         }
10933     }
10934
10935   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
10936 }
10937
10938 /**
10939  * clutter_actor_lower:
10940  * @self: A #ClutterActor
10941  * @above: (allow-none): A #ClutterActor to lower below
10942  *
10943  * Puts @self below @above.
10944  *
10945  * Both actors must have the same parent, and the parent must implement
10946  * the #ClutterContainer interface.
10947  *
10948  * This function calls clutter_container_lower_child() internally.
10949  *
10950  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
10951  */
10952 void
10953 clutter_actor_lower (ClutterActor *self,
10954                      ClutterActor *above)
10955 {
10956   ClutterActor *parent;
10957
10958   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10959
10960   parent = clutter_actor_get_parent (self);
10961   if (parent == NULL)
10962     {
10963       g_warning ("%s: Actor of type %s is not inside a container",
10964                  G_STRFUNC,
10965                  _clutter_actor_get_debug_name (self));
10966       return;
10967     }
10968
10969   if (above)
10970     {
10971       if (parent != clutter_actor_get_parent (above))
10972         {
10973           g_warning ("%s: Actor '%s' is not in the same container as "
10974                      "actor '%s'",
10975                      G_STRFUNC,
10976                      _clutter_actor_get_debug_name (self),
10977                      _clutter_actor_get_debug_name (above));
10978           return;
10979         }
10980     }
10981
10982   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
10983 }
10984
10985 /**
10986  * clutter_actor_raise_top:
10987  * @self: A #ClutterActor
10988  *
10989  * Raises @self to the top.
10990  *
10991  * This function calls clutter_actor_raise() internally.
10992  *
10993  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
10994  *   a %NULL sibling, instead.
10995  */
10996 void
10997 clutter_actor_raise_top (ClutterActor *self)
10998 {
10999   clutter_actor_raise (self, NULL);
11000 }
11001
11002 /**
11003  * clutter_actor_lower_bottom:
11004  * @self: A #ClutterActor
11005  *
11006  * Lowers @self to the bottom.
11007  *
11008  * This function calls clutter_actor_lower() internally.
11009  *
11010  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11011  *   a %NULL sibling, instead.
11012  */
11013 void
11014 clutter_actor_lower_bottom (ClutterActor *self)
11015 {
11016   clutter_actor_lower (self, NULL);
11017 }
11018
11019 /*
11020  * Event handling
11021  */
11022
11023 /**
11024  * clutter_actor_event:
11025  * @actor: a #ClutterActor
11026  * @event: a #ClutterEvent
11027  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11028  *
11029  * This function is used to emit an event on the main stage.
11030  * You should rarely need to use this function, except for
11031  * synthetising events.
11032  *
11033  * Return value: the return value from the signal emission: %TRUE
11034  *   if the actor handled the event, or %FALSE if the event was
11035  *   not handled
11036  *
11037  * Since: 0.6
11038  */
11039 gboolean
11040 clutter_actor_event (ClutterActor *actor,
11041                      ClutterEvent *event,
11042                      gboolean      capture)
11043 {
11044   gboolean retval = FALSE;
11045   gint signal_num = -1;
11046
11047   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11048   g_return_val_if_fail (event != NULL, FALSE);
11049
11050   g_object_ref (actor);
11051
11052   if (capture)
11053     {
11054       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11055                      event,
11056                      &retval);
11057       goto out;
11058     }
11059
11060   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11061
11062   if (!retval)
11063     {
11064       switch (event->type)
11065         {
11066         case CLUTTER_NOTHING:
11067           break;
11068         case CLUTTER_BUTTON_PRESS:
11069           signal_num = BUTTON_PRESS_EVENT;
11070           break;
11071         case CLUTTER_BUTTON_RELEASE:
11072           signal_num = BUTTON_RELEASE_EVENT;
11073           break;
11074         case CLUTTER_SCROLL:
11075           signal_num = SCROLL_EVENT;
11076           break;
11077         case CLUTTER_KEY_PRESS:
11078           signal_num = KEY_PRESS_EVENT;
11079           break;
11080         case CLUTTER_KEY_RELEASE:
11081           signal_num = KEY_RELEASE_EVENT;
11082           break;
11083         case CLUTTER_MOTION:
11084           signal_num = MOTION_EVENT;
11085           break;
11086         case CLUTTER_ENTER:
11087           signal_num = ENTER_EVENT;
11088           break;
11089         case CLUTTER_LEAVE:
11090           signal_num = LEAVE_EVENT;
11091           break;
11092         case CLUTTER_DELETE:
11093         case CLUTTER_DESTROY_NOTIFY:
11094         case CLUTTER_CLIENT_MESSAGE:
11095         default:
11096           signal_num = -1;
11097           break;
11098         }
11099
11100       if (signal_num != -1)
11101         g_signal_emit (actor, actor_signals[signal_num], 0,
11102                        event, &retval);
11103     }
11104
11105 out:
11106   g_object_unref (actor);
11107
11108   return retval;
11109 }
11110
11111 /**
11112  * clutter_actor_set_reactive:
11113  * @actor: a #ClutterActor
11114  * @reactive: whether the actor should be reactive to events
11115  *
11116  * Sets @actor as reactive. Reactive actors will receive events.
11117  *
11118  * Since: 0.6
11119  */
11120 void
11121 clutter_actor_set_reactive (ClutterActor *actor,
11122                             gboolean      reactive)
11123 {
11124   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11125
11126   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11127     return;
11128
11129   if (reactive)
11130     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11131   else
11132     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11133
11134   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11135 }
11136
11137 /**
11138  * clutter_actor_get_reactive:
11139  * @actor: a #ClutterActor
11140  *
11141  * Checks whether @actor is marked as reactive.
11142  *
11143  * Return value: %TRUE if the actor is reactive
11144  *
11145  * Since: 0.6
11146  */
11147 gboolean
11148 clutter_actor_get_reactive (ClutterActor *actor)
11149 {
11150   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11151
11152   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11153 }
11154
11155 /**
11156  * clutter_actor_get_anchor_point:
11157  * @self: a #ClutterActor
11158  * @anchor_x: (out): return location for the X coordinate of the anchor point
11159  * @anchor_y: (out): return location for the Y coordinate of the anchor point
11160  *
11161  * Gets the current anchor point of the @actor in pixels.
11162  *
11163  * Since: 0.6
11164  */
11165 void
11166 clutter_actor_get_anchor_point (ClutterActor *self,
11167                                 gfloat       *anchor_x,
11168                                 gfloat       *anchor_y)
11169 {
11170   const ClutterTransformInfo *info;
11171
11172   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11173
11174   info = _clutter_actor_get_transform_info_or_defaults (self);
11175   clutter_anchor_coord_get_units (self, &info->anchor,
11176                                   anchor_x,
11177                                   anchor_y,
11178                                   NULL);
11179 }
11180
11181 /**
11182  * clutter_actor_set_anchor_point:
11183  * @self: a #ClutterActor
11184  * @anchor_x: X coordinate of the anchor point
11185  * @anchor_y: Y coordinate of the anchor point
11186  *
11187  * Sets an anchor point for @self. The anchor point is a point in the
11188  * coordinate space of an actor to which the actor position within its
11189  * parent is relative; the default is (0, 0), i.e. the top-left corner
11190  * of the actor.
11191  *
11192  * Since: 0.6
11193  */
11194 void
11195 clutter_actor_set_anchor_point (ClutterActor *self,
11196                                 gfloat        anchor_x,
11197                                 gfloat        anchor_y)
11198 {
11199   ClutterTransformInfo *info;
11200   ClutterActorPrivate *priv;
11201   gboolean changed = FALSE;
11202   gfloat old_anchor_x, old_anchor_y;
11203   GObject *obj;
11204
11205   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11206
11207   obj = G_OBJECT (self);
11208   priv = self->priv;
11209   info = _clutter_actor_get_transform_info (self);
11210
11211   g_object_freeze_notify (obj);
11212
11213   clutter_anchor_coord_get_units (self, &info->anchor,
11214                                   &old_anchor_x,
11215                                   &old_anchor_y,
11216                                   NULL);
11217
11218   if (info->anchor.is_fractional)
11219     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11220
11221   if (old_anchor_x != anchor_x)
11222     {
11223       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11224       changed = TRUE;
11225     }
11226
11227   if (old_anchor_y != anchor_y)
11228     {
11229       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11230       changed = TRUE;
11231     }
11232
11233   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11234
11235   if (changed)
11236     {
11237       priv->transform_valid = FALSE;
11238       clutter_actor_queue_redraw (self);
11239     }
11240
11241   g_object_thaw_notify (obj);
11242 }
11243
11244 /**
11245  * clutter_actor_get_anchor_point_gravity:
11246  * @self: a #ClutterActor
11247  *
11248  * Retrieves the anchor position expressed as a #ClutterGravity. If
11249  * the anchor point was specified using pixels or units this will
11250  * return %CLUTTER_GRAVITY_NONE.
11251  *
11252  * Return value: the #ClutterGravity used by the anchor point
11253  *
11254  * Since: 1.0
11255  */
11256 ClutterGravity
11257 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11258 {
11259   const ClutterTransformInfo *info;
11260
11261   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11262
11263   info = _clutter_actor_get_transform_info_or_defaults (self);
11264
11265   return clutter_anchor_coord_get_gravity (&info->anchor);
11266 }
11267
11268 /**
11269  * clutter_actor_move_anchor_point:
11270  * @self: a #ClutterActor
11271  * @anchor_x: X coordinate of the anchor point
11272  * @anchor_y: Y coordinate of the anchor point
11273  *
11274  * Sets an anchor point for the actor, and adjusts the actor postion so that
11275  * the relative position of the actor toward its parent remains the same.
11276  *
11277  * Since: 0.6
11278  */
11279 void
11280 clutter_actor_move_anchor_point (ClutterActor *self,
11281                                  gfloat        anchor_x,
11282                                  gfloat        anchor_y)
11283 {
11284   gfloat old_anchor_x, old_anchor_y;
11285   const ClutterTransformInfo *info;
11286
11287   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11288
11289   info = _clutter_actor_get_transform_info (self);
11290   clutter_anchor_coord_get_units (self, &info->anchor,
11291                                   &old_anchor_x,
11292                                   &old_anchor_y,
11293                                   NULL);
11294
11295   g_object_freeze_notify (G_OBJECT (self));
11296
11297   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11298
11299   if (self->priv->position_set)
11300     clutter_actor_move_by (self,
11301                            anchor_x - old_anchor_x,
11302                            anchor_y - old_anchor_y);
11303
11304   g_object_thaw_notify (G_OBJECT (self));
11305 }
11306
11307 /**
11308  * clutter_actor_move_anchor_point_from_gravity:
11309  * @self: a #ClutterActor
11310  * @gravity: #ClutterGravity.
11311  *
11312  * Sets an anchor point on the actor based on the given gravity, adjusting the
11313  * actor postion so that its relative position within its parent remains
11314  * unchanged.
11315  *
11316  * Since version 1.0 the anchor point will be stored as a gravity so
11317  * that if the actor changes size then the anchor point will move. For
11318  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11319  * and later double the size of the actor, the anchor point will move
11320  * to the bottom right.
11321  *
11322  * Since: 0.6
11323  */
11324 void
11325 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
11326                                               ClutterGravity  gravity)
11327 {
11328   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11329   const ClutterTransformInfo *info;
11330   ClutterActorPrivate *priv;
11331
11332   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11333
11334   priv = self->priv;
11335   info = _clutter_actor_get_transform_info (self);
11336
11337   g_object_freeze_notify (G_OBJECT (self));
11338
11339   clutter_anchor_coord_get_units (self, &info->anchor,
11340                                   &old_anchor_x,
11341                                   &old_anchor_y,
11342                                   NULL);
11343   clutter_actor_set_anchor_point_from_gravity (self, gravity);
11344   clutter_anchor_coord_get_units (self, &info->anchor,
11345                                   &new_anchor_x,
11346                                   &new_anchor_y,
11347                                   NULL);
11348
11349   if (priv->position_set)
11350     clutter_actor_move_by (self,
11351                            new_anchor_x - old_anchor_x,
11352                            new_anchor_y - old_anchor_y);
11353
11354   g_object_thaw_notify (G_OBJECT (self));
11355 }
11356
11357 /**
11358  * clutter_actor_set_anchor_point_from_gravity:
11359  * @self: a #ClutterActor
11360  * @gravity: #ClutterGravity.
11361  *
11362  * Sets an anchor point on the actor, based on the given gravity (this is a
11363  * convenience function wrapping clutter_actor_set_anchor_point()).
11364  *
11365  * Since version 1.0 the anchor point will be stored as a gravity so
11366  * that if the actor changes size then the anchor point will move. For
11367  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11368  * and later double the size of the actor, the anchor point will move
11369  * to the bottom right.
11370  *
11371  * Since: 0.6
11372  */
11373 void
11374 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
11375                                              ClutterGravity  gravity)
11376 {
11377   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11378
11379   if (gravity == CLUTTER_GRAVITY_NONE)
11380     clutter_actor_set_anchor_point (self, 0, 0);
11381   else
11382     {
11383       GObject *obj = G_OBJECT (self);
11384       ClutterTransformInfo *info;
11385
11386       g_object_freeze_notify (obj);
11387
11388       info = _clutter_actor_get_transform_info (self);
11389       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11390
11391       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11392       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11393       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11394
11395       self->priv->transform_valid = FALSE;
11396
11397       clutter_actor_queue_redraw (self);
11398
11399       g_object_thaw_notify (obj);
11400     }
11401 }
11402
11403 static void
11404 clutter_container_iface_init (ClutterContainerIface *iface)
11405 {
11406   /* we don't override anything, as ClutterContainer already has a default
11407    * implementation that we can use, and which calls into our own API.
11408    */
11409 }
11410
11411 typedef enum
11412 {
11413   PARSE_X,
11414   PARSE_Y,
11415   PARSE_WIDTH,
11416   PARSE_HEIGHT,
11417   PARSE_ANCHOR_X,
11418   PARSE_ANCHOR_Y
11419 } ParseDimension;
11420
11421 static gfloat
11422 parse_units (ClutterActor   *self,
11423              ParseDimension  dimension,
11424              JsonNode       *node)
11425 {
11426   GValue value = { 0, };
11427   gfloat retval = 0;
11428
11429   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11430     return 0;
11431
11432   json_node_get_value (node, &value);
11433
11434   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11435     {
11436       retval = (gfloat) g_value_get_int64 (&value);
11437     }
11438   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
11439     {
11440       retval = g_value_get_double (&value);
11441     }
11442   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
11443     {
11444       ClutterUnits units;
11445       gboolean res;
11446
11447       res = clutter_units_from_string (&units, g_value_get_string (&value));
11448       if (res)
11449         retval = clutter_units_to_pixels (&units);
11450       else
11451         {
11452           g_warning ("Invalid value '%s': integers, strings or floating point "
11453                      "values can be used for the x, y, width and height "
11454                      "properties. Valid modifiers for strings are 'px', 'mm', "
11455                      "'pt' and 'em'.",
11456                      g_value_get_string (&value));
11457           retval = 0;
11458         }
11459     }
11460   else
11461     {
11462       g_warning ("Invalid value of type '%s': integers, strings of floating "
11463                  "point values can be used for the x, y, width, height "
11464                  "anchor-x and anchor-y properties.",
11465                  g_type_name (G_VALUE_TYPE (&value)));
11466     }
11467
11468   g_value_unset (&value);
11469
11470   return retval;
11471 }
11472
11473 typedef struct {
11474   ClutterRotateAxis axis;
11475
11476   gdouble angle;
11477
11478   gfloat center_x;
11479   gfloat center_y;
11480   gfloat center_z;
11481 } RotationInfo;
11482
11483 static inline gboolean
11484 parse_rotation_array (ClutterActor *actor,
11485                       JsonArray    *array,
11486                       RotationInfo *info)
11487 {
11488   JsonNode *element;
11489
11490   if (json_array_get_length (array) != 2)
11491     return FALSE;
11492
11493   /* angle */
11494   element = json_array_get_element (array, 0);
11495   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
11496     info->angle = json_node_get_double (element);
11497   else
11498     return FALSE;
11499
11500   /* center */
11501   element = json_array_get_element (array, 1);
11502   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
11503     {
11504       JsonArray *center = json_node_get_array (element);
11505
11506       if (json_array_get_length (center) != 2)
11507         return FALSE;
11508
11509       switch (info->axis)
11510         {
11511         case CLUTTER_X_AXIS:
11512           info->center_y = parse_units (actor, PARSE_Y,
11513                                         json_array_get_element (center, 0));
11514           info->center_z = parse_units (actor, PARSE_Y,
11515                                         json_array_get_element (center, 1));
11516           return TRUE;
11517
11518         case CLUTTER_Y_AXIS:
11519           info->center_x = parse_units (actor, PARSE_X,
11520                                         json_array_get_element (center, 0));
11521           info->center_z = parse_units (actor, PARSE_X,
11522                                         json_array_get_element (center, 1));
11523           return TRUE;
11524
11525         case CLUTTER_Z_AXIS:
11526           info->center_x = parse_units (actor, PARSE_X,
11527                                         json_array_get_element (center, 0));
11528           info->center_y = parse_units (actor, PARSE_Y,
11529                                         json_array_get_element (center, 1));
11530           return TRUE;
11531         }
11532     }
11533
11534   return FALSE;
11535 }
11536
11537 static gboolean
11538 parse_rotation (ClutterActor *actor,
11539                 JsonNode     *node,
11540                 RotationInfo *info)
11541 {
11542   JsonArray *array;
11543   guint len, i;
11544   gboolean retval = FALSE;
11545
11546   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
11547     {
11548       g_warning ("Invalid node of type '%s' found, expecting an array",
11549                  json_node_type_name (node));
11550       return FALSE;
11551     }
11552
11553   array = json_node_get_array (node);
11554   len = json_array_get_length (array);
11555
11556   for (i = 0; i < len; i++)
11557     {
11558       JsonNode *element = json_array_get_element (array, i);
11559       JsonObject *object;
11560       JsonNode *member;
11561
11562       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
11563         {
11564           g_warning ("Invalid node of type '%s' found, expecting an object",
11565                      json_node_type_name (element));
11566           return FALSE;
11567         }
11568
11569       object = json_node_get_object (element);
11570
11571       if (json_object_has_member (object, "x-axis"))
11572         {
11573           member = json_object_get_member (object, "x-axis");
11574
11575           info->axis = CLUTTER_X_AXIS;
11576
11577           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11578             {
11579               info->angle = json_node_get_double (member);
11580               retval = TRUE;
11581             }
11582           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11583             retval = parse_rotation_array (actor,
11584                                            json_node_get_array (member),
11585                                            info);
11586           else
11587             retval = FALSE;
11588         }
11589       else if (json_object_has_member (object, "y-axis"))
11590         {
11591           member = json_object_get_member (object, "y-axis");
11592
11593           info->axis = CLUTTER_Y_AXIS;
11594
11595           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11596             {
11597               info->angle = json_node_get_double (member);
11598               retval = TRUE;
11599             }
11600           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11601             retval = parse_rotation_array (actor,
11602                                            json_node_get_array (member),
11603                                            info);
11604           else
11605             retval = FALSE;
11606         }
11607       else if (json_object_has_member (object, "z-axis"))
11608         {
11609           member = json_object_get_member (object, "z-axis");
11610
11611           info->axis = CLUTTER_Z_AXIS;
11612
11613           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
11614             {
11615               info->angle = json_node_get_double (member);
11616               retval = TRUE;
11617             }
11618           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
11619             retval = parse_rotation_array (actor,
11620                                            json_node_get_array (member),
11621                                            info);
11622           else
11623             retval = FALSE;
11624         }
11625     }
11626
11627   return retval;
11628 }
11629
11630 static GSList *
11631 parse_actor_metas (ClutterScript *script,
11632                    ClutterActor  *actor,
11633                    JsonNode      *node)
11634 {
11635   GList *elements, *l;
11636   GSList *retval = NULL;
11637
11638   if (!JSON_NODE_HOLDS_ARRAY (node))
11639     return NULL;
11640
11641   elements = json_array_get_elements (json_node_get_array (node));
11642
11643   for (l = elements; l != NULL; l = l->next)
11644     {
11645       JsonNode *element = l->data;
11646       const gchar *id_ = _clutter_script_get_id_from_node (element);
11647       GObject *meta;
11648
11649       if (id_ == NULL || *id_ == '\0')
11650         continue;
11651
11652       meta = clutter_script_get_object (script, id_);
11653       if (meta == NULL)
11654         continue;
11655
11656       retval = g_slist_prepend (retval, meta);
11657     }
11658
11659   g_list_free (elements);
11660
11661   return g_slist_reverse (retval);
11662 }
11663
11664 static GSList *
11665 parse_behaviours (ClutterScript *script,
11666                   ClutterActor  *actor,
11667                   JsonNode      *node)
11668 {
11669   GList *elements, *l;
11670   GSList *retval = NULL;
11671
11672   if (!JSON_NODE_HOLDS_ARRAY (node))
11673     return NULL;
11674
11675   elements = json_array_get_elements (json_node_get_array (node));
11676
11677   for (l = elements; l != NULL; l = l->next)
11678     {
11679       JsonNode *element = l->data;
11680       const gchar *id_ = _clutter_script_get_id_from_node (element);
11681       GObject *behaviour;
11682
11683       if (id_ == NULL || *id_ == '\0')
11684         continue;
11685
11686       behaviour = clutter_script_get_object (script, id_);
11687       if (behaviour == NULL)
11688         continue;
11689
11690       retval = g_slist_prepend (retval, behaviour);
11691     }
11692
11693   g_list_free (elements);
11694
11695   return g_slist_reverse (retval);
11696 }
11697
11698 static gboolean
11699 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
11700                                  ClutterScript     *script,
11701                                  GValue            *value,
11702                                  const gchar       *name,
11703                                  JsonNode          *node)
11704 {
11705   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11706   gboolean retval = FALSE;
11707
11708   if ((name[0] == 'x' && name[1] == '\0') ||
11709       (name[0] == 'y' && name[1] == '\0') ||
11710       (strcmp (name, "width") == 0) ||
11711       (strcmp (name, "height") == 0) ||
11712       (strcmp (name, "anchor_x") == 0) ||
11713       (strcmp (name, "anchor_y") == 0))
11714     {
11715       ParseDimension dimension;
11716       gfloat units;
11717
11718       if (name[0] == 'x')
11719         dimension = PARSE_X;
11720       else if (name[0] == 'y')
11721         dimension = PARSE_Y;
11722       else if (name[0] == 'w')
11723         dimension = PARSE_WIDTH;
11724       else if (name[0] == 'h')
11725         dimension = PARSE_HEIGHT;
11726       else if (name[0] == 'a' && name[7] == 'x')
11727         dimension = PARSE_ANCHOR_X;
11728       else if (name[0] == 'a' && name[7] == 'y')
11729         dimension = PARSE_ANCHOR_Y;
11730       else
11731         return FALSE;
11732
11733       units = parse_units (actor, dimension, node);
11734
11735       /* convert back to pixels: all properties are pixel-based */
11736       g_value_init (value, G_TYPE_FLOAT);
11737       g_value_set_float (value, units);
11738
11739       retval = TRUE;
11740     }
11741   else if (strcmp (name, "rotation") == 0)
11742     {
11743       RotationInfo *info;
11744
11745       info = g_slice_new0 (RotationInfo);
11746       retval = parse_rotation (actor, node, info);
11747
11748       if (retval)
11749         {
11750           g_value_init (value, G_TYPE_POINTER);
11751           g_value_set_pointer (value, info);
11752         }
11753       else
11754         g_slice_free (RotationInfo, info);
11755     }
11756   else if (strcmp (name, "behaviours") == 0)
11757     {
11758       GSList *l;
11759
11760 #ifdef CLUTTER_ENABLE_DEBUG
11761       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
11762         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
11763                                      "and it should not be used in newly "
11764                                      "written ClutterScript definitions.");
11765 #endif
11766
11767       l = parse_behaviours (script, actor, node);
11768
11769       g_value_init (value, G_TYPE_POINTER);
11770       g_value_set_pointer (value, l);
11771
11772       retval = TRUE;
11773     }
11774   else if (strcmp (name, "actions") == 0 ||
11775            strcmp (name, "constraints") == 0 ||
11776            strcmp (name, "effects") == 0)
11777     {
11778       GSList *l;
11779
11780       l = parse_actor_metas (script, actor, node);
11781
11782       g_value_init (value, G_TYPE_POINTER);
11783       g_value_set_pointer (value, l);
11784
11785       retval = TRUE;
11786     }
11787
11788   return retval;
11789 }
11790
11791 static void
11792 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
11793                                    ClutterScript     *script,
11794                                    const gchar       *name,
11795                                    const GValue      *value)
11796 {
11797   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
11798
11799 #ifdef CLUTTER_ENABLE_DEBUG
11800   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
11801     {
11802       gchar *tmp = g_strdup_value_contents (value);
11803
11804       CLUTTER_NOTE (SCRIPT,
11805                     "in ClutterActor::set_custom_property('%s') = %s",
11806                     name,
11807                     tmp);
11808
11809       g_free (tmp);
11810     }
11811 #endif /* CLUTTER_ENABLE_DEBUG */
11812
11813   if (strcmp (name, "rotation") == 0)
11814     {
11815       RotationInfo *info;
11816
11817       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11818         return;
11819
11820       info = g_value_get_pointer (value);
11821
11822       clutter_actor_set_rotation (actor,
11823                                   info->axis, info->angle,
11824                                   info->center_x,
11825                                   info->center_y,
11826                                   info->center_z);
11827
11828       g_slice_free (RotationInfo, info);
11829
11830       return;
11831     }
11832
11833   if (strcmp (name, "behaviours") == 0)
11834     {
11835       GSList *behaviours, *l;
11836
11837       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11838         return;
11839
11840       behaviours = g_value_get_pointer (value);
11841       for (l = behaviours; l != NULL; l = l->next)
11842         {
11843           ClutterBehaviour *behaviour = l->data;
11844
11845           clutter_behaviour_apply (behaviour, actor);
11846         }
11847
11848       g_slist_free (behaviours);
11849
11850       return;
11851     }
11852
11853   if (strcmp (name, "actions") == 0 ||
11854       strcmp (name, "constraints") == 0 ||
11855       strcmp (name, "effects") == 0)
11856     {
11857       GSList *metas, *l;
11858
11859       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
11860         return;
11861
11862       metas = g_value_get_pointer (value);
11863       for (l = metas; l != NULL; l = l->next)
11864         {
11865           if (name[0] == 'a')
11866             clutter_actor_add_action (actor, l->data);
11867
11868           if (name[0] == 'c')
11869             clutter_actor_add_constraint (actor, l->data);
11870
11871           if (name[0] == 'e')
11872             clutter_actor_add_effect (actor, l->data);
11873         }
11874
11875       g_slist_free (metas);
11876
11877       return;
11878     }
11879
11880   g_object_set_property (G_OBJECT (scriptable), name, value);
11881 }
11882
11883 static void
11884 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
11885 {
11886   iface->parse_custom_node = clutter_actor_parse_custom_node;
11887   iface->set_custom_property = clutter_actor_set_custom_property;
11888 }
11889
11890 static ClutterActorMeta *
11891 get_meta_from_animation_property (ClutterActor  *actor,
11892                                   const gchar   *name,
11893                                   gchar        **name_p)
11894 {
11895   ClutterActorPrivate *priv = actor->priv;
11896   ClutterActorMeta *meta = NULL;
11897   gchar **tokens;
11898
11899   /* if this is not a special property, fall through */
11900   if (name[0] != '@')
11901     return NULL;
11902
11903   /* detect the properties named using the following spec:
11904    *
11905    *   @<section>.<meta-name>.<property-name>
11906    *
11907    * where <section> can be one of the following:
11908    *
11909    *   - actions
11910    *   - constraints
11911    *   - effects
11912    *
11913    * and <meta-name> is the name set on a specific ActorMeta
11914    */
11915
11916   tokens = g_strsplit (name + 1, ".", -1);
11917   if (tokens == NULL || g_strv_length (tokens) != 3)
11918     {
11919       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
11920                     name + 1);
11921       g_strfreev (tokens);
11922       return NULL;
11923     }
11924
11925   if (strcmp (tokens[0], "actions") == 0)
11926     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
11927
11928   if (strcmp (tokens[0], "constraints") == 0)
11929     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
11930
11931   if (strcmp (tokens[0], "effects") == 0)
11932     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
11933
11934   if (name_p != NULL)
11935     *name_p = g_strdup (tokens[2]);
11936
11937   CLUTTER_NOTE (ANIMATION,
11938                 "Looking for property '%s' of object '%s' in section '%s'",
11939                 tokens[2],
11940                 tokens[1],
11941                 tokens[0]);
11942
11943   g_strfreev (tokens);
11944
11945   return meta;
11946 }
11947
11948 static GParamSpec *
11949 clutter_actor_find_property (ClutterAnimatable *animatable,
11950                              const gchar       *property_name)
11951 {
11952   ClutterActorMeta *meta = NULL;
11953   GObjectClass *klass = NULL;
11954   GParamSpec *pspec = NULL;
11955   gchar *p_name = NULL;
11956
11957   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
11958                                            property_name,
11959                                            &p_name);
11960
11961   if (meta != NULL)
11962     {
11963       klass = G_OBJECT_GET_CLASS (meta);
11964
11965       pspec = g_object_class_find_property (klass, p_name);
11966     }
11967   else
11968     {
11969       klass = G_OBJECT_GET_CLASS (animatable);
11970
11971       pspec = g_object_class_find_property (klass, property_name);
11972     }
11973
11974   g_free (p_name);
11975
11976   return pspec;
11977 }
11978
11979 static void
11980 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
11981                                  const gchar       *property_name,
11982                                  GValue            *initial)
11983 {
11984   ClutterActorMeta *meta = NULL;
11985   gchar *p_name = NULL;
11986
11987   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
11988                                            property_name,
11989                                            &p_name);
11990
11991   if (meta != NULL)
11992     g_object_get_property (G_OBJECT (meta), p_name, initial);
11993   else
11994     g_object_get_property (G_OBJECT (animatable), property_name, initial);
11995
11996   g_free (p_name);
11997 }
11998
11999 static void
12000 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12001                                const gchar       *property_name,
12002                                const GValue      *final)
12003 {
12004   ClutterActorMeta *meta = NULL;
12005   gchar *p_name = NULL;
12006
12007   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12008                                            property_name,
12009                                            &p_name);
12010   if (meta != NULL)
12011     g_object_set_property (G_OBJECT (meta), p_name, final);
12012   else
12013     g_object_set_property (G_OBJECT (animatable), property_name, final);
12014
12015   g_free (p_name);
12016 }
12017
12018 static void
12019 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12020 {
12021   iface->find_property = clutter_actor_find_property;
12022   iface->get_initial_state = clutter_actor_get_initial_state;
12023   iface->set_final_state = clutter_actor_set_final_state;
12024 }
12025
12026 /**
12027  * clutter_actor_transform_stage_point:
12028  * @self: A #ClutterActor
12029  * @x: (in): x screen coordinate of the point to unproject
12030  * @y: (in): y screen coordinate of the point to unproject
12031  * @x_out: (out): return location for the unprojected x coordinance
12032  * @y_out: (out): return location for the unprojected y coordinance
12033  *
12034  * This function translates screen coordinates (@x, @y) to
12035  * coordinates relative to the actor. For example, it can be used to translate
12036  * screen events from global screen coordinates into actor-local coordinates.
12037  *
12038  * The conversion can fail, notably if the transform stack results in the
12039  * actor being projected on the screen as a mere line.
12040  *
12041  * The conversion should not be expected to be pixel-perfect due to the
12042  * nature of the operation. In general the error grows when the skewing
12043  * of the actor rectangle on screen increases.
12044  *
12045  * <note><para>This function can be computationally intensive.</para></note>
12046  *
12047  * <note><para>This function only works when the allocation is up-to-date,
12048  * i.e. inside of paint().</para></note>
12049  *
12050  * Return value: %TRUE if conversion was successful.
12051  *
12052  * Since: 0.6
12053  */
12054 gboolean
12055 clutter_actor_transform_stage_point (ClutterActor *self,
12056                                      gfloat        x,
12057                                      gfloat        y,
12058                                      gfloat       *x_out,
12059                                      gfloat       *y_out)
12060 {
12061   ClutterVertex v[4];
12062   float ST[3][3];
12063   float RQ[3][3];
12064   int du, dv, xi, yi;
12065   float px, py;
12066   float xf, yf, wf, det;
12067   ClutterActorPrivate *priv;
12068
12069   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12070
12071   priv = self->priv;
12072
12073   /* This implementation is based on the quad -> quad projection algorithm
12074    * described by Paul Heckbert in:
12075    *
12076    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12077    *
12078    * and the sample implementation at:
12079    *
12080    *   http://www.cs.cmu.edu/~ph/src/texfund/
12081    *
12082    * Our texture is a rectangle with origin [0, 0], so we are mapping from
12083    * quad to rectangle only, which significantly simplifies things; the
12084    * function calls have been unrolled, and most of the math is done in fixed
12085    * point.
12086    */
12087
12088   clutter_actor_get_abs_allocation_vertices (self, v);
12089
12090   /* Keeping these as ints simplifies the multiplication (no significant
12091    * loss of precision here).
12092    */
12093   du = (int) (priv->allocation.x2 - priv->allocation.x1);
12094   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12095
12096   if (!du || !dv)
12097     return FALSE;
12098
12099 #define UX2FP(x)        (x)
12100 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12101
12102   /* First, find mapping from unit uv square to xy quadrilateral; this
12103    * equivalent to the pmap_square_quad() functions in the sample
12104    * implementation, which we can simplify, since our target is always
12105    * a rectangle.
12106    */
12107   px = v[0].x - v[1].x + v[3].x - v[2].x;
12108   py = v[0].y - v[1].y + v[3].y - v[2].y;
12109
12110   if (!px && !py)
12111     {
12112       /* affine transform */
12113       RQ[0][0] = UX2FP (v[1].x - v[0].x);
12114       RQ[1][0] = UX2FP (v[3].x - v[1].x);
12115       RQ[2][0] = UX2FP (v[0].x);
12116       RQ[0][1] = UX2FP (v[1].y - v[0].y);
12117       RQ[1][1] = UX2FP (v[3].y - v[1].y);
12118       RQ[2][1] = UX2FP (v[0].y);
12119       RQ[0][2] = 0;
12120       RQ[1][2] = 0;
12121       RQ[2][2] = 1.0;
12122     }
12123   else
12124     {
12125       /* projective transform */
12126       double dx1, dx2, dy1, dy2, del;
12127
12128       dx1 = UX2FP (v[1].x - v[3].x);
12129       dx2 = UX2FP (v[2].x - v[3].x);
12130       dy1 = UX2FP (v[1].y - v[3].y);
12131       dy2 = UX2FP (v[2].y - v[3].y);
12132
12133       del = DET2FP (dx1, dx2, dy1, dy2);
12134       if (!del)
12135         return FALSE;
12136
12137       /*
12138        * The division here needs to be done in floating point for
12139        * precisions reasons.
12140        */
12141       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12142       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12143       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12144       RQ[2][2] = 1.0;
12145       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12146       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12147       RQ[2][0] = UX2FP (v[0].x);
12148       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12149       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12150       RQ[2][1] = UX2FP (v[0].y);
12151     }
12152
12153   /*
12154    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12155    * square. Since our rectangle is based at 0,0 we only need to scale.
12156    */
12157   RQ[0][0] /= du;
12158   RQ[1][0] /= dv;
12159   RQ[0][1] /= du;
12160   RQ[1][1] /= dv;
12161   RQ[0][2] /= du;
12162   RQ[1][2] /= dv;
12163
12164   /*
12165    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12166    * inverse of that.
12167    */
12168   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12169   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12170   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12171   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12172   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12173   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12174   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12175   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12176   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12177
12178   /*
12179    * Check the resulting matrix is OK.
12180    */
12181   det = (RQ[0][0] * ST[0][0])
12182       + (RQ[0][1] * ST[0][1])
12183       + (RQ[0][2] * ST[0][2]);
12184   if (!det)
12185     return FALSE;
12186
12187   /*
12188    * Now transform our point with the ST matrix; the notional w
12189    * coordinate is 1, hence the last part is simply added.
12190    */
12191   xi = (int) x;
12192   yi = (int) y;
12193
12194   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12195   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12196   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12197
12198   if (x_out)
12199     *x_out = xf / wf;
12200
12201   if (y_out)
12202     *y_out = yf / wf;
12203
12204 #undef UX2FP
12205 #undef DET2FP
12206
12207   return TRUE;
12208 }
12209
12210 /*
12211  * ClutterGeometry
12212  */
12213
12214 static ClutterGeometry*
12215 clutter_geometry_copy (const ClutterGeometry *geometry)
12216 {
12217   return g_slice_dup (ClutterGeometry, geometry);
12218 }
12219
12220 static void
12221 clutter_geometry_free (ClutterGeometry *geometry)
12222 {
12223   if (G_LIKELY (geometry != NULL))
12224     g_slice_free (ClutterGeometry, geometry);
12225 }
12226
12227 /**
12228  * clutter_geometry_union:
12229  * @geometry_a: a #ClutterGeometry
12230  * @geometry_b: another #ClutterGeometry
12231  * @result: (out): location to store the result
12232  *
12233  * Find the union of two rectangles represented as #ClutterGeometry.
12234  *
12235  * Since: 1.4
12236  */
12237 void
12238 clutter_geometry_union (const ClutterGeometry *geometry_a,
12239                         const ClutterGeometry *geometry_b,
12240                         ClutterGeometry       *result)
12241 {
12242   /* We don't try to handle rectangles that can't be represented
12243    * as a signed integer box */
12244   gint x_1 = MIN (geometry_a->x, geometry_b->x);
12245   gint y_1 = MIN (geometry_a->y, geometry_b->y);
12246   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12247                   geometry_b->x + (gint)geometry_b->width);
12248   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12249                   geometry_b->y + (gint)geometry_b->height);
12250   result->x = x_1;
12251   result->y = y_1;
12252   result->width = x_2 - x_1;
12253   result->height = y_2 - y_1;
12254 }
12255
12256 /**
12257  * clutter_geometry_intersects:
12258  * @geometry0: The first geometry to test
12259  * @geometry1: The second geometry to test
12260  *
12261  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12262  * they do else %FALSE.
12263  *
12264  * Return value: %TRUE of @geometry0 and geometry1 intersect else
12265  * %FALSE.
12266  *
12267  * Since: 1.4
12268  */
12269 gboolean
12270 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12271                              const ClutterGeometry *geometry1)
12272 {
12273   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12274       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12275       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12276       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12277     return FALSE;
12278   else
12279     return TRUE;
12280 }
12281
12282 static gboolean
12283 clutter_geometry_progress (const GValue *a,
12284                            const GValue *b,
12285                            gdouble       progress,
12286                            GValue       *retval)
12287 {
12288   const ClutterGeometry *a_geom = g_value_get_boxed (a);
12289   const ClutterGeometry *b_geom = g_value_get_boxed (b);
12290   ClutterGeometry res = { 0, };
12291   gint a_width = a_geom->width;
12292   gint b_width = b_geom->width;
12293   gint a_height = a_geom->height;
12294   gint b_height = b_geom->height;
12295
12296   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12297   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12298
12299   res.width = a_width + (b_width - a_width) * progress;
12300   res.height = a_height + (b_height - a_height) * progress;
12301
12302   g_value_set_boxed (retval, &res);
12303
12304   return TRUE;
12305 }
12306
12307 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12308                                clutter_geometry_copy,
12309                                clutter_geometry_free,
12310                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12311
12312 /*
12313  * ClutterVertices
12314  */
12315
12316 /**
12317  * clutter_vertex_new:
12318  * @x: X coordinate
12319  * @y: Y coordinate
12320  * @z: Z coordinate
12321  *
12322  * Creates a new #ClutterVertex for the point in 3D space
12323  * identified by the 3 coordinates @x, @y, @z
12324  *
12325  * Return value: the newly allocate #ClutterVertex. Use
12326  *   clutter_vertex_free() to free the resources
12327  *
12328  * Since: 1.0
12329  */
12330 ClutterVertex *
12331 clutter_vertex_new (gfloat x,
12332                     gfloat y,
12333                     gfloat z)
12334 {
12335   ClutterVertex *vertex;
12336
12337   vertex = g_slice_new (ClutterVertex);
12338   vertex->x = x;
12339   vertex->y = y;
12340   vertex->z = z;
12341
12342   return vertex;
12343 }
12344
12345 /**
12346  * clutter_vertex_copy:
12347  * @vertex: a #ClutterVertex
12348  *
12349  * Copies @vertex
12350  *
12351  * Return value: a newly allocated copy of #ClutterVertex. Use
12352  *   clutter_vertex_free() to free the allocated resources
12353  *
12354  * Since: 1.0
12355  */
12356 ClutterVertex *
12357 clutter_vertex_copy (const ClutterVertex *vertex)
12358 {
12359   if (G_LIKELY (vertex != NULL))
12360     return g_slice_dup (ClutterVertex, vertex);
12361
12362   return NULL;
12363 }
12364
12365 /**
12366  * clutter_vertex_free:
12367  * @vertex: a #ClutterVertex
12368  *
12369  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
12370  *
12371  * Since: 1.0
12372  */
12373 void
12374 clutter_vertex_free (ClutterVertex *vertex)
12375 {
12376   if (G_UNLIKELY (vertex != NULL))
12377     g_slice_free (ClutterVertex, vertex);
12378 }
12379
12380 /**
12381  * clutter_vertex_equal:
12382  * @vertex_a: a #ClutterVertex
12383  * @vertex_b: a #ClutterVertex
12384  *
12385  * Compares @vertex_a and @vertex_b for equality
12386  *
12387  * Return value: %TRUE if the passed #ClutterVertex are equal
12388  *
12389  * Since: 1.0
12390  */
12391 gboolean
12392 clutter_vertex_equal (const ClutterVertex *vertex_a,
12393                       const ClutterVertex *vertex_b)
12394 {
12395   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
12396
12397   if (vertex_a == vertex_b)
12398     return TRUE;
12399
12400   return vertex_a->x == vertex_b->x &&
12401          vertex_a->y == vertex_b->y &&
12402          vertex_a->z == vertex_b->z;
12403 }
12404
12405 static gboolean
12406 clutter_vertex_progress (const GValue *a,
12407                          const GValue *b,
12408                          gdouble       progress,
12409                          GValue       *retval)
12410 {
12411   const ClutterVertex *av = g_value_get_boxed (a);
12412   const ClutterVertex *bv = g_value_get_boxed (b);
12413   ClutterVertex res = { 0, };
12414
12415   res.x = av->x + (bv->x - av->x) * progress;
12416   res.y = av->y + (bv->y - av->y) * progress;
12417   res.z = av->z + (bv->z - av->z) * progress;
12418
12419   g_value_set_boxed (retval, &res);
12420
12421   return TRUE;
12422 }
12423
12424 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
12425                                clutter_vertex_copy,
12426                                clutter_vertex_free,
12427                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
12428
12429 /**
12430  * clutter_actor_is_rotated:
12431  * @self: a #ClutterActor
12432  *
12433  * Checks whether any rotation is applied to the actor.
12434  *
12435  * Return value: %TRUE if the actor is rotated.
12436  *
12437  * Since: 0.6
12438  */
12439 gboolean
12440 clutter_actor_is_rotated (ClutterActor *self)
12441 {
12442   const ClutterTransformInfo *info;
12443
12444   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12445
12446   info = _clutter_actor_get_transform_info_or_defaults (self);
12447
12448   if (info->rx_angle || info->ry_angle || info->rz_angle)
12449     return TRUE;
12450
12451   return FALSE;
12452 }
12453
12454 /**
12455  * clutter_actor_is_scaled:
12456  * @self: a #ClutterActor
12457  *
12458  * Checks whether the actor is scaled in either dimension.
12459  *
12460  * Return value: %TRUE if the actor is scaled.
12461  *
12462  * Since: 0.6
12463  */
12464 gboolean
12465 clutter_actor_is_scaled (ClutterActor *self)
12466 {
12467   const ClutterTransformInfo *info;
12468
12469   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12470
12471   info = _clutter_actor_get_transform_info_or_defaults (self);
12472
12473   if (info->scale_x != 1.0 || info->scale_y != 1.0)
12474     return TRUE;
12475
12476   return FALSE;
12477 }
12478
12479 ClutterActor *
12480 _clutter_actor_get_stage_internal (ClutterActor *actor)
12481 {
12482   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
12483     actor = actor->priv->parent;
12484
12485   return actor;
12486 }
12487
12488 /**
12489  * clutter_actor_get_stage:
12490  * @actor: a #ClutterActor
12491  *
12492  * Retrieves the #ClutterStage where @actor is contained.
12493  *
12494  * Return value: (transfer none) (type Clutter.Stage): the stage
12495  *   containing the actor, or %NULL
12496  *
12497  * Since: 0.8
12498  */
12499 ClutterActor *
12500 clutter_actor_get_stage (ClutterActor *actor)
12501 {
12502   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
12503
12504   return _clutter_actor_get_stage_internal (actor);
12505 }
12506
12507 /**
12508  * clutter_actor_allocate_available_size:
12509  * @self: a #ClutterActor
12510  * @x: the actor's X coordinate
12511  * @y: the actor's Y coordinate
12512  * @available_width: the maximum available width, or -1 to use the
12513  *   actor's natural width
12514  * @available_height: the maximum available height, or -1 to use the
12515  *   actor's natural height
12516  * @flags: flags controlling the allocation
12517  *
12518  * Allocates @self taking into account the #ClutterActor<!-- -->'s
12519  * preferred size, but limiting it to the maximum available width
12520  * and height provided.
12521  *
12522  * This function will do the right thing when dealing with the
12523  * actor's request mode.
12524  *
12525  * The implementation of this function is equivalent to:
12526  *
12527  * |[
12528  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12529  *     {
12530  *       clutter_actor_get_preferred_width (self, available_height,
12531  *                                          &amp;min_width,
12532  *                                          &amp;natural_width);
12533  *       width = CLAMP (natural_width, min_width, available_width);
12534  *
12535  *       clutter_actor_get_preferred_height (self, width,
12536  *                                           &amp;min_height,
12537  *                                           &amp;natural_height);
12538  *       height = CLAMP (natural_height, min_height, available_height);
12539  *     }
12540  *   else
12541  *     {
12542  *       clutter_actor_get_preferred_height (self, available_width,
12543  *                                           &amp;min_height,
12544  *                                           &amp;natural_height);
12545  *       height = CLAMP (natural_height, min_height, available_height);
12546  *
12547  *       clutter_actor_get_preferred_width (self, height,
12548  *                                          &amp;min_width,
12549  *                                          &amp;natural_width);
12550  *       width = CLAMP (natural_width, min_width, available_width);
12551  *     }
12552  *
12553  *   box.x1 = x; box.y1 = y;
12554  *   box.x2 = box.x1 + available_width;
12555  *   box.y2 = box.y1 + available_height;
12556  *   clutter_actor_allocate (self, &amp;box, flags);
12557  * ]|
12558  *
12559  * This function can be used by fluid layout managers to allocate
12560  * an actor's preferred size without making it bigger than the area
12561  * available for the container.
12562  *
12563  * Since: 1.0
12564  */
12565 void
12566 clutter_actor_allocate_available_size (ClutterActor           *self,
12567                                        gfloat                  x,
12568                                        gfloat                  y,
12569                                        gfloat                  available_width,
12570                                        gfloat                  available_height,
12571                                        ClutterAllocationFlags  flags)
12572 {
12573   ClutterActorPrivate *priv;
12574   gfloat width, height;
12575   gfloat min_width, min_height;
12576   gfloat natural_width, natural_height;
12577   ClutterActorBox box;
12578
12579   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12580
12581   priv = self->priv;
12582
12583   width = height = 0.0;
12584
12585   switch (priv->request_mode)
12586     {
12587     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
12588       clutter_actor_get_preferred_width (self, available_height,
12589                                          &min_width,
12590                                          &natural_width);
12591       width  = CLAMP (natural_width, min_width, available_width);
12592
12593       clutter_actor_get_preferred_height (self, width,
12594                                           &min_height,
12595                                           &natural_height);
12596       height = CLAMP (natural_height, min_height, available_height);
12597       break;
12598
12599     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
12600       clutter_actor_get_preferred_height (self, available_width,
12601                                           &min_height,
12602                                           &natural_height);
12603       height = CLAMP (natural_height, min_height, available_height);
12604
12605       clutter_actor_get_preferred_width (self, height,
12606                                          &min_width,
12607                                          &natural_width);
12608       width  = CLAMP (natural_width, min_width, available_width);
12609       break;
12610     }
12611
12612
12613   box.x1 = x;
12614   box.y1 = y;
12615   box.x2 = box.x1 + width;
12616   box.y2 = box.y1 + height;
12617   clutter_actor_allocate (self, &box, flags);
12618 }
12619
12620 /**
12621  * clutter_actor_allocate_preferred_size:
12622  * @self: a #ClutterActor
12623  * @flags: flags controlling the allocation
12624  *
12625  * Allocates the natural size of @self.
12626  *
12627  * This function is a utility call for #ClutterActor implementations
12628  * that allocates the actor's preferred natural size. It can be used
12629  * by fixed layout managers (like #ClutterGroup or so called
12630  * 'composite actors') inside the ClutterActor::allocate
12631  * implementation to give each child exactly how much space it
12632  * requires.
12633  *
12634  * This function is not meant to be used by applications. It is also
12635  * not meant to be used outside the implementation of the
12636  * ClutterActor::allocate virtual function.
12637  *
12638  * Since: 0.8
12639  */
12640 void
12641 clutter_actor_allocate_preferred_size (ClutterActor           *self,
12642                                        ClutterAllocationFlags  flags)
12643 {
12644   gfloat actor_x, actor_y;
12645   gfloat natural_width, natural_height;
12646   ClutterActorBox actor_box;
12647
12648   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12649
12650   actor_x = clutter_actor_get_x (self);
12651   actor_y = clutter_actor_get_y (self);
12652
12653   clutter_actor_get_preferred_size (self,
12654                                     NULL, NULL,
12655                                     &natural_width,
12656                                     &natural_height);
12657
12658   actor_box.x1 = actor_x;
12659   actor_box.y1 = actor_y;
12660   actor_box.x2 = actor_box.x1 + natural_width;
12661   actor_box.y2 = actor_box.y1 + natural_height;
12662
12663   clutter_actor_allocate (self, &actor_box, flags);
12664 }
12665
12666 /**
12667  * clutter_actor_allocate_align_fill:
12668  * @self: a #ClutterActor
12669  * @box: a #ClutterActorBox, containing the available width and height
12670  * @x_align: the horizontal alignment, between 0 and 1
12671  * @y_align: the vertical alignment, between 0 and 1
12672  * @x_fill: whether the actor should fill horizontally
12673  * @y_fill: whether the actor should fill vertically
12674  * @flags: allocation flags to be passed to clutter_actor_allocate()
12675  *
12676  * Allocates @self by taking into consideration the available allocation
12677  * area; an alignment factor on either axis; and whether the actor should
12678  * fill the allocation on either axis.
12679  *
12680  * The @box should contain the available allocation width and height;
12681  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
12682  * allocation will be offset by their value.
12683  *
12684  * This function takes into consideration the geometry request specified by
12685  * the #ClutterActor:request-mode property, and the text direction.
12686  *
12687  * This function is useful for fluid layout managers, like #ClutterBinLayout
12688  * or #ClutterTableLayout
12689  *
12690  * Since: 1.4
12691  */
12692 void
12693 clutter_actor_allocate_align_fill (ClutterActor           *self,
12694                                    const ClutterActorBox  *box,
12695                                    gdouble                 x_align,
12696                                    gdouble                 y_align,
12697                                    gboolean                x_fill,
12698                                    gboolean                y_fill,
12699                                    ClutterAllocationFlags  flags)
12700 {
12701   ClutterActorPrivate *priv;
12702   ClutterActorBox allocation = { 0, };
12703   gfloat x_offset, y_offset;
12704   gfloat available_width, available_height;
12705   gfloat child_width, child_height;
12706
12707   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12708   g_return_if_fail (box != NULL);
12709   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
12710   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
12711
12712   priv = self->priv;
12713
12714   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
12715   clutter_actor_box_get_size (box, &available_width, &available_height);
12716
12717   if (available_width < 0)
12718     available_width = 0;
12719
12720   if (available_height < 0)
12721     available_height = 0;
12722
12723   if (x_fill)
12724     {
12725       allocation.x1 = x_offset;
12726       allocation.x2 = allocation.x1 + available_width;
12727     }
12728
12729   if (y_fill)
12730     {
12731       allocation.y1 = y_offset;
12732       allocation.y2 = allocation.y1 + available_height;
12733     }
12734
12735   /* if we are filling horizontally and vertically then we're done */
12736   if (x_fill && y_fill)
12737     goto out;
12738
12739   child_width = child_height = 0.0f;
12740
12741   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
12742     {
12743       gfloat min_width, natural_width;
12744       gfloat min_height, natural_height;
12745
12746       clutter_actor_get_preferred_width (self, available_height,
12747                                          &min_width,
12748                                          &natural_width);
12749
12750       child_width = CLAMP (natural_width, min_width, available_width);
12751
12752       if (!y_fill)
12753         {
12754           clutter_actor_get_preferred_height (self, child_width,
12755                                               &min_height,
12756                                               &natural_height);
12757
12758           child_height = CLAMP (natural_height, min_height, available_height);
12759         }
12760     }
12761   else
12762     {
12763       gfloat min_width, natural_width;
12764       gfloat min_height, natural_height;
12765
12766       clutter_actor_get_preferred_height (self, available_width,
12767                                           &min_height,
12768                                           &natural_height);
12769
12770       child_height = CLAMP (natural_height, min_height, available_height);
12771
12772       if (!x_fill)
12773         {
12774           clutter_actor_get_preferred_width (self, child_height,
12775                                              &min_width,
12776                                              &natural_width);
12777
12778           child_width = CLAMP (natural_width, min_width, available_width);
12779         }
12780     }
12781
12782   /* invert the horizontal alignment for RTL languages */
12783   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
12784     x_align = 1.0 - x_align;
12785
12786   if (!x_fill)
12787     {
12788       allocation.x1 = x_offset
12789                     + ((available_width - child_width) * x_align);
12790       allocation.x2 = allocation.x1 + child_width;
12791     }
12792
12793   if (!y_fill)
12794     {
12795       allocation.y1 = y_offset
12796                     + ((available_height - child_height) * y_align);
12797       allocation.y2 = allocation.y1 + child_height;
12798     }
12799
12800 out:
12801   clutter_actor_box_clamp_to_pixel (&allocation);
12802   clutter_actor_allocate (self, &allocation, flags);
12803 }
12804
12805 /**
12806  * clutter_actor_grab_key_focus:
12807  * @self: a #ClutterActor
12808  *
12809  * Sets the key focus of the #ClutterStage including @self
12810  * to this #ClutterActor.
12811  *
12812  * Since: 1.0
12813  */
12814 void
12815 clutter_actor_grab_key_focus (ClutterActor *self)
12816 {
12817   ClutterActor *stage;
12818
12819   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12820
12821   stage = _clutter_actor_get_stage_internal (self);
12822   if (stage != NULL)
12823     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
12824 }
12825
12826 /**
12827  * clutter_actor_get_pango_context:
12828  * @self: a #ClutterActor
12829  *
12830  * Retrieves the #PangoContext for @self. The actor's #PangoContext
12831  * is already configured using the appropriate font map, resolution
12832  * and font options.
12833  *
12834  * Unlike clutter_actor_create_pango_context(), this context is owend
12835  * by the #ClutterActor and it will be updated each time the options
12836  * stored by the #ClutterBackend change.
12837  *
12838  * You can use the returned #PangoContext to create a #PangoLayout
12839  * and render text using cogl_pango_render_layout() to reuse the
12840  * glyphs cache also used by Clutter.
12841  *
12842  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
12843  *   The returned #PangoContext is owned by the actor and should not be
12844  *   unreferenced by the application code
12845  *
12846  * Since: 1.0
12847  */
12848 PangoContext *
12849 clutter_actor_get_pango_context (ClutterActor *self)
12850 {
12851   ClutterActorPrivate *priv;
12852
12853   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12854
12855   priv = self->priv;
12856
12857   if (priv->pango_context != NULL)
12858     return priv->pango_context;
12859
12860   priv->pango_context = _clutter_context_get_pango_context ();
12861   g_object_ref (priv->pango_context);
12862
12863   return priv->pango_context;
12864 }
12865
12866 /**
12867  * clutter_actor_create_pango_context:
12868  * @self: a #ClutterActor
12869  *
12870  * Creates a #PangoContext for the given actor. The #PangoContext
12871  * is already configured using the appropriate font map, resolution
12872  * and font options.
12873  *
12874  * See also clutter_actor_get_pango_context().
12875  *
12876  * Return value: (transfer full): the newly created #PangoContext.
12877  *   Use g_object_unref() on the returned value to deallocate its
12878  *   resources
12879  *
12880  * Since: 1.0
12881  */
12882 PangoContext *
12883 clutter_actor_create_pango_context (ClutterActor *self)
12884 {
12885   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12886
12887   return _clutter_context_create_pango_context ();
12888 }
12889
12890 /**
12891  * clutter_actor_create_pango_layout:
12892  * @self: a #ClutterActor
12893  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
12894  *
12895  * Creates a new #PangoLayout from the same #PangoContext used
12896  * by the #ClutterActor. The #PangoLayout is already configured
12897  * with the font map, resolution and font options, and the
12898  * given @text.
12899  *
12900  * If you want to keep around a #PangoLayout created by this
12901  * function you will have to connect to the #ClutterBackend::font-changed
12902  * and #ClutterBackend::resolution-changed signals, and call
12903  * pango_layout_context_changed() in response to them.
12904  *
12905  * Return value: (transfer full): the newly created #PangoLayout.
12906  *   Use g_object_unref() when done
12907  *
12908  * Since: 1.0
12909  */
12910 PangoLayout *
12911 clutter_actor_create_pango_layout (ClutterActor *self,
12912                                    const gchar  *text)
12913 {
12914   PangoContext *context;
12915   PangoLayout *layout;
12916
12917   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
12918
12919   context = clutter_actor_get_pango_context (self);
12920   layout = pango_layout_new (context);
12921
12922   if (text)
12923     pango_layout_set_text (layout, text, -1);
12924
12925   return layout;
12926 }
12927
12928 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
12929  * ClutterOffscreenEffect.
12930  */
12931 void
12932 _clutter_actor_set_opacity_override (ClutterActor *self,
12933                                      gint          opacity)
12934 {
12935   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12936
12937   self->priv->opacity_override = opacity;
12938 }
12939
12940 gint
12941 _clutter_actor_get_opacity_override (ClutterActor *self)
12942 {
12943   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
12944
12945   return self->priv->opacity_override;
12946 }
12947
12948 /* Allows you to disable applying the actors model view transform during
12949  * a paint. Used by ClutterClone. */
12950 void
12951 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
12952                                                 gboolean      enable)
12953 {
12954   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12955
12956   self->priv->enable_model_view_transform = enable;
12957 }
12958
12959 void
12960 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
12961                                           gboolean      enable)
12962 {
12963   ClutterActorPrivate *priv;
12964
12965   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12966
12967   priv = self->priv;
12968
12969   priv->enable_paint_unmapped = enable;
12970
12971   if (priv->enable_paint_unmapped)
12972     {
12973       /* Make sure that the parents of the widget are realized first;
12974        * otherwise checks in clutter_actor_update_map_state() will
12975        * fail.
12976        */
12977       clutter_actor_realize (self);
12978
12979       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
12980     }
12981   else
12982     {
12983       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
12984     }
12985 }
12986
12987 static void
12988 clutter_anchor_coord_get_units (ClutterActor      *self,
12989                                 const AnchorCoord *coord,
12990                                 gfloat            *x,
12991                                 gfloat            *y,
12992                                 gfloat            *z)
12993 {
12994   if (coord->is_fractional)
12995     {
12996       gfloat actor_width, actor_height;
12997
12998       clutter_actor_get_size (self, &actor_width, &actor_height);
12999
13000       if (x)
13001         *x = actor_width * coord->v.fraction.x;
13002
13003       if (y)
13004         *y = actor_height * coord->v.fraction.y;
13005
13006       if (z)
13007         *z = 0;
13008     }
13009   else
13010     {
13011       if (x)
13012         *x = coord->v.units.x;
13013
13014       if (y)
13015         *y = coord->v.units.y;
13016
13017       if (z)
13018         *z = coord->v.units.z;
13019     }
13020 }
13021
13022 static void
13023 clutter_anchor_coord_set_units (AnchorCoord *coord,
13024                                 gfloat       x,
13025                                 gfloat       y,
13026                                 gfloat       z)
13027 {
13028   coord->is_fractional = FALSE;
13029   coord->v.units.x = x;
13030   coord->v.units.y = y;
13031   coord->v.units.z = z;
13032 }
13033
13034 static ClutterGravity
13035 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13036 {
13037   if (coord->is_fractional)
13038     {
13039       if (coord->v.fraction.x == 0.0)
13040         {
13041           if (coord->v.fraction.y == 0.0)
13042             return CLUTTER_GRAVITY_NORTH_WEST;
13043           else if (coord->v.fraction.y == 0.5)
13044             return CLUTTER_GRAVITY_WEST;
13045           else if (coord->v.fraction.y == 1.0)
13046             return CLUTTER_GRAVITY_SOUTH_WEST;
13047           else
13048             return CLUTTER_GRAVITY_NONE;
13049         }
13050       else if (coord->v.fraction.x == 0.5)
13051         {
13052           if (coord->v.fraction.y == 0.0)
13053             return CLUTTER_GRAVITY_NORTH;
13054           else if (coord->v.fraction.y == 0.5)
13055             return CLUTTER_GRAVITY_CENTER;
13056           else if (coord->v.fraction.y == 1.0)
13057             return CLUTTER_GRAVITY_SOUTH;
13058           else
13059             return CLUTTER_GRAVITY_NONE;
13060         }
13061       else if (coord->v.fraction.x == 1.0)
13062         {
13063           if (coord->v.fraction.y == 0.0)
13064             return CLUTTER_GRAVITY_NORTH_EAST;
13065           else if (coord->v.fraction.y == 0.5)
13066             return CLUTTER_GRAVITY_EAST;
13067           else if (coord->v.fraction.y == 1.0)
13068             return CLUTTER_GRAVITY_SOUTH_EAST;
13069           else
13070             return CLUTTER_GRAVITY_NONE;
13071         }
13072       else
13073         return CLUTTER_GRAVITY_NONE;
13074     }
13075   else
13076     return CLUTTER_GRAVITY_NONE;
13077 }
13078
13079 static void
13080 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
13081                                   ClutterGravity  gravity)
13082 {
13083   switch (gravity)
13084     {
13085     case CLUTTER_GRAVITY_NORTH:
13086       coord->v.fraction.x = 0.5;
13087       coord->v.fraction.y = 0.0;
13088       break;
13089
13090     case CLUTTER_GRAVITY_NORTH_EAST:
13091       coord->v.fraction.x = 1.0;
13092       coord->v.fraction.y = 0.0;
13093       break;
13094
13095     case CLUTTER_GRAVITY_EAST:
13096       coord->v.fraction.x = 1.0;
13097       coord->v.fraction.y = 0.5;
13098       break;
13099
13100     case CLUTTER_GRAVITY_SOUTH_EAST:
13101       coord->v.fraction.x = 1.0;
13102       coord->v.fraction.y = 1.0;
13103       break;
13104
13105     case CLUTTER_GRAVITY_SOUTH:
13106       coord->v.fraction.x = 0.5;
13107       coord->v.fraction.y = 1.0;
13108       break;
13109
13110     case CLUTTER_GRAVITY_SOUTH_WEST:
13111       coord->v.fraction.x = 0.0;
13112       coord->v.fraction.y = 1.0;
13113       break;
13114
13115     case CLUTTER_GRAVITY_WEST:
13116       coord->v.fraction.x = 0.0;
13117       coord->v.fraction.y = 0.5;
13118       break;
13119
13120     case CLUTTER_GRAVITY_NORTH_WEST:
13121       coord->v.fraction.x = 0.0;
13122       coord->v.fraction.y = 0.0;
13123       break;
13124
13125     case CLUTTER_GRAVITY_CENTER:
13126       coord->v.fraction.x = 0.5;
13127       coord->v.fraction.y = 0.5;
13128       break;
13129
13130     default:
13131       coord->v.fraction.x = 0.0;
13132       coord->v.fraction.y = 0.0;
13133       break;
13134     }
13135
13136   coord->is_fractional = TRUE;
13137 }
13138
13139 static gboolean
13140 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13141 {
13142   if (coord->is_fractional)
13143     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13144   else
13145     return (coord->v.units.x == 0.0
13146             && coord->v.units.y == 0.0
13147             && coord->v.units.z == 0.0);
13148 }
13149
13150 /**
13151  * clutter_actor_get_flags:
13152  * @self: a #ClutterActor
13153  *
13154  * Retrieves the flags set on @self
13155  *
13156  * Return value: a bitwise or of #ClutterActorFlags or 0
13157  *
13158  * Since: 1.0
13159  */
13160 ClutterActorFlags
13161 clutter_actor_get_flags (ClutterActor *self)
13162 {
13163   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13164
13165   return self->flags;
13166 }
13167
13168 /**
13169  * clutter_actor_set_flags:
13170  * @self: a #ClutterActor
13171  * @flags: the flags to set
13172  *
13173  * Sets @flags on @self
13174  *
13175  * This function will emit notifications for the changed properties
13176  *
13177  * Since: 1.0
13178  */
13179 void
13180 clutter_actor_set_flags (ClutterActor      *self,
13181                          ClutterActorFlags  flags)
13182 {
13183   ClutterActorFlags old_flags;
13184   GObject *obj;
13185   gboolean was_reactive_set, reactive_set;
13186   gboolean was_realized_set, realized_set;
13187   gboolean was_mapped_set, mapped_set;
13188   gboolean was_visible_set, visible_set;
13189
13190   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13191
13192   if (self->flags == flags)
13193     return;
13194
13195   obj = G_OBJECT (self);
13196   g_object_ref (obj);
13197   g_object_freeze_notify (obj);
13198
13199   old_flags = self->flags;
13200
13201   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13202   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13203   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13204   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13205
13206   self->flags |= flags;
13207
13208   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13209   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13210   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13211   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13212
13213   if (reactive_set != was_reactive_set)
13214     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13215
13216   if (realized_set != was_realized_set)
13217     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13218
13219   if (mapped_set != was_mapped_set)
13220     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13221
13222   if (visible_set != was_visible_set)
13223     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13224
13225   g_object_thaw_notify (obj);
13226   g_object_unref (obj);
13227 }
13228
13229 /**
13230  * clutter_actor_unset_flags:
13231  * @self: a #ClutterActor
13232  * @flags: the flags to unset
13233  *
13234  * Unsets @flags on @self
13235  *
13236  * This function will emit notifications for the changed properties
13237  *
13238  * Since: 1.0
13239  */
13240 void
13241 clutter_actor_unset_flags (ClutterActor      *self,
13242                            ClutterActorFlags  flags)
13243 {
13244   ClutterActorFlags old_flags;
13245   GObject *obj;
13246   gboolean was_reactive_set, reactive_set;
13247   gboolean was_realized_set, realized_set;
13248   gboolean was_mapped_set, mapped_set;
13249   gboolean was_visible_set, visible_set;
13250
13251   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13252
13253   obj = G_OBJECT (self);
13254   g_object_freeze_notify (obj);
13255
13256   old_flags = self->flags;
13257
13258   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13259   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13260   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
13261   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13262
13263   self->flags &= ~flags;
13264
13265   if (self->flags == old_flags)
13266     return;
13267
13268   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13269   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13270   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
13271   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
13272
13273   if (reactive_set != was_reactive_set)
13274     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13275
13276   if (realized_set != was_realized_set)
13277     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13278
13279   if (mapped_set != was_mapped_set)
13280     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13281
13282   if (visible_set != was_visible_set)
13283     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13284
13285   g_object_thaw_notify (obj);
13286 }
13287
13288 /**
13289  * clutter_actor_get_transformation_matrix:
13290  * @self: a #ClutterActor
13291  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13292  *
13293  * Retrieves the transformations applied to @self relative to its
13294  * parent.
13295  *
13296  * Since: 1.0
13297  */
13298 void
13299 clutter_actor_get_transformation_matrix (ClutterActor *self,
13300                                          CoglMatrix   *matrix)
13301 {
13302   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13303
13304   cogl_matrix_init_identity (matrix);
13305
13306   _clutter_actor_apply_modelview_transform (self, matrix);
13307 }
13308
13309 void
13310 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13311                                    gboolean      is_in_clone_paint)
13312 {
13313   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13314   self->priv->in_clone_paint = is_in_clone_paint;
13315 }
13316
13317 /**
13318  * clutter_actor_is_in_clone_paint:
13319  * @self: a #ClutterActor
13320  *
13321  * Checks whether @self is being currently painted by a #ClutterClone
13322  *
13323  * This function is useful only inside the ::paint virtual function
13324  * implementations or within handlers for the #ClutterActor::paint
13325  * signal
13326  *
13327  * This function should not be used by applications
13328  *
13329  * Return value: %TRUE if the #ClutterActor is currently being painted
13330  *   by a #ClutterClone, and %FALSE otherwise
13331  *
13332  * Since: 1.0
13333  */
13334 gboolean
13335 clutter_actor_is_in_clone_paint (ClutterActor *self)
13336 {
13337   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13338
13339   return self->priv->in_clone_paint;
13340 }
13341
13342 static gboolean
13343 set_direction_recursive (ClutterActor *actor,
13344                          gpointer      user_data)
13345 {
13346   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
13347
13348   clutter_actor_set_text_direction (actor, text_dir);
13349
13350   return TRUE;
13351 }
13352
13353 /**
13354  * clutter_actor_set_text_direction:
13355  * @self: a #ClutterActor
13356  * @text_dir: the text direction for @self
13357  *
13358  * Sets the #ClutterTextDirection for an actor
13359  *
13360  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
13361  *
13362  * If @self implements #ClutterContainer then this function will recurse
13363  * inside all the children of @self (including the internal ones).
13364  *
13365  * Composite actors not implementing #ClutterContainer, or actors requiring
13366  * special handling when the text direction changes, should connect to
13367  * the #GObject::notify signal for the #ClutterActor:text-direction property
13368  *
13369  * Since: 1.2
13370  */
13371 void
13372 clutter_actor_set_text_direction (ClutterActor         *self,
13373                                   ClutterTextDirection  text_dir)
13374 {
13375   ClutterActorPrivate *priv;
13376
13377   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13378   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
13379
13380   priv = self->priv;
13381
13382   if (priv->text_direction != text_dir)
13383     {
13384       priv->text_direction = text_dir;
13385
13386       /* we need to emit the notify::text-direction first, so that
13387        * the sub-classes can catch that and do specific handling of
13388        * the text direction; see clutter_text_direction_changed_cb()
13389        * inside clutter-text.c
13390        */
13391       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
13392
13393       _clutter_actor_foreach_child (self, set_direction_recursive,
13394                                     GINT_TO_POINTER (text_dir));
13395
13396       clutter_actor_queue_relayout (self);
13397     }
13398 }
13399
13400 void
13401 _clutter_actor_set_has_pointer (ClutterActor *self,
13402                                 gboolean      has_pointer)
13403 {
13404   ClutterActorPrivate *priv = self->priv;
13405
13406   if (priv->has_pointer != has_pointer)
13407     {
13408       priv->has_pointer = has_pointer;
13409
13410       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
13411     }
13412 }
13413
13414 /**
13415  * clutter_actor_get_text_direction:
13416  * @self: a #ClutterActor
13417  *
13418  * Retrieves the value set using clutter_actor_set_text_direction()
13419  *
13420  * If no text direction has been previously set, the default text
13421  * direction, as returned by clutter_get_default_text_direction(), will
13422  * be returned instead
13423  *
13424  * Return value: the #ClutterTextDirection for the actor
13425  *
13426  * Since: 1.2
13427  */
13428 ClutterTextDirection
13429 clutter_actor_get_text_direction (ClutterActor *self)
13430 {
13431   ClutterActorPrivate *priv;
13432
13433   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
13434                         CLUTTER_TEXT_DIRECTION_LTR);
13435
13436   priv = self->priv;
13437
13438   /* if no direction has been set yet use the default */
13439   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
13440     priv->text_direction = clutter_get_default_text_direction ();
13441
13442   return priv->text_direction;
13443 }
13444
13445 /**
13446  * clutter_actor_push_internal:
13447  * @self: a #ClutterActor
13448  *
13449  * Should be used by actors implementing the #ClutterContainer and with
13450  * internal children added through clutter_actor_set_parent(), for instance:
13451  *
13452  * |[
13453  *   static void
13454  *   my_actor_init (MyActor *self)
13455  *   {
13456  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
13457  *
13458  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
13459  *
13460  *     /&ast; calling clutter_actor_set_parent() now will result in
13461  *      &ast; the internal flag being set on a child of MyActor
13462  *      &ast;/
13463  *
13464  *     /&ast; internal child - a background texture &ast;/
13465  *     self->priv->background_tex = clutter_texture_new ();
13466  *     clutter_actor_set_parent (self->priv->background_tex,
13467  *                               CLUTTER_ACTOR (self));
13468  *
13469  *     /&ast; internal child - a label &ast;/
13470  *     self->priv->label = clutter_text_new ();
13471  *     clutter_actor_set_parent (self->priv->label,
13472  *                               CLUTTER_ACTOR (self));
13473  *
13474  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
13475  *
13476  *     /&ast; calling clutter_actor_set_parent() now will not result in
13477  *      &ast; the internal flag being set on a child of MyActor
13478  *      &ast;/
13479  *   }
13480  * ]|
13481  *
13482  * This function will be used by Clutter to toggle an "internal child"
13483  * flag whenever clutter_actor_set_parent() is called; internal children
13484  * are handled differently by Clutter, specifically when destroying their
13485  * parent.
13486  *
13487  * Call clutter_actor_pop_internal() when you finished adding internal
13488  * children.
13489  *
13490  * Nested calls to clutter_actor_push_internal() are allowed, but each
13491  * one must by followed by a clutter_actor_pop_internal() call.
13492  *
13493  * Since: 1.2
13494  *
13495  * Deprecated: 1.10: All children of an actor are accessible through
13496  *   the #ClutterActor API, and #ClutterActor implements the
13497  *   #ClutterContainer interface, so this function is only useful
13498  *   for legacy containers overriding the default implementation.
13499  */
13500 void
13501 clutter_actor_push_internal (ClutterActor *self)
13502 {
13503   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13504
13505   self->priv->internal_child += 1;
13506 }
13507
13508 /**
13509  * clutter_actor_pop_internal:
13510  * @self: a #ClutterActor
13511  *
13512  * Disables the effects of clutter_actor_push_internal().
13513  *
13514  * Since: 1.2
13515  *
13516  * Deprecated: 1.10: All children of an actor are accessible through
13517  *   the #ClutterActor API. This function is only useful for legacy
13518  *   containers overriding the default implementation of the
13519  *   #ClutterContainer interface.
13520  */
13521 void
13522 clutter_actor_pop_internal (ClutterActor *self)
13523 {
13524   ClutterActorPrivate *priv;
13525
13526   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13527
13528   priv = self->priv;
13529
13530   if (priv->internal_child == 0)
13531     {
13532       g_warning ("Mismatched %s: you need to call "
13533                  "clutter_actor_push_composite() at least once before "
13534                  "calling this function", G_STRFUNC);
13535       return;
13536     }
13537
13538   priv->internal_child -= 1;
13539 }
13540
13541 /**
13542  * clutter_actor_has_pointer:
13543  * @self: a #ClutterActor
13544  *
13545  * Checks whether an actor contains the pointer of a
13546  * #ClutterInputDevice
13547  *
13548  * Return value: %TRUE if the actor contains the pointer, and
13549  *   %FALSE otherwise
13550  *
13551  * Since: 1.2
13552  */
13553 gboolean
13554 clutter_actor_has_pointer (ClutterActor *self)
13555 {
13556   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13557
13558   return self->priv->has_pointer;
13559 }
13560
13561 /* XXX: This is a workaround for not being able to break the ABI of
13562  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
13563  * clutter_actor_queue_clipped_redraw() for details.
13564  */
13565 ClutterPaintVolume *
13566 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
13567 {
13568   return g_object_get_data (G_OBJECT (self),
13569                             "-clutter-actor-queue-redraw-clip");
13570 }
13571
13572 void
13573 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
13574                                       ClutterPaintVolume *clip)
13575 {
13576   g_object_set_data (G_OBJECT (self),
13577                      "-clutter-actor-queue-redraw-clip",
13578                      clip);
13579 }
13580
13581 /**
13582  * clutter_actor_has_allocation:
13583  * @self: a #ClutterActor
13584  *
13585  * Checks if the actor has an up-to-date allocation assigned to
13586  * it. This means that the actor should have an allocation: it's
13587  * visible and has a parent. It also means that there is no
13588  * outstanding relayout request in progress for the actor or its
13589  * children (There might be other outstanding layout requests in
13590  * progress that will cause the actor to get a new allocation
13591  * when the stage is laid out, however).
13592  *
13593  * If this function returns %FALSE, then the actor will normally
13594  * be allocated before it is next drawn on the screen.
13595  *
13596  * Return value: %TRUE if the actor has an up-to-date allocation
13597  *
13598  * Since: 1.4
13599  */
13600 gboolean
13601 clutter_actor_has_allocation (ClutterActor *self)
13602 {
13603   ClutterActorPrivate *priv;
13604
13605   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13606
13607   priv = self->priv;
13608
13609   return priv->parent != NULL &&
13610          CLUTTER_ACTOR_IS_VISIBLE (self) &&
13611          !priv->needs_allocation;
13612 }
13613
13614 /**
13615  * clutter_actor_add_action:
13616  * @self: a #ClutterActor
13617  * @action: a #ClutterAction
13618  *
13619  * Adds @action to the list of actions applied to @self
13620  *
13621  * A #ClutterAction can only belong to one actor at a time
13622  *
13623  * The #ClutterActor will hold a reference on @action until either
13624  * clutter_actor_remove_action() or clutter_actor_clear_actions()
13625  * is called
13626  *
13627  * Since: 1.4
13628  */
13629 void
13630 clutter_actor_add_action (ClutterActor  *self,
13631                           ClutterAction *action)
13632 {
13633   ClutterActorPrivate *priv;
13634
13635   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13636   g_return_if_fail (CLUTTER_IS_ACTION (action));
13637
13638   priv = self->priv;
13639
13640   if (priv->actions == NULL)
13641     {
13642       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13643       priv->actions->actor = self;
13644     }
13645
13646   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
13647
13648   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13649 }
13650
13651 /**
13652  * clutter_actor_add_action_with_name:
13653  * @self: a #ClutterActor
13654  * @name: the name to set on the action
13655  * @action: a #ClutterAction
13656  *
13657  * A convenience function for setting the name of a #ClutterAction
13658  * while adding it to the list of actions applied to @self
13659  *
13660  * This function is the logical equivalent of:
13661  *
13662  * |[
13663  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13664  *   clutter_actor_add_action (self, action);
13665  * ]|
13666  *
13667  * Since: 1.4
13668  */
13669 void
13670 clutter_actor_add_action_with_name (ClutterActor  *self,
13671                                     const gchar   *name,
13672                                     ClutterAction *action)
13673 {
13674   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13675   g_return_if_fail (name != NULL);
13676   g_return_if_fail (CLUTTER_IS_ACTION (action));
13677
13678   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
13679   clutter_actor_add_action (self, action);
13680 }
13681
13682 /**
13683  * clutter_actor_remove_action:
13684  * @self: a #ClutterActor
13685  * @action: a #ClutterAction
13686  *
13687  * Removes @action from the list of actions applied to @self
13688  *
13689  * The reference held by @self on the #ClutterAction will be released
13690  *
13691  * Since: 1.4
13692  */
13693 void
13694 clutter_actor_remove_action (ClutterActor  *self,
13695                              ClutterAction *action)
13696 {
13697   ClutterActorPrivate *priv;
13698
13699   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13700   g_return_if_fail (CLUTTER_IS_ACTION (action));
13701
13702   priv = self->priv;
13703
13704   if (priv->actions == NULL)
13705     return;
13706
13707   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
13708
13709   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13710 }
13711
13712 /**
13713  * clutter_actor_remove_action_by_name:
13714  * @self: a #ClutterActor
13715  * @name: the name of the action to remove
13716  *
13717  * Removes the #ClutterAction with the given name from the list
13718  * of actions applied to @self
13719  *
13720  * Since: 1.4
13721  */
13722 void
13723 clutter_actor_remove_action_by_name (ClutterActor *self,
13724                                      const gchar  *name)
13725 {
13726   ClutterActorPrivate *priv;
13727   ClutterActorMeta *meta;
13728
13729   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13730   g_return_if_fail (name != NULL);
13731
13732   priv = self->priv;
13733
13734   if (priv->actions == NULL)
13735     return;
13736
13737   meta = _clutter_meta_group_get_meta (priv->actions, name);
13738   if (meta == NULL)
13739     return;
13740
13741   _clutter_meta_group_remove_meta (priv->actions, meta);
13742
13743   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
13744 }
13745
13746 /**
13747  * clutter_actor_get_actions:
13748  * @self: a #ClutterActor
13749  *
13750  * Retrieves the list of actions applied to @self
13751  *
13752  * Return value: (transfer container) (element-type Clutter.Action): a copy
13753  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
13754  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13755  *   allocated by the returned #GList
13756  *
13757  * Since: 1.4
13758  */
13759 GList *
13760 clutter_actor_get_actions (ClutterActor *self)
13761 {
13762   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13763
13764   if (self->priv->actions == NULL)
13765     return NULL;
13766
13767   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
13768 }
13769
13770 /**
13771  * clutter_actor_get_action:
13772  * @self: a #ClutterActor
13773  * @name: the name of the action to retrieve
13774  *
13775  * Retrieves the #ClutterAction with the given name in the list
13776  * of actions applied to @self
13777  *
13778  * Return value: (transfer none): a #ClutterAction for the given
13779  *   name, or %NULL. The returned #ClutterAction is owned by the
13780  *   actor and it should not be unreferenced directly
13781  *
13782  * Since: 1.4
13783  */
13784 ClutterAction *
13785 clutter_actor_get_action (ClutterActor *self,
13786                           const gchar  *name)
13787 {
13788   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13789   g_return_val_if_fail (name != NULL, NULL);
13790
13791   if (self->priv->actions == NULL)
13792     return NULL;
13793
13794   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
13795 }
13796
13797 /**
13798  * clutter_actor_clear_actions:
13799  * @self: a #ClutterActor
13800  *
13801  * Clears the list of actions applied to @self
13802  *
13803  * Since: 1.4
13804  */
13805 void
13806 clutter_actor_clear_actions (ClutterActor *self)
13807 {
13808   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13809
13810   if (self->priv->actions == NULL)
13811     return;
13812
13813   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
13814 }
13815
13816 /**
13817  * clutter_actor_add_constraint:
13818  * @self: a #ClutterActor
13819  * @constraint: a #ClutterConstraint
13820  *
13821  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
13822  * to @self
13823  *
13824  * The #ClutterActor will hold a reference on the @constraint until
13825  * either clutter_actor_remove_constraint() or
13826  * clutter_actor_clear_constraints() is called.
13827  *
13828  * Since: 1.4
13829  */
13830 void
13831 clutter_actor_add_constraint (ClutterActor      *self,
13832                               ClutterConstraint *constraint)
13833 {
13834   ClutterActorPrivate *priv;
13835
13836   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13837   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13838
13839   priv = self->priv;
13840
13841   if (priv->constraints == NULL)
13842     {
13843       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
13844       priv->constraints->actor = self;
13845     }
13846
13847   _clutter_meta_group_add_meta (priv->constraints,
13848                                 CLUTTER_ACTOR_META (constraint));
13849   clutter_actor_queue_relayout (self);
13850
13851   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13852 }
13853
13854 /**
13855  * clutter_actor_add_constraint_with_name:
13856  * @self: a #ClutterActor
13857  * @name: the name to set on the constraint
13858  * @constraint: a #ClutterConstraint
13859  *
13860  * A convenience function for setting the name of a #ClutterConstraint
13861  * while adding it to the list of constraints applied to @self
13862  *
13863  * This function is the logical equivalent of:
13864  *
13865  * |[
13866  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13867  *   clutter_actor_add_constraint (self, constraint);
13868  * ]|
13869  *
13870  * Since: 1.4
13871  */
13872 void
13873 clutter_actor_add_constraint_with_name (ClutterActor      *self,
13874                                         const gchar       *name,
13875                                         ClutterConstraint *constraint)
13876 {
13877   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13878   g_return_if_fail (name != NULL);
13879   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13880
13881   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
13882   clutter_actor_add_constraint (self, constraint);
13883 }
13884
13885 /**
13886  * clutter_actor_remove_constraint:
13887  * @self: a #ClutterActor
13888  * @constraint: a #ClutterConstraint
13889  *
13890  * Removes @constraint from the list of constraints applied to @self
13891  *
13892  * The reference held by @self on the #ClutterConstraint will be released
13893  *
13894  * Since: 1.4
13895  */
13896 void
13897 clutter_actor_remove_constraint (ClutterActor      *self,
13898                                  ClutterConstraint *constraint)
13899 {
13900   ClutterActorPrivate *priv;
13901
13902   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13903   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
13904
13905   priv = self->priv;
13906
13907   if (priv->constraints == NULL)
13908     return;
13909
13910   _clutter_meta_group_remove_meta (priv->constraints,
13911                                    CLUTTER_ACTOR_META (constraint));
13912   clutter_actor_queue_relayout (self);
13913
13914   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
13915 }
13916
13917 /**
13918  * clutter_actor_remove_constraint_by_name:
13919  * @self: a #ClutterActor
13920  * @name: the name of the constraint to remove
13921  *
13922  * Removes the #ClutterConstraint with the given name from the list
13923  * of constraints applied to @self
13924  *
13925  * Since: 1.4
13926  */
13927 void
13928 clutter_actor_remove_constraint_by_name (ClutterActor *self,
13929                                          const gchar  *name)
13930 {
13931   ClutterActorPrivate *priv;
13932   ClutterActorMeta *meta;
13933
13934   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13935   g_return_if_fail (name != NULL);
13936
13937   priv = self->priv;
13938
13939   if (priv->constraints == NULL)
13940     return;
13941
13942   meta = _clutter_meta_group_get_meta (priv->constraints, name);
13943   if (meta == NULL)
13944     return;
13945
13946   _clutter_meta_group_remove_meta (priv->constraints, meta);
13947   clutter_actor_queue_relayout (self);
13948 }
13949
13950 /**
13951  * clutter_actor_get_constraints:
13952  * @self: a #ClutterActor
13953  *
13954  * Retrieves the list of constraints applied to @self
13955  *
13956  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
13957  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
13958  *   owned by the #ClutterActor. Use g_list_free() to free the resources
13959  *   allocated by the returned #GList
13960  *
13961  * Since: 1.4
13962  */
13963 GList *
13964 clutter_actor_get_constraints (ClutterActor *self)
13965 {
13966   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13967
13968   if (self->priv->constraints == NULL)
13969     return NULL;
13970
13971   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
13972 }
13973
13974 /**
13975  * clutter_actor_get_constraint:
13976  * @self: a #ClutterActor
13977  * @name: the name of the constraint to retrieve
13978  *
13979  * Retrieves the #ClutterConstraint with the given name in the list
13980  * of constraints applied to @self
13981  *
13982  * Return value: (transfer none): a #ClutterConstraint for the given
13983  *   name, or %NULL. The returned #ClutterConstraint is owned by the
13984  *   actor and it should not be unreferenced directly
13985  *
13986  * Since: 1.4
13987  */
13988 ClutterConstraint *
13989 clutter_actor_get_constraint (ClutterActor *self,
13990                               const gchar  *name)
13991 {
13992   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13993   g_return_val_if_fail (name != NULL, NULL);
13994
13995   if (self->priv->constraints == NULL)
13996     return NULL;
13997
13998   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
13999 }
14000
14001 /**
14002  * clutter_actor_clear_constraints:
14003  * @self: a #ClutterActor
14004  *
14005  * Clears the list of constraints applied to @self
14006  *
14007  * Since: 1.4
14008  */
14009 void
14010 clutter_actor_clear_constraints (ClutterActor *self)
14011 {
14012   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14013
14014   if (self->priv->constraints == NULL)
14015     return;
14016
14017   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14018
14019   clutter_actor_queue_relayout (self);
14020 }
14021
14022 /**
14023  * clutter_actor_set_clip_to_allocation:
14024  * @self: a #ClutterActor
14025  * @clip_set: %TRUE to apply a clip tracking the allocation
14026  *
14027  * Sets whether @self should be clipped to the same size as its
14028  * allocation
14029  *
14030  * Since: 1.4
14031  */
14032 void
14033 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14034                                       gboolean      clip_set)
14035 {
14036   ClutterActorPrivate *priv;
14037
14038   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14039
14040   clip_set = !!clip_set;
14041
14042   priv = self->priv;
14043
14044   if (priv->clip_to_allocation != clip_set)
14045     {
14046       priv->clip_to_allocation = clip_set;
14047
14048       clutter_actor_queue_redraw (self);
14049
14050       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14051     }
14052 }
14053
14054 /**
14055  * clutter_actor_get_clip_to_allocation:
14056  * @self: a #ClutterActor
14057  *
14058  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14059  *
14060  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14061  *
14062  * Since: 1.4
14063  */
14064 gboolean
14065 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14066 {
14067   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14068
14069   return self->priv->clip_to_allocation;
14070 }
14071
14072 /**
14073  * clutter_actor_add_effect:
14074  * @self: a #ClutterActor
14075  * @effect: a #ClutterEffect
14076  *
14077  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14078  *
14079  * The #ClutterActor will hold a reference on the @effect until either
14080  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14081  * called.
14082  *
14083  * Since: 1.4
14084  */
14085 void
14086 clutter_actor_add_effect (ClutterActor  *self,
14087                           ClutterEffect *effect)
14088 {
14089   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14090   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14091
14092   _clutter_actor_add_effect_internal (self, effect);
14093
14094   clutter_actor_queue_redraw (self);
14095
14096   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14097 }
14098
14099 /**
14100  * clutter_actor_add_effect_with_name:
14101  * @self: a #ClutterActor
14102  * @name: the name to set on the effect
14103  * @effect: a #ClutterEffect
14104  *
14105  * A convenience function for setting the name of a #ClutterEffect
14106  * while adding it to the list of effectss applied to @self
14107  *
14108  * This function is the logical equivalent of:
14109  *
14110  * |[
14111  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14112  *   clutter_actor_add_effect (self, effect);
14113  * ]|
14114  *
14115  * Since: 1.4
14116  */
14117 void
14118 clutter_actor_add_effect_with_name (ClutterActor  *self,
14119                                     const gchar   *name,
14120                                     ClutterEffect *effect)
14121 {
14122   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14123   g_return_if_fail (name != NULL);
14124   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14125
14126   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14127   clutter_actor_add_effect (self, effect);
14128 }
14129
14130 /**
14131  * clutter_actor_remove_effect:
14132  * @self: a #ClutterActor
14133  * @effect: a #ClutterEffect
14134  *
14135  * Removes @effect from the list of effects applied to @self
14136  *
14137  * The reference held by @self on the #ClutterEffect will be released
14138  *
14139  * Since: 1.4
14140  */
14141 void
14142 clutter_actor_remove_effect (ClutterActor  *self,
14143                              ClutterEffect *effect)
14144 {
14145   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14146   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14147
14148   _clutter_actor_remove_effect_internal (self, effect);
14149
14150   clutter_actor_queue_redraw (self);
14151
14152   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14153 }
14154
14155 /**
14156  * clutter_actor_remove_effect_by_name:
14157  * @self: a #ClutterActor
14158  * @name: the name of the effect to remove
14159  *
14160  * Removes the #ClutterEffect with the given name from the list
14161  * of effects applied to @self
14162  *
14163  * Since: 1.4
14164  */
14165 void
14166 clutter_actor_remove_effect_by_name (ClutterActor *self,
14167                                      const gchar  *name)
14168 {
14169   ClutterActorPrivate *priv;
14170   ClutterActorMeta *meta;
14171
14172   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14173   g_return_if_fail (name != NULL);
14174
14175   priv = self->priv;
14176
14177   if (priv->effects == NULL)
14178     return;
14179
14180   meta = _clutter_meta_group_get_meta (priv->effects, name);
14181   if (meta == NULL)
14182     return;
14183
14184   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14185 }
14186
14187 /**
14188  * clutter_actor_get_effects:
14189  * @self: a #ClutterActor
14190  *
14191  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14192  *
14193  * Return value: (transfer container) (element-type Clutter.Effect): a list
14194  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14195  *   list are owned by Clutter and they should not be freed. You should
14196  *   free the returned list using g_list_free() when done
14197  *
14198  * Since: 1.4
14199  */
14200 GList *
14201 clutter_actor_get_effects (ClutterActor *self)
14202 {
14203   ClutterActorPrivate *priv;
14204
14205   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14206
14207   priv = self->priv;
14208
14209   if (priv->effects == NULL)
14210     return NULL;
14211
14212   return _clutter_meta_group_get_metas_no_internal (priv->effects);
14213 }
14214
14215 /**
14216  * clutter_actor_get_effect:
14217  * @self: a #ClutterActor
14218  * @name: the name of the effect to retrieve
14219  *
14220  * Retrieves the #ClutterEffect with the given name in the list
14221  * of effects applied to @self
14222  *
14223  * Return value: (transfer none): a #ClutterEffect for the given
14224  *   name, or %NULL. The returned #ClutterEffect is owned by the
14225  *   actor and it should not be unreferenced directly
14226  *
14227  * Since: 1.4
14228  */
14229 ClutterEffect *
14230 clutter_actor_get_effect (ClutterActor *self,
14231                           const gchar  *name)
14232 {
14233   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14234   g_return_val_if_fail (name != NULL, NULL);
14235
14236   if (self->priv->effects == NULL)
14237     return NULL;
14238
14239   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14240 }
14241
14242 /**
14243  * clutter_actor_clear_effects:
14244  * @self: a #ClutterActor
14245  *
14246  * Clears the list of effects applied to @self
14247  *
14248  * Since: 1.4
14249  */
14250 void
14251 clutter_actor_clear_effects (ClutterActor *self)
14252 {
14253   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14254
14255   if (self->priv->effects == NULL)
14256     return;
14257
14258   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14259
14260   clutter_actor_queue_redraw (self);
14261 }
14262
14263 /**
14264  * clutter_actor_has_key_focus:
14265  * @self: a #ClutterActor
14266  *
14267  * Checks whether @self is the #ClutterActor that has key focus
14268  *
14269  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14270  *
14271  * Since: 1.4
14272  */
14273 gboolean
14274 clutter_actor_has_key_focus (ClutterActor *self)
14275 {
14276   ClutterActor *stage;
14277
14278   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14279
14280   stage = _clutter_actor_get_stage_internal (self);
14281   if (stage == NULL)
14282     return FALSE;
14283
14284   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14285 }
14286
14287 static gboolean
14288 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14289                                       ClutterPaintVolume *pv)
14290 {
14291   ClutterActorPrivate *priv = self->priv;
14292
14293   /* Actors are only expected to report a valid paint volume
14294    * while they have a valid allocation. */
14295   if (G_UNLIKELY (priv->needs_allocation))
14296     {
14297       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14298                     "Actor needs allocation",
14299                     _clutter_actor_get_debug_name (self));
14300       return FALSE;
14301     }
14302
14303   /* Check if there are any handlers connected to the paint
14304    * signal. If there are then all bets are off for what the paint
14305    * volume for this actor might possibly be!
14306    *
14307    * XXX: It's expected that this is going to end up being quite a
14308    * costly check to have to do here, but we haven't come up with
14309    * another solution that can reliably catch paint signal handlers at
14310    * the right time to either avoid artefacts due to invalid stage
14311    * clipping or due to incorrect culling.
14312    *
14313    * Previously we checked in clutter_actor_paint(), but at that time
14314    * we may already be using a stage clip that could be derived from
14315    * an invalid paint-volume. We used to try and handle that by
14316    * queuing a follow up, unclipped, redraw but still the previous
14317    * checking wasn't enough to catch invalid volumes involved in
14318    * culling (considering that containers may derive their volume from
14319    * children that haven't yet been painted)
14320    *
14321    * Longer term, improved solutions could be:
14322    * - Disallow painting in the paint signal, only allow using it
14323    *   for tracking when paints happen. We can add another API that
14324    *   allows monkey patching the paint of arbitrary actors but in a
14325    *   more controlled way and that also supports modifying the
14326    *   paint-volume.
14327    * - If we could be notified somehow when signal handlers are
14328    *   connected we wouldn't have to poll for handlers like this.
14329    */
14330   if (g_signal_has_handler_pending (self,
14331                                     actor_signals[PAINT],
14332                                     0,
14333                                     TRUE))
14334     {
14335       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14336                     "Actor has \"paint\" signal handlers",
14337                     _clutter_actor_get_debug_name (self));
14338       return FALSE;
14339     }
14340
14341   _clutter_paint_volume_init_static (pv, self);
14342
14343   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
14344     {
14345       clutter_paint_volume_free (pv);
14346       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14347                     "Actor failed to report a volume",
14348                     _clutter_actor_get_debug_name (self));
14349       return FALSE;
14350     }
14351
14352   /* since effects can modify the paint volume, we allow them to actually
14353    * do this by making get_paint_volume() "context sensitive"
14354    */
14355   if (priv->effects != NULL)
14356     {
14357       if (priv->current_effect != NULL)
14358         {
14359           const GList *effects, *l;
14360
14361           /* if we are being called from within the paint sequence of
14362            * an actor, get the paint volume up to the current effect
14363            */
14364           effects = _clutter_meta_group_peek_metas (priv->effects);
14365           for (l = effects;
14366                l != NULL || (l != NULL && l->data != priv->current_effect);
14367                l = l->next)
14368             {
14369               if (!_clutter_effect_get_paint_volume (l->data, pv))
14370                 {
14371                   clutter_paint_volume_free (pv);
14372                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14373                                 "Effect (%s) failed to report a volume",
14374                                 _clutter_actor_get_debug_name (self),
14375                                 _clutter_actor_meta_get_debug_name (l->data));
14376                   return FALSE;
14377                 }
14378             }
14379         }
14380       else
14381         {
14382           const GList *effects, *l;
14383
14384           /* otherwise, get the cumulative volume */
14385           effects = _clutter_meta_group_peek_metas (priv->effects);
14386           for (l = effects; l != NULL; l = l->next)
14387             if (!_clutter_effect_get_paint_volume (l->data, pv))
14388               {
14389                 clutter_paint_volume_free (pv);
14390                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14391                               "Effect (%s) failed to report a volume",
14392                               _clutter_actor_get_debug_name (self),
14393                               _clutter_actor_meta_get_debug_name (l->data));
14394                 return FALSE;
14395               }
14396         }
14397     }
14398
14399   return TRUE;
14400 }
14401
14402 /* The public clutter_actor_get_paint_volume API returns a const
14403  * pointer since we return a pointer directly to the cached
14404  * PaintVolume associated with the actor and don't want the user to
14405  * inadvertently modify it, but for internal uses we sometimes need
14406  * access to the same PaintVolume but need to apply some book-keeping
14407  * modifications to it so we don't want a const pointer.
14408  */
14409 static ClutterPaintVolume *
14410 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
14411 {
14412   ClutterActorPrivate *priv;
14413
14414   priv = self->priv;
14415
14416   if (priv->paint_volume_valid)
14417     clutter_paint_volume_free (&priv->paint_volume);
14418
14419   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
14420     {
14421       priv->paint_volume_valid = TRUE;
14422       return &priv->paint_volume;
14423     }
14424   else
14425     {
14426       priv->paint_volume_valid = FALSE;
14427       return NULL;
14428     }
14429 }
14430
14431 /**
14432  * clutter_actor_get_paint_volume:
14433  * @self: a #ClutterActor
14434  *
14435  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
14436  * when a paint volume can't be determined.
14437  *
14438  * The paint volume is defined as the 3D space occupied by an actor
14439  * when being painted.
14440  *
14441  * This function will call the <function>get_paint_volume()</function>
14442  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
14443  * should not usually care about overriding the default implementation,
14444  * unless they are, for instance: painting outside their allocation, or
14445  * actors with a depth factor (not in terms of #ClutterActor:depth but real
14446  * 3D depth).
14447  *
14448  * <note>2D actors overriding <function>get_paint_volume()</function>
14449  * ensure their volume has a depth of 0. (This will be true so long as
14450  * you don't call clutter_paint_volume_set_depth().)</note>
14451  *
14452  * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14453  *   or %NULL if no volume could be determined.
14454  *
14455  * Since: 1.6
14456  */
14457 const ClutterPaintVolume *
14458 clutter_actor_get_paint_volume (ClutterActor *self)
14459 {
14460   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14461
14462   return _clutter_actor_get_paint_volume_mutable (self);
14463 }
14464
14465 /**
14466  * clutter_actor_get_transformed_paint_volume:
14467  * @self: a #ClutterActor
14468  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
14469  *    (or %NULL for the stage)
14470  *
14471  * Retrieves the 3D paint volume of an actor like
14472  * clutter_actor_get_paint_volume() does (Please refer to the
14473  * documentation of clutter_actor_get_paint_volume() for more
14474  * details.) and it additionally transforms the paint volume into the
14475  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
14476  * is passed for @relative_to_ancestor)
14477  *
14478  * This can be used by containers that base their paint volume on
14479  * the volume of their children. Such containers can query the
14480  * transformed paint volume of all of its children and union them
14481  * together using clutter_paint_volume_union().
14482  *
14483  * Return value: (transfer none): a pointer to a #ClutterPaintVolume
14484  *   or %NULL if no volume could be determined.
14485  *
14486  * Since: 1.6
14487  */
14488 const ClutterPaintVolume *
14489 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
14490                                             ClutterActor *relative_to_ancestor)
14491 {
14492   const ClutterPaintVolume *volume;
14493   ClutterActor *stage;
14494   ClutterPaintVolume *transformed_volume;
14495
14496   stage = _clutter_actor_get_stage_internal (self);
14497   if (G_UNLIKELY (stage == NULL))
14498     return NULL;
14499
14500   if (relative_to_ancestor == NULL)
14501     relative_to_ancestor = stage;
14502
14503   volume = clutter_actor_get_paint_volume (self);
14504   if (volume == NULL)
14505     return NULL;
14506
14507   transformed_volume =
14508     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
14509
14510   _clutter_paint_volume_copy_static (volume, transformed_volume);
14511
14512   _clutter_paint_volume_transform_relative (transformed_volume,
14513                                             relative_to_ancestor);
14514
14515   return transformed_volume;
14516 }
14517
14518 /**
14519  * clutter_actor_get_paint_box:
14520  * @self: a #ClutterActor
14521  * @box: (out): return location for a #ClutterActorBox
14522  *
14523  * Retrieves the paint volume of the passed #ClutterActor, and
14524  * transforms it into a 2D bounding box in stage coordinates.
14525  *
14526  * This function is useful to determine the on screen area occupied by
14527  * the actor. The box is only an approximation and may often be
14528  * considerably larger due to the optimizations used to calculate the
14529  * box. The box is never smaller though, so it can reliably be used
14530  * for culling.
14531  *
14532  * There are times when a 2D paint box can't be determined, e.g.
14533  * because the actor isn't yet parented under a stage or because
14534  * the actor is unable to determine a paint volume.
14535  *
14536  * Return value: %TRUE if a 2D paint box could be determined, else
14537  * %FALSE.
14538  *
14539  * Since: 1.6
14540  */
14541 gboolean
14542 clutter_actor_get_paint_box (ClutterActor    *self,
14543                              ClutterActorBox *box)
14544 {
14545   ClutterActor *stage;
14546   ClutterPaintVolume *pv;
14547
14548   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14549   g_return_val_if_fail (box != NULL, FALSE);
14550
14551   stage = _clutter_actor_get_stage_internal (self);
14552   if (G_UNLIKELY (!stage))
14553     return FALSE;
14554
14555   pv = _clutter_actor_get_paint_volume_mutable (self);
14556   if (G_UNLIKELY (!pv))
14557     return FALSE;
14558
14559   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
14560
14561   return TRUE;
14562 }
14563
14564 /**
14565  * clutter_actor_has_overlaps:
14566  * @self: A #ClutterActor
14567  *
14568  * Asks the actor's implementation whether it may contain overlapping
14569  * primitives.
14570  *
14571  * For example; Clutter may use this to determine whether the painting
14572  * should be redirected to an offscreen buffer to correctly implement
14573  * the opacity property.
14574  *
14575  * Custom actors can override the default response by implementing the
14576  * #ClutterActor <function>has_overlaps</function> virtual function. See
14577  * clutter_actor_set_offscreen_redirect() for more information.
14578  *
14579  * Return value: %TRUE if the actor may have overlapping primitives, and
14580  *   %FALSE otherwise
14581  *
14582  * Since: 1.8
14583  */
14584 gboolean
14585 clutter_actor_has_overlaps (ClutterActor *self)
14586 {
14587   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14588
14589   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
14590 }
14591
14592 /**
14593  * clutter_actor_has_effects:
14594  * @self: A #ClutterActor
14595  *
14596  * Returns whether the actor has any effects applied.
14597  *
14598  * Return value: %TRUE if the actor has any effects,
14599  *   %FALSE otherwise
14600  *
14601  * Since: 1.10
14602  */
14603 gboolean
14604 clutter_actor_has_effects (ClutterActor *self)
14605 {
14606   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14607
14608   if (self->priv->effects == NULL)
14609     return FALSE;
14610
14611   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
14612 }
14613
14614 /**
14615  * clutter_actor_has_constraints:
14616  * @self: A #ClutterActor
14617  *
14618  * Returns whether the actor has any constraints applied.
14619  *
14620  * Return value: %TRUE if the actor has any constraints,
14621  *   %FALSE otherwise
14622  *
14623  * Since: 1.10
14624  */
14625 gboolean
14626 clutter_actor_has_constraints (ClutterActor *self)
14627 {
14628   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14629
14630   return self->priv->constraints != NULL;
14631 }
14632
14633 /**
14634  * clutter_actor_has_actions:
14635  * @self: A #ClutterActor
14636  *
14637  * Returns whether the actor has any actions applied.
14638  *
14639  * Return value: %TRUE if the actor has any actions,
14640  *   %FALSE otherwise
14641  *
14642  * Since: 1.10
14643  */
14644 gboolean
14645 clutter_actor_has_actions (ClutterActor *self)
14646 {
14647   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
14648
14649   return self->priv->actions != NULL;
14650 }
14651
14652 /**
14653  * clutter_actor_get_n_children:
14654  * @self: a #ClutterActor
14655  *
14656  * Retrieves the number of children of @self.
14657  *
14658  * Return value: the number of children of an actor
14659  *
14660  * Since: 1.10
14661  */
14662 gint
14663 clutter_actor_get_n_children (ClutterActor *self)
14664 {
14665   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14666
14667   return self->priv->n_children;
14668 }
14669
14670 /**
14671  * clutter_actor_get_child_at_index:
14672  * @self: a #ClutterActor
14673  * @index_: the position in the list of children
14674  *
14675  * Retrieves the actor at the given @index_ inside the list of
14676  * children of @self.
14677  *
14678  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
14679  *
14680  * Since: 1.10
14681  */
14682 ClutterActor *
14683 clutter_actor_get_child_at_index (ClutterActor *self,
14684                                   gint          index_)
14685 {
14686   ClutterActor *iter;
14687   int i;
14688
14689   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14690   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
14691
14692   for (iter = self->priv->first_child, i = 0;
14693        iter != NULL && i < index_;
14694        iter = iter->priv->next_sibling, i += 1)
14695     ;
14696
14697   return iter;
14698 }
14699
14700 /*< private >
14701  * _clutter_actor_foreach_child:
14702  * @actor: The actor whos children you want to iterate
14703  * @callback: The function to call for each child
14704  * @user_data: Private data to pass to @callback
14705  *
14706  * Calls a given @callback once for each child of the specified @actor and
14707  * passing the @user_data pointer each time.
14708  *
14709  * Return value: returns %TRUE if all children were iterated, else
14710  *    %FALSE if a callback broke out of iteration early.
14711  */
14712 gboolean
14713 _clutter_actor_foreach_child (ClutterActor           *self,
14714                               ClutterForeachCallback  callback,
14715                               gpointer                user_data)
14716 {
14717   ClutterActorPrivate *priv = self->priv;
14718   ClutterActor *iter;
14719   gboolean cont;
14720
14721   for (cont = TRUE, iter = priv->first_child;
14722        cont && iter != NULL;
14723        iter = iter->priv->next_sibling)
14724     {
14725       cont = callback (iter, user_data);
14726     }
14727
14728   return cont;
14729 }
14730
14731 /* For debugging purposes this gives us a simple way to print out
14732  * the scenegraph e.g in gdb using:
14733  * [|
14734  *   _clutter_actor_traverse (stage,
14735  *                            0,
14736  *                            _clutter_debug_print_actor_cb,
14737  *                            NULL,
14738  *                            NULL);
14739  * |]
14740  */
14741 ClutterActorTraverseVisitFlags
14742 _clutter_debug_print_actor_cb (ClutterActor *actor,
14743                                int depth,
14744                                void *user_data)
14745 {
14746   g_print ("%*s%s:%p\n",
14747            depth * 2, "",
14748            _clutter_actor_get_debug_name (actor),
14749            actor);
14750
14751   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14752 }
14753
14754 static void
14755 _clutter_actor_traverse_breadth (ClutterActor           *actor,
14756                                  ClutterTraverseCallback callback,
14757                                  gpointer                user_data)
14758 {
14759   GQueue *queue = g_queue_new ();
14760   ClutterActor dummy;
14761   int current_depth = 0;
14762
14763   g_queue_push_tail (queue, actor);
14764   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
14765
14766   while ((actor = g_queue_pop_head (queue)))
14767     {
14768       ClutterActorTraverseVisitFlags flags;
14769
14770       if (actor == &dummy)
14771         {
14772           current_depth++;
14773           g_queue_push_tail (queue, &dummy);
14774           continue;
14775         }
14776
14777       flags = callback (actor, current_depth, user_data);
14778       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14779         break;
14780       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14781         {
14782           ClutterActor *iter;
14783
14784           for (iter = actor->priv->first_child;
14785                iter != NULL;
14786                iter = iter->priv->next_sibling)
14787             {
14788               g_queue_push_tail (queue, iter);
14789             }
14790         }
14791     }
14792
14793   g_queue_free (queue);
14794 }
14795
14796 static ClutterActorTraverseVisitFlags
14797 _clutter_actor_traverse_depth (ClutterActor           *actor,
14798                                ClutterTraverseCallback before_children_callback,
14799                                ClutterTraverseCallback after_children_callback,
14800                                int                     current_depth,
14801                                gpointer                user_data)
14802 {
14803   ClutterActorTraverseVisitFlags flags;
14804
14805   flags = before_children_callback (actor, current_depth, user_data);
14806   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14807     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14808
14809   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
14810     {
14811       ClutterActor *iter;
14812
14813       for (iter = actor->priv->first_child;
14814            iter != NULL;
14815            iter = iter->priv->next_sibling)
14816         {
14817           flags = _clutter_actor_traverse_depth (iter,
14818                                                  before_children_callback,
14819                                                  after_children_callback,
14820                                                  current_depth + 1,
14821                                                  user_data);
14822
14823           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
14824             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
14825         }
14826     }
14827
14828   if (after_children_callback)
14829     return after_children_callback (actor, current_depth, user_data);
14830   else
14831     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
14832 }
14833
14834 /* _clutter_actor_traverse:
14835  * @actor: The actor to start traversing the graph from
14836  * @flags: These flags may affect how the traversal is done
14837  * @before_children_callback: A function to call before visiting the
14838  *   children of the current actor.
14839  * @after_children_callback: A function to call after visiting the
14840  *   children of the current actor. (Ignored if
14841  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
14842  * @user_data: The private data to pass to the callbacks
14843  *
14844  * Traverses the scenegraph starting at the specified @actor and
14845  * descending through all its children and its children's children.
14846  * For each actor traversed @before_children_callback and
14847  * @after_children_callback are called with the specified
14848  * @user_data, before and after visiting that actor's children.
14849  *
14850  * The callbacks can return flags that affect the ongoing traversal
14851  * such as by skipping over an actors children or bailing out of
14852  * any further traversing.
14853  */
14854 void
14855 _clutter_actor_traverse (ClutterActor              *actor,
14856                          ClutterActorTraverseFlags  flags,
14857                          ClutterTraverseCallback    before_children_callback,
14858                          ClutterTraverseCallback    after_children_callback,
14859                          gpointer                   user_data)
14860 {
14861   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
14862     _clutter_actor_traverse_breadth (actor,
14863                                      before_children_callback,
14864                                      user_data);
14865   else /* DEPTH_FIRST */
14866     _clutter_actor_traverse_depth (actor,
14867                                    before_children_callback,
14868                                    after_children_callback,
14869                                    0, /* start depth */
14870                                    user_data);
14871 }
14872
14873 static void
14874 on_layout_manager_changed (ClutterLayoutManager *manager,
14875                            ClutterActor         *self)
14876 {
14877   clutter_actor_queue_relayout (self);
14878 }
14879
14880 /**
14881  * clutter_actor_set_layout_manager:
14882  * @self: a #ClutterActor
14883  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
14884  *
14885  * Sets the #ClutterLayoutManager delegate object that will be used to
14886  * lay out the children of @self.
14887  *
14888  * The #ClutterActor will take a reference on the passed @manager which
14889  * will be released either when the layout manager is removed, or when
14890  * the actor is destroyed.
14891  *
14892  * Since: 1.10
14893  */
14894 void
14895 clutter_actor_set_layout_manager (ClutterActor         *self,
14896                                   ClutterLayoutManager *manager)
14897 {
14898   ClutterActorPrivate *priv;
14899
14900   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14901   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
14902
14903   priv = self->priv;
14904
14905   if (priv->layout_manager != NULL)
14906     {
14907       g_signal_handlers_disconnect_by_func (priv->layout_manager,
14908                                             G_CALLBACK (on_layout_manager_changed),
14909                                             self);
14910       clutter_layout_manager_set_container (priv->layout_manager, NULL);
14911       g_object_unref (priv->layout_manager);
14912     }
14913
14914   priv->layout_manager = manager;
14915
14916   if (priv->layout_manager != NULL)
14917     {
14918       g_object_ref_sink (priv->layout_manager);
14919       clutter_layout_manager_set_container (priv->layout_manager,
14920                                             CLUTTER_CONTAINER (self));
14921       g_signal_connect (priv->layout_manager, "layout-changed",
14922                         G_CALLBACK (on_layout_manager_changed),
14923                         self);
14924     }
14925
14926   clutter_actor_queue_relayout (self);
14927
14928   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
14929 }
14930
14931 /**
14932  * clutter_actor_get_layout_manager:
14933  * @self: a #ClutterActor
14934  *
14935  * Retrieves the #ClutterLayoutManager used by @self.
14936  *
14937  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
14938  *   or %NULL
14939  *
14940  * Since: 1.10
14941  */
14942 ClutterLayoutManager *
14943 clutter_actor_get_layout_manager (ClutterActor *self)
14944 {
14945   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14946
14947   return self->priv->layout_manager;
14948 }
14949
14950 static const ClutterLayoutInfo default_layout_info = {
14951   0.f,                          /* fixed-x */
14952   0.f,                          /* fixed-y */
14953   { 0, 0, 0, 0 },               /* margin */
14954   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
14955   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
14956   0.f, 0.f,                     /* min_width, natural_width */
14957   0.f, 0.f,                     /* natual_width, natural_height */
14958 };
14959
14960 static void
14961 layout_info_free (gpointer data)
14962 {
14963   if (G_LIKELY (data != NULL))
14964     g_slice_free (ClutterLayoutInfo, data);
14965 }
14966
14967 /*< private >
14968  * _clutter_actor_get_layout_info:
14969  * @self: a #ClutterActor
14970  *
14971  * Retrieves a pointer to the ClutterLayoutInfo structure.
14972  *
14973  * If the actor does not have a ClutterLayoutInfo associated to it, one
14974  * will be created and initialized to the default values.
14975  *
14976  * This function should be used for setters.
14977  *
14978  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
14979  * instead.
14980  *
14981  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
14982  */
14983 ClutterLayoutInfo *
14984 _clutter_actor_get_layout_info (ClutterActor *self)
14985 {
14986   ClutterLayoutInfo *retval;
14987
14988   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
14989   if (retval == NULL)
14990     {
14991       retval = g_slice_new (ClutterLayoutInfo);
14992
14993       *retval = default_layout_info;
14994
14995       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
14996                                retval,
14997                                layout_info_free);
14998     }
14999
15000   return retval;
15001 }
15002
15003 /*< private >
15004  * _clutter_actor_get_layout_info_or_defaults:
15005  * @self: a #ClutterActor
15006  *
15007  * Retrieves the ClutterLayoutInfo structure associated to an actor.
15008  *
15009  * If the actor does not have a ClutterLayoutInfo structure associated to it,
15010  * then the default structure will be returned.
15011  *
15012  * This function should only be used for getters.
15013  *
15014  * Return value: a const pointer to the ClutterLayoutInfo structure
15015  */
15016 const ClutterLayoutInfo *
15017 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15018 {
15019   const ClutterLayoutInfo *info;
15020
15021   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15022   if (info == NULL)
15023     return &default_layout_info;
15024
15025   return info;
15026 }
15027
15028 /**
15029  * clutter_actor_set_x_align:
15030  * @self: a #ClutterActor
15031  * @x_align: the horizontal alignment policy
15032  *
15033  * Sets the horizontal alignment policy of a #ClutterActor, in case the
15034  * actor received extra horizontal space.
15035  *
15036  * See also the #ClutterActor:x-align property.
15037  *
15038  * Since: 1.10
15039  */
15040 void
15041 clutter_actor_set_x_align (ClutterActor      *self,
15042                            ClutterActorAlign  x_align)
15043 {
15044   ClutterLayoutInfo *info;
15045
15046   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15047
15048   info = _clutter_actor_get_layout_info (self);
15049
15050   if (info->x_align != x_align)
15051     {
15052       info->x_align = x_align;
15053
15054       clutter_actor_queue_relayout (self);
15055
15056       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15057     }
15058 }
15059
15060 /**
15061  * clutter_actor_get_x_align:
15062  * @self: a #ClutterActor
15063  *
15064  * Retrieves the horizontal alignment policy set using
15065  * clutter_actor_set_x_align().
15066  *
15067  * Return value: the horizontal alignment policy.
15068  *
15069  * Since: 1.10
15070  */
15071 ClutterActorAlign
15072 clutter_actor_get_x_align (ClutterActor *self)
15073 {
15074   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15075
15076   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15077 }
15078
15079 /**
15080  * clutter_actor_set_y_align:
15081  * @self: a #ClutterActor
15082  * @y_align: the vertical alignment policy
15083  *
15084  * Sets the vertical alignment policy of a #ClutterActor, in case the
15085  * actor received extra vertical space.
15086  *
15087  * See also the #ClutterActor:y-align property.
15088  *
15089  * Since: 1.10
15090  */
15091 void
15092 clutter_actor_set_y_align (ClutterActor      *self,
15093                            ClutterActorAlign  y_align)
15094 {
15095   ClutterLayoutInfo *info;
15096
15097   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15098
15099   info = _clutter_actor_get_layout_info (self);
15100
15101   if (info->y_align != y_align)
15102     {
15103       info->y_align = y_align;
15104
15105       clutter_actor_queue_relayout (self);
15106
15107       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15108     }
15109 }
15110
15111 /**
15112  * clutter_actor_get_y_align:
15113  * @self: a #ClutterActor
15114  *
15115  * Retrieves the vertical alignment policy set using
15116  * clutter_actor_set_y_align().
15117  *
15118  * Return value: the vertical alignment policy.
15119  *
15120  * Since: 1.10
15121  */
15122 ClutterActorAlign
15123 clutter_actor_get_y_align (ClutterActor *self)
15124 {
15125   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15126
15127   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15128 }
15129
15130
15131 /**
15132  * clutter_margin_new:
15133  *
15134  * Creates a new #ClutterMargin.
15135  *
15136  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15137  *   clutter_margin_free() to free the resources associated with it when
15138  *   done.
15139  *
15140  * Since: 1.10
15141  */
15142 ClutterMargin *
15143 clutter_margin_new (void)
15144 {
15145   return g_slice_new0 (ClutterMargin);
15146 }
15147
15148 /**
15149  * clutter_margin_copy:
15150  * @margin_: a #ClutterMargin
15151  *
15152  * Creates a new #ClutterMargin and copies the contents of @margin_ into
15153  * the newly created structure.
15154  *
15155  * Return value: (transfer full): a copy of the #ClutterMargin.
15156  *
15157  * Since: 1.10
15158  */
15159 ClutterMargin *
15160 clutter_margin_copy (const ClutterMargin *margin_)
15161 {
15162   if (G_LIKELY (margin_ != NULL))
15163     return g_slice_dup (ClutterMargin, margin_);
15164
15165   return NULL;
15166 }
15167
15168 /**
15169  * clutter_margin_free:
15170  * @margin_: a #ClutterMargin
15171  *
15172  * Frees the resources allocated by clutter_margin_new() and
15173  * clutter_margin_copy().
15174  *
15175  * Since: 1.10
15176  */
15177 void
15178 clutter_margin_free (ClutterMargin *margin_)
15179 {
15180   if (G_LIKELY (margin_ != NULL))
15181     g_slice_free (ClutterMargin, margin_);
15182 }
15183
15184 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15185                      clutter_margin_copy,
15186                      clutter_margin_free)
15187
15188 /**
15189  * clutter_actor_set_margin:
15190  * @self: a #ClutterActor
15191  * @margin: a #ClutterMargin
15192  *
15193  * Sets all the components of the margin of a #ClutterActor.
15194  *
15195  * Since: 1.10
15196  */
15197 void
15198 clutter_actor_set_margin (ClutterActor        *self,
15199                           const ClutterMargin *margin)
15200 {
15201   ClutterLayoutInfo *info;
15202   gboolean changed;
15203   GObject *obj;
15204
15205   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15206   g_return_if_fail (margin != NULL);
15207
15208   obj = G_OBJECT (self);
15209   changed = FALSE;
15210
15211   g_object_freeze_notify (obj);
15212
15213   info = _clutter_actor_get_layout_info (self);
15214
15215   if (info->margin.top != margin->top)
15216     {
15217       info->margin.top = margin->top;
15218       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15219       changed = TRUE;
15220     }
15221
15222   if (info->margin.right != margin->right)
15223     {
15224       info->margin.right = margin->right;
15225       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15226       changed = TRUE;
15227     }
15228
15229   if (info->margin.bottom != margin->bottom)
15230     {
15231       info->margin.bottom = margin->bottom;
15232       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15233       changed = TRUE;
15234     }
15235
15236   if (info->margin.left != margin->left)
15237     {
15238       info->margin.left = margin->left;
15239       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15240       changed = TRUE;
15241     }
15242
15243   if (changed)
15244     clutter_actor_queue_relayout (self);
15245
15246   g_object_thaw_notify (obj);
15247 }
15248
15249 /**
15250  * clutter_actor_get_margin:
15251  * @self: a #ClutterActor
15252  * @margin: (out caller-allocates): return location for a #ClutterMargin
15253  *
15254  * Retrieves all the components of the margin of a #ClutterActor.
15255  *
15256  * Since: 1.10
15257  */
15258 void
15259 clutter_actor_get_margin (ClutterActor  *self,
15260                           ClutterMargin *margin)
15261 {
15262   const ClutterLayoutInfo *info;
15263
15264   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15265   g_return_if_fail (margin != NULL);
15266
15267   info = _clutter_actor_get_layout_info_or_defaults (self);
15268
15269   *margin = info->margin;
15270 }
15271
15272 /**
15273  * clutter_actor_set_margin_top:
15274  * @self: a #ClutterActor
15275  * @margin: the top margin
15276  *
15277  * Sets the margin from the top of a #ClutterActor.
15278  *
15279  * Since: 1.10
15280  */
15281 void
15282 clutter_actor_set_margin_top (ClutterActor *self,
15283                               gfloat        margin)
15284 {
15285   ClutterLayoutInfo *info;
15286
15287   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15288   g_return_if_fail (margin >= 0.f);
15289
15290   info = _clutter_actor_get_layout_info (self);
15291
15292   if (info->margin.top == margin)
15293     return;
15294
15295   info->margin.top = margin;
15296
15297   clutter_actor_queue_relayout (self);
15298
15299   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15300 }
15301
15302 /**
15303  * clutter_actor_get_margin_top:
15304  * @self: a #ClutterActor
15305  *
15306  * Retrieves the top margin of a #ClutterActor.
15307  *
15308  * Return value: the top margin
15309  *
15310  * Since: 1.10
15311  */
15312 gfloat
15313 clutter_actor_get_margin_top (ClutterActor *self)
15314 {
15315   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15316
15317   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15318 }
15319
15320 /**
15321  * clutter_actor_set_margin_bottom:
15322  * @self: a #ClutterActor
15323  * @margin: the bottom margin
15324  *
15325  * Sets the margin from the bottom of a #ClutterActor.
15326  *
15327  * Since: 1.10
15328  */
15329 void
15330 clutter_actor_set_margin_bottom (ClutterActor *self,
15331                                  gfloat        margin)
15332 {
15333   ClutterLayoutInfo *info;
15334
15335   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15336   g_return_if_fail (margin >= 0.f);
15337
15338   info = _clutter_actor_get_layout_info (self);
15339
15340   if (info->margin.bottom == margin)
15341     return;
15342
15343   info->margin.bottom = margin;
15344
15345   clutter_actor_queue_relayout (self);
15346
15347   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
15348 }
15349
15350 /**
15351  * clutter_actor_get_margin_bottom:
15352  * @self: a #ClutterActor
15353  *
15354  * Retrieves the bottom margin of a #ClutterActor.
15355  *
15356  * Return value: the bottom margin
15357  *
15358  * Since: 1.10
15359  */
15360 gfloat
15361 clutter_actor_get_margin_bottom (ClutterActor *self)
15362 {
15363   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15364
15365   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
15366 }
15367
15368 /**
15369  * clutter_actor_set_margin_left:
15370  * @self: a #ClutterActor
15371  * @margin: the left margin
15372  *
15373  * Sets the margin from the left of a #ClutterActor.
15374  *
15375  * Since: 1.10
15376  */
15377 void
15378 clutter_actor_set_margin_left (ClutterActor *self,
15379                                gfloat        margin)
15380 {
15381   ClutterLayoutInfo *info;
15382
15383   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15384   g_return_if_fail (margin >= 0.f);
15385
15386   info = _clutter_actor_get_layout_info (self);
15387
15388   if (info->margin.left == margin)
15389     return;
15390
15391   info->margin.left = margin;
15392
15393   clutter_actor_queue_relayout (self);
15394
15395   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
15396 }
15397
15398 /**
15399  * clutter_actor_get_margin_left:
15400  * @self: a #ClutterActor
15401  *
15402  * Retrieves the left margin of a #ClutterActor.
15403  *
15404  * Return value: the left margin
15405  *
15406  * Since: 1.10
15407  */
15408 gfloat
15409 clutter_actor_get_margin_left (ClutterActor *self)
15410 {
15411   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15412
15413   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
15414 }
15415
15416 /**
15417  * clutter_actor_set_margin_right:
15418  * @self: a #ClutterActor
15419  * @margin: the right margin
15420  *
15421  * Sets the margin from the right of a #ClutterActor.
15422  *
15423  * Since: 1.10
15424  */
15425 void
15426 clutter_actor_set_margin_right (ClutterActor *self,
15427                                 gfloat        margin)
15428 {
15429   ClutterLayoutInfo *info;
15430
15431   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15432   g_return_if_fail (margin >= 0.f);
15433
15434   info = _clutter_actor_get_layout_info (self);
15435
15436   if (info->margin.right == margin)
15437     return;
15438
15439   info->margin.right = margin;
15440
15441   clutter_actor_queue_relayout (self);
15442
15443   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
15444 }
15445
15446 /**
15447  * clutter_actor_get_margin_right:
15448  * @self: a #ClutterActor
15449  *
15450  * Retrieves the right margin of a #ClutterActor.
15451  *
15452  * Return value: the right margin
15453  *
15454  * Since: 1.10
15455  */
15456 gfloat
15457 clutter_actor_get_margin_right (ClutterActor *self)
15458 {
15459   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15460
15461   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
15462 }
15463
15464 /**
15465  * clutter_actor_set_background_color:
15466  * @self: a #ClutterActor
15467  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
15468  *  set color
15469  *
15470  * Sets the background color of a #ClutterActor.
15471  *
15472  * The background color will be used to cover the whole allocation of the
15473  * actor. The default background color of an actor is transparent.
15474  *
15475  * To check whether an actor has a background color, you can use the
15476  * #ClutterActor:background-color-set actor property.
15477  *
15478  * Since: 1.10
15479  */
15480 void
15481 clutter_actor_set_background_color (ClutterActor       *self,
15482                                     const ClutterColor *color)
15483 {
15484   ClutterActorPrivate *priv;
15485
15486   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15487
15488   priv = self->priv;
15489
15490   if (color == NULL)
15491     {
15492       priv->bg_color_set = FALSE;
15493       g_object_notify_by_pspec (G_OBJECT (self),
15494                                 obj_props[PROP_BACKGROUND_COLOR_SET]);
15495       return;
15496     }
15497
15498   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
15499     return;
15500
15501   priv->bg_color = *color;
15502   priv->bg_color_set = TRUE;
15503
15504   clutter_actor_queue_redraw (self);
15505
15506   g_object_notify_by_pspec (G_OBJECT (self),
15507                             obj_props[PROP_BACKGROUND_COLOR_SET]);
15508   g_object_notify_by_pspec (G_OBJECT (self),
15509                             obj_props[PROP_BACKGROUND_COLOR]);
15510 }
15511
15512 /**
15513  * clutter_actor_get_background_color:
15514  * @self: a #ClutterActor
15515  * @color: (out caller-allocates): return location for a #ClutterColor
15516  *
15517  * Retrieves the color set using clutter_actor_set_background_color().
15518  *
15519  * Since: 1.10
15520  */
15521 void
15522 clutter_actor_get_background_color (ClutterActor *self,
15523                                     ClutterColor *color)
15524 {
15525   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15526   g_return_if_fail (color != NULL);
15527
15528   *color = self->priv->bg_color;
15529 }
15530
15531 /**
15532  * clutter_actor_get_previous_sibling:
15533  * @self: a #ClutterActor
15534  *
15535  * Retrieves the sibling of @self that comes before it in the list
15536  * of children of @self's parent.
15537  *
15538  * The returned pointer is only valid until the scene graph changes; it
15539  * is not safe to modify the list of children of @self while iterating
15540  * it.
15541  *
15542  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15543  *
15544  * Since: 1.10
15545  */
15546 ClutterActor *
15547 clutter_actor_get_previous_sibling (ClutterActor *self)
15548 {
15549   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15550
15551   return self->priv->prev_sibling;
15552 }
15553
15554 /**
15555  * clutter_actor_get_next_sibling:
15556  * @self: a #ClutterActor
15557  *
15558  * Retrieves the sibling of @self that comes after it in the list
15559  * of children of @self's parent.
15560  *
15561  * The returned pointer is only valid until the scene graph changes; it
15562  * is not safe to modify the list of children of @self while iterating
15563  * it.
15564  *
15565  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15566  *
15567  * Since: 1.10
15568  */
15569 ClutterActor *
15570 clutter_actor_get_next_sibling (ClutterActor *self)
15571 {
15572   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15573
15574   return self->priv->next_sibling;
15575 }
15576
15577 /**
15578  * clutter_actor_get_first_child:
15579  * @self: a #ClutterActor
15580  *
15581  * Retrieves the first child of @self.
15582  *
15583  * The returned pointer is only valid until the scene graph changes; it
15584  * is not safe to modify the list of children of @self while iterating
15585  * it.
15586  *
15587  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15588  *
15589  * Since: 1.10
15590  */
15591 ClutterActor *
15592 clutter_actor_get_first_child (ClutterActor *self)
15593 {
15594   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15595
15596   return self->priv->first_child;
15597 }
15598
15599 /**
15600  * clutter_actor_get_last_child:
15601  * @self: a #ClutterActor
15602  *
15603  * Retrieves the last child of @self.
15604  *
15605  * The returned pointer is only valid until the scene graph changes; it
15606  * is not safe to modify the list of children of @self while iterating
15607  * it.
15608  *
15609  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15610  *
15611  * Since: 1.10
15612  */
15613 ClutterActor *
15614 clutter_actor_get_last_child (ClutterActor *self)
15615 {
15616   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15617
15618   return self->priv->last_child;
15619 }
15620
15621 /* easy way to have properly named fields instead of the dummy ones
15622  * we use in the public structure
15623  */
15624 typedef struct _RealActorIter
15625 {
15626   ClutterActor *root;           /* dummy1 */
15627   ClutterActor *current;        /* dummy2 */
15628   gpointer padding_1;           /* dummy3 */
15629   gint age;                     /* dummy4 */
15630   gpointer padding_2;           /* dummy5 */
15631 } RealActorIter;
15632
15633 /**
15634  * clutter_actor_iter_init:
15635  * @iter: a #ClutterActorIter
15636  * @root: a #ClutterActor
15637  *
15638  * Initializes a #ClutterActorIter, which can then be used to iterate
15639  * efficiently over a section of the scene graph, and associates it
15640  * with @root.
15641  *
15642  * Modifying the scene graph section that contains @root will invalidate
15643  * the iterator.
15644  *
15645  * |[
15646  *   ClutterActorIter iter;
15647  *   ClutterActor *child;
15648  *
15649  *   clutter_actor_iter_init (&iter, container);
15650  *   while (clutter_actor_iter_next (&iter, &child))
15651  *     {
15652  *       /&ast; do something with child &ast;/
15653  *     }
15654  * ]|
15655  *
15656  * Since: 1.10
15657  */
15658 void
15659 clutter_actor_iter_init (ClutterActorIter *iter,
15660                          ClutterActor     *root)
15661 {
15662   RealActorIter *ri = (RealActorIter *) iter;
15663
15664   g_return_if_fail (iter != NULL);
15665   g_return_if_fail (CLUTTER_IS_ACTOR (root));
15666
15667   ri->root = root;
15668   ri->current = NULL;
15669   ri->age = root->priv->age;
15670 }
15671
15672 /**
15673  * clutter_actor_iter_next:
15674  * @iter: a #ClutterActorIter
15675  * @child: (out): return location for a #ClutterActor
15676  *
15677  * Advances the @iter and retrieves the next child of the root #ClutterActor
15678  * that was used to initialize the #ClutterActorIterator.
15679  *
15680  * If the iterator can advance, this function returns %TRUE and sets the
15681  * @child argument.
15682  *
15683  * If the iterator cannot advance, this function returns %FALSE, and
15684  * the contents of @child are undefined.
15685  *
15686  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15687  *
15688  * Since: 1.10
15689  */
15690 gboolean
15691 clutter_actor_iter_next (ClutterActorIter  *iter,
15692                          ClutterActor     **child)
15693 {
15694   RealActorIter *ri = (RealActorIter *) iter;
15695
15696   g_return_val_if_fail (iter != NULL, FALSE);
15697   g_return_val_if_fail (ri->root != NULL, FALSE);
15698 #ifndef G_DISABLE_ASSERT
15699   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15700 #endif
15701
15702   if (ri->current == NULL)
15703     ri->current = ri->root->priv->first_child;
15704   else
15705     ri->current = ri->current->priv->next_sibling;
15706
15707   if (child != NULL)
15708     *child = ri->current;
15709
15710   return ri->current != NULL;
15711 }
15712
15713 /**
15714  * clutter_actor_iter_next:
15715  * @iter: a #ClutterActorIter
15716  * @child: (out): return location for a #ClutterActor
15717  *
15718  * Advances the @iter and retrieves the previous child of the root
15719  * #ClutterActor that was used to initialize the #ClutterActorIterator.
15720  *
15721  * If the iterator can advance, this function returns %TRUE and sets the
15722  * @child argument.
15723  *
15724  * If the iterator cannot advance, this function returns %FALSE, and
15725  * the contents of @child are undefined.
15726  *
15727  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
15728  *
15729  * Since: 1.10
15730  */
15731 gboolean
15732 clutter_actor_iter_prev (ClutterActorIter  *iter,
15733                          ClutterActor     **child)
15734 {
15735   RealActorIter *ri = (RealActorIter *) iter;
15736
15737   g_return_val_if_fail (iter != NULL, FALSE);
15738   g_return_val_if_fail (ri->root != NULL, FALSE);
15739 #ifndef G_DISABLE_ASSERT
15740   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
15741 #endif
15742
15743   if (ri->current == NULL)
15744     ri->current = ri->root->priv->last_child;
15745   else
15746     ri->current = ri->current->priv->prev_sibling;
15747
15748   if (child != NULL)
15749     *child = ri->current;
15750
15751   return ri->current != NULL;
15752 }
15753
15754 /**
15755  * clutter_actor_iter_remove:
15756  * @iter: a #ClutterActorIter
15757  *
15758  * Safely removes the #ClutterActor currently pointer to by the iterator
15759  * from its parent.
15760  *
15761  * This function can only be called after clutter_actor_iter_next() or
15762  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15763  * than once for the same actor.
15764  *
15765  * This function will call clutter_actor_remove_child() internally.
15766  *
15767  * Since: 1.10
15768  */
15769 void
15770 clutter_actor_iter_remove (ClutterActorIter *iter)
15771 {
15772   RealActorIter *ri = (RealActorIter *) iter;
15773   ClutterActor *cur;
15774
15775   g_return_if_fail (iter != NULL);
15776   g_return_if_fail (ri->root != NULL);
15777 #ifndef G_DISABLE_ASSERT
15778   g_return_if_fail (ri->age == ri->root->priv->age);
15779 #endif
15780   g_return_if_fail (ri->current != NULL);
15781
15782   cur = ri->current;
15783
15784   if (cur != NULL)
15785     {
15786       ri->current = cur->priv->prev_sibling;
15787
15788       clutter_actor_remove_child_internal (ri->root, cur,
15789                                            REMOVE_CHILD_DEFAULT_FLAGS);
15790
15791       ri->age += 1;
15792     }
15793 }
15794
15795 /**
15796  * clutter_actor_iter_destroy:
15797  * @iter: a #ClutterActorIter
15798  *
15799  * Safely destroys the #ClutterActor currently pointer to by the iterator
15800  * from its parent.
15801  *
15802  * This function can only be called after clutter_actor_iter_next() or
15803  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
15804  * than once for the same actor.
15805  *
15806  * This function will call clutter_actor_destroy() internally.
15807  *
15808  * Since: 1.10
15809  */
15810 void
15811 clutter_actor_iter_destroy (ClutterActorIter *iter)
15812 {
15813   RealActorIter *ri = (RealActorIter *) iter;
15814   ClutterActor *cur;
15815
15816   g_return_if_fail (iter != NULL);
15817   g_return_if_fail (ri->root != NULL);
15818 #ifndef G_DISABLE_ASSERT
15819   g_return_if_fail (ri->age == ri->root->priv->age);
15820 #endif
15821   g_return_if_fail (ri->current != NULL);
15822
15823   cur = ri->current;
15824
15825   if (cur != NULL)
15826     {
15827       ri->current = cur->priv->prev_sibling;
15828
15829       clutter_actor_destroy (cur);
15830
15831       ri->age += 1;
15832     }
15833 }