actor: Ensure we use the current easing duration and mode
[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, 2011, 2012 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: The basic element of the scene graph 
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-painting">
119  *   <title>Painting an actor</title>
120  *   <para>There are three ways to paint an actor:</para>
121  *   <itemizedlist>
122  *     <listitem><para>set a delegate #ClutterContent as the value for the
123  *     #ClutterActor:content property of the actor;</para></listitem>
124  *     <listitem><para>subclass #ClutterActor and override the
125  *     #ClutterActorClass.paint_node() virtual function;</para></listitem>
126  *     <listitem><para>subclass #ClutterActor and override the
127  *     #ClutterActorClass.paint() virtual function.</para></listitem>
128  *   </itemizedlist>
129  *   <formalpara>
130  *     <title>Setting the Content property</title>
131  *     <para>A #ClutterContent is a delegate object that takes over the
132  *     painting operation of one, or more actors. The #ClutterContent
133  *     painting will be performed on top of the #ClutterActor:background-color
134  *     of the actor, and before calling the #ClutterActorClass.paint_node()
135  *     virtual function.</para>
136  *     <informalexample><programlisting>
137  * ClutterActor *actor = clutter_actor_new ();
138  *
139  * /&ast; set the bounding box &ast;/
140  * clutter_actor_set_position (actor, 50, 50);
141  * clutter_actor_set_size (actor, 100, 100);
142  *
143  * /&ast; set the content; the image_content variable is set elsewhere &ast;/
144  * clutter_actor_set_content (actor, image_content);
145  *     </programlisting></informalexample>
146  *   </formalpara>
147  *   <formalpara>
148  *     <title>Overriding the paint_node virtual function</title>
149  *     <para>The #ClutterActorClass.paint_node() virtual function is invoked
150  *     whenever an actor needs to be painted. The implementation of the
151  *     virtual function must only paint the contents of the actor itself,
152  *     and not the contents of its children, if the actor has any.</para>
153  *     <para>The #ClutterPaintNode passed to the virtual function is the
154  *     local root of the render tree; any node added to it will be
155  *     rendered at the correct position, as defined by the actor's
156  *     #ClutterActor:allocation.</para>
157  *     <informalexample><programlisting>
158  * static void
159  * my_actor_paint_node (ClutterActor     *actor,
160  *                      ClutterPaintNode *root)
161  * {
162  *   ClutterPaintNode *node;
163  *   ClutterActorBox box;
164  *
165  *   /&ast; where the content of the actor should be painted &ast;/
166  *   clutter_actor_get_allocation_box (actor, &box);
167  *
168  *   /&ast; the cogl_texture variable is set elsewhere &ast;/
169  *   node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170  *                                    CLUTTER_SCALING_FILTER_TRILINEAR,
171  *                                    CLUTTER_SCALING_FILTER_LINEAR);
172  *
173  *   /&ast; paint the content of the node using the allocation &ast;/
174  *   clutter_paint_node_add_rectangle (node, &box);
175  *
176  *   /&ast; add the node, and transfer ownership &ast;/
177  *   clutter_paint_node_add_child (root, node);
178  *   clutter_paint_node_unref (node);
179  * }
180  *     </programlisting></informalexample>
181  *   </formalpara>
182  *   <formalpara>
183  *     <title>Overriding the paint virtual function</title>
184  *     <para>The #ClutterActorClass.paint() virtual function is invoked
185  *     when the #ClutterActor::paint signal is emitted, and after the other
186  *     signal handlers have been invoked. Overriding the paint virtual
187  *     function gives total control to the paint sequence of the actor
188  *     itself, including the children of the actor, if any.</para>
189  *     <warning><para>It is strongly discouraged to override the
190  *     #ClutterActorClass.paint() virtual function, as well as connecting
191  *     to the #ClutterActor::paint signal. These hooks into the paint
192  *     sequence are considered legacy, and will be removed when the Clutter
193  *     API changes.</para></warning>
194  *   </formalpara>
195  * </refsect2>
196  *
197  * <refsect2 id="ClutterActor-events">
198  *   <title>Handling events on an actor</title>
199  *   <para>A #ClutterActor can receive and handle input device events, for
200  *   instance pointer events and key events, as long as its
201  *   #ClutterActor:reactive property is set to %TRUE.</para>
202  *   <para>Once an actor has been determined to be the source of an event,
203  *   Clutter will traverse the scene graph from the top-level actor towards the
204  *   event source, emitting the #ClutterActor::captured-event signal on each
205  *   ancestor until it reaches the source; this phase is also called
206  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
207  *   stopped, the graph is walked backwards, from the source actor to the
208  *   top-level, and the #ClutterActor::event signal, along with other event
209  *   signals if needed, is emitted; this phase is also called <emphasis>the
210  *   bubble phase</emphasis>. At any point of the signal emission, signal
211  *   handlers can stop the propagation through the scene graph by returning
212  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
214  * </refsect2>
215  *
216  * <refsect2 id="ClutterActor-animation">
217  *   <title>Animation</title>
218  *   <para>Animation is a core concept of modern user interfaces; Clutter
219  *   provides a complete and powerful animation framework that automatically
220  *   tweens the actor's state without requiring direct, frame by frame
221  *   manipulation from your application code.</para>
222  *   <formalpara>
223  *     <title>Implicit animations</title>
224  *     <para>The implicit animation model of Clutter assumes that all the
225  *     changes in an actor state should be gradual and asynchronous; Clutter
226  *     will automatically transition an actor's property change between the
227  *     current state and the desired one without manual intervention.</para>
228  *     <para>By default, in the 1.0 API series, the transition happens with
229  *     a duration of zero milliseconds, and the implicit animation is an
230  *     opt in feature to retain backwards compatibility. In order to enable
231  *     implicit animations, it is necessary to change the easing state of
232  *     an actor by using clutter_actor_save_easing_state():</para>
233  *     <informalexample><programlisting>
234  * /&ast; assume that the actor is currently positioned at (100, 100) &ast;/
235  * clutter_actor_save_easing_state (actor);
236  * clutter_actor_set_position (actor, 500, 500);
237  * clutter_actor_restore_easing_state (actor);
238  *     </programlisting></informalexample>
239  *     <para>The example above will trigger an implicit animation of the
240  *     actor between its current position to a new position.</para>
241  *     <para>It is possible to animate multiple properties of an actor
242  *     at the same time, and you can animate multiple actors at the same
243  *     time as well, for instance:</para>
244  *     <informalexample><programlisting>
245  * /&ast; animate the actor's opacity and depth &ast;/
246  * clutter_actor_save_easing_state (actor);
247  * clutter_actor_set_opacity (actor, 0);
248  * clutter_actor_set_depth (actor, -100);
249  * clutter_actor_restore_easing_state (actor);
250  *
251  * /&ast; animate another actor's opacity &ast;/
252  * clutter_actor_save_easing_state (another_actor);
253  * clutter_actor_set_opacity (another_actor, 255);
254  * clutter_actor_set_depth (another_actor, 100);
255  * clutter_actor_restore_easing_state (another_actor);
256  *     </programlisting></informalexample>
257  *     <para>Implicit animations use a default duration of 250 milliseconds,
258  *     and a default easing mode of %CLUTTER_EASE_OUT_CUBIC, unless you call
259  *     clutter_actor_set_easing_mode() and clutter_actor_set_easing_duration()
260  *     after changing the easing state of the actor.</para>
261  *     <para>It is important to note that if you modify the state on an
262  *     animatable property while a transition is in flight, the transition's
263  *     final value will be updated, as well as its duration and progress
264  *     mode by using the current easing state; for instance, in the following
265  *     example:</para>
266  *     <informalexample><programlisting>
267  * clutter_actor_save_easing_state (actor);
268  * clutter_actor_set_x (actor, 200);
269  * clutter_actor_restore_easing_state (actor);
270  *
271  * clutter_actor_save_easing_state (actor);
272  * clutter_actor_set_x (actor, 100);
273  * clutter_actor_restore_easing_state (actor);
274  *     </programlisting></informalexample>
275  *     <para>the first call to clutter_actor_set_x() will begin a transition
276  *     of the #ClutterActor:x property to the value of 200; the second call
277  *     to clutter_actor_set_x() will change the transition's final value to
278  *     100.</para>
279  *     <para>It is possible to retrieve the #ClutterTransition used by the
280  *     animatable properties by using clutter_actor_get_transition() and using
281  *     the property name as the transition name.</para>
282  *   </formalpara>
283  *   <formalpara>
284  *     <title>Explicit animations</title>
285  *     <para>The explicit animation model supported by Clutter requires that
286  *     you create a #ClutterTransition object, and set the initial and
287  *     final values. The transition will not start unless you add it to the
288  *     #ClutterActor.</para>
289  *     <informalexample><programlisting>
290  * ClutterTransition *transition;
291  *
292  * transition = clutter_property_transition_new ("opacity");
293  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000);
294  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
295  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
296  * clutter_transition_set_interval (transition, clutter_interval_new (G_TYPE_UINT, 255, 0));
297  *
298  * clutter_actor_add_transition (actor, "animate-opacity", transition);
299  *     </programlisting></informalexample>
300  *     <para>The example above will animate the #ClutterActor:opacity property
301  *     of an actor between fully opaque and fully transparent, and back, over
302  *     a span of 3 seconds. The animation does not begin until it is added to
303  *     the actor.</para>
304  *     <para>The explicit animation API should also be used when using custom
305  *     animatable properties for #ClutterAction, #ClutterConstraint, and
306  *     #ClutterEffect instances associated to an actor; see the section on
307  *     <ulink linkend="ClutterActor-custom-animatable-properties">custom
308  *     animatable properties below</ulink> for an example.</para>
309  *     <para>Finally, explicit animations are useful for creating animations
310  *     that run continuously, for instance:</para>
311  *     <informalexample><programlisting>
312  * /&ast; this animation will pulse the actor's opacity continuously &ast;/
313  * ClutterTransition *transition;
314  * ClutterInterval *interval;
315  *
316  * transition = clutter_property_transition_new ("opacity");
317  *
318  * /&ast; we want to animate the opacity between 0 and 255 &ast;/
319  * internal = clutter_interval_new (G_TYPE_UINT, 0, 255);
320  * clutter_transition_set_interval (transition, interval);
321  *
322  * /&ast; over a one second duration, running an infinite amount of times &ast;/
323  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
324  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
325  *
326  * /&ast; we want to fade in and out, so we need to auto-reverse the transition &ast;/
327  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
328  *
329  * /&ast; and we want to use an easing function that eases both in and out &ast;/
330  * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
331  *                                     CLUTTER_EASE_IN_OUT_CUBIC);
332  *
333  * /&ast; add the transition to the desired actor; this will
334  *  &ast; start the animation.
335  *  &ast;/
336  * clutter_actor_add_transition (actor, "opacityAnimation", transition);
337  *     </programlisting></informalexample>
338  *   </formalpara>
339  * </refsect2>
340  *
341  * <refsect2 id="ClutterActor-subclassing">
342  *   <title>Implementing an actor</title>
343  *   <para>Careful consideration should be given when deciding to implement
344  *   a #ClutterActor sub-class. It is generally recommended to implement a
345  *   sub-class of #ClutterActor only for actors that should be used as leaf
346  *   nodes of a scene graph.</para>
347  *   <para>If your actor should be painted in a custom way, you should
348  *   override the #ClutterActor::paint signal class handler. You can either
349  *   opt to chain up to the parent class implementation or decide to fully
350  *   override the default paint implementation; Clutter will set up the
351  *   transformations and clip regions prior to emitting the #ClutterActor::paint
352  *   signal.</para>
353  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
354  *   #ClutterActorClass.get_preferred_height() virtual functions it is
355  *   possible to change or provide the preferred size of an actor; similarly,
356  *   by overriding the #ClutterActorClass.allocate() virtual function it is
357  *   possible to control the layout of the children of an actor. Make sure to
358  *   always chain up to the parent implementation of the
359  *   #ClutterActorClass.allocate() virtual function.</para>
360  *   <para>In general, it is strongly encouraged to use delegation and
361  *   composition instead of direct subclassing.</para>
362  * </refsect2>
363  *
364  * <refsect2 id="ClutterActor-script">
365  *   <title>ClutterActor custom properties for #ClutterScript</title>
366  *   <para>#ClutterActor defines a custom "rotation" property which
367  *   allows a short-hand description of the rotations to be applied
368  *   to an actor.</para>
369  *   <para>The syntax of the "rotation" property is the following:</para>
370  *   <informalexample>
371  *     <programlisting>
372  * "rotation" : [
373  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
374  * ]
375  *     </programlisting>
376  *   </informalexample>
377  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
378  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
379  *   floating point value representing the rotation angle on the given axis,
380  *   in degrees.</para>
381  *   <para>The <emphasis>center</emphasis> array is optional, and if present
382  *   it must contain the center of rotation as described by two coordinates:
383  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
384  *   "z-axis".</para>
385  *   <para>#ClutterActor will also parse every positional and dimensional
386  *   property defined as a string through clutter_units_from_string(); you
387  *   should read the documentation for the #ClutterUnits parser format for
388  *   the valid units and syntax.</para>
389  * </refsect2>
390  *
391  * <refsect2 id="ClutterActor-custom-animatable-properties">
392  *   <title>Custom animatable properties</title>
393  *   <para>#ClutterActor allows accessing properties of #ClutterAction,
394  *   #ClutterEffect, and #ClutterConstraint instances associated to an actor
395  *   instance for animation purposes.</para>
396  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
397  *   property it is necessary to set the #ClutterActorMeta:name property on the
398  *   given action or constraint.</para>
399  *   <para>The property can be accessed using the following syntax:</para>
400  *   <informalexample>
401  *     <programlisting>
402  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
403  *     </programlisting>
404  *   </informalexample>
405  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
406  *   <para>The <emphasis>section</emphasis> fragment can be one between
407  *   "actions", "constraints" and "effects".</para>
408  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
409  *   action or constraint, as specified by the #ClutterActorMeta:name
410  *   property.</para>
411  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
412  *   action or constraint property to be animated.</para>
413  *   <para>The example below animates a #ClutterBindConstraint applied to an
414  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
415  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
416  *   its initial state is overlapping the actor to which is bound to.</para>
417  *   <informalexample><programlisting>
418  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
419  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
420  * clutter_actor_add_constraint (rect, constraint);
421  *
422  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
423  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
424  * clutter_actor_add_constraint (rect, constraint);
425  *
426  * clutter_actor_set_reactive (origin, TRUE);
427  *
428  * g_signal_connect (origin, "button-press-event",
429  *                   G_CALLBACK (on_button_press),
430  *                   rect);
431  *   </programlisting></informalexample>
432  *   <para>On button press, the rectangle "slides" from behind the actor to
433  *   which is bound to, using the #ClutterBindConstraint:offset property to
434  *   achieve the effect:</para>
435  *   <informalexample><programlisting>
436  * gboolean
437  * on_button_press (ClutterActor *origin,
438  *                  ClutterEvent *event,
439  *                  ClutterActor *rect)
440  * {
441  *   ClutterTransition *transition;
442  *   ClutterInterval *interval;
443  *
444  *   /&ast; the offset that we want to apply; this will make the actor
445  *    &ast; slide in from behind the origin and rest at the right of
446  *    &ast; the origin, plus a padding value.
447  *    &ast;/
448  *   float new_offset = clutter_actor_get_width (origin) + h_padding;
449  *
450  *   /&ast; the property we wish to animate; the "@constraints" section
451  *    &ast; tells Clutter to check inside the constraints associated
452  *    &ast; with the actor; the "bind-x" section is the name of the
453  *    &ast; constraint; and the "offset" is the name of the property
454  *    &ast; on the constraint.
455  *    &ast;/
456  *   const char *prop = "@constraints.bind-x.offset";
457  *
458  *   /&ast; create a new transition for the given property &ast;/
459  *   transition = clutter_property_transition_new (prop);
460  *
461  *   /&ast; set the easing mode and duration &ast;/
462  *   clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
463  *                                       CLUTTER_EASE_OUT_CUBIC);
464  *   clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
465  *
466  *   /&ast; create the interval with the initial and final values &ast;/
467  *   interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
468  *   clutter_transition_set_interval (transition, interval);
469  *
470  *   /&ast; add the transition to the actor; this causes the animation
471  *    &ast; to start. the name "offsetAnimation" can be used to retrieve
472  *    &ast; the transition later.
473  *    &ast;/
474  *   clutter_actor_add_transition (rect, "offsetAnimation", transition);
475  *
476  *   /&ast; we handled the event &ast;/
477  *   return CLUTTER_EVENT_STOP;
478  * }
479  *   </programlisting></informalexample>
480  * </refsect2>
481  */
482
483 /**
484  * CLUTTER_ACTOR_IS_MAPPED:
485  * @a: a #ClutterActor
486  *
487  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
488  *
489  * The mapped state is set when the actor is visible and all its parents up
490  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
491  *
492  * This check can be used to see if an actor is going to be painted, as only
493  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
494  *
495  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
496  * not be checked directly; instead, the recommended usage is to connect a
497  * handler on the #GObject::notify signal for the #ClutterActor:mapped
498  * property of #ClutterActor, and check the presence of
499  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
500  *
501  * It is also important to note that Clutter may delay the changes of
502  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
503  * limitations, or during the reparenting of an actor, to optimize
504  * unnecessary (and potentially expensive) state changes.
505  *
506  * Since: 0.2
507  */
508
509 /**
510  * CLUTTER_ACTOR_IS_REALIZED:
511  * @a: a #ClutterActor
512  *
513  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
514  *
515  * The realized state has an actor-dependant interpretation. If an
516  * actor wants to delay allocating resources until it is attached to a
517  * stage, it may use the realize state to do so. However it is
518  * perfectly acceptable for an actor to allocate Cogl resources before
519  * being realized because there is only one drawing context used by Clutter
520  * so any resources will work on any stage.  If an actor is mapped it
521  * must also be realized, but an actor can be realized and unmapped
522  * (this is so hiding an actor temporarily doesn't do an expensive
523  * unrealize/realize).
524  *
525  * To be realized an actor must be inside a stage, and all its parents
526  * must be realized.
527  *
528  * Since: 0.2
529  */
530
531 /**
532  * CLUTTER_ACTOR_IS_VISIBLE:
533  * @a: a #ClutterActor
534  *
535  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
536  * Equivalent to the ClutterActor::visible object property.
537  *
538  * Note that an actor is only painted onscreen if it's mapped, which
539  * means it's visible, and all its parents are visible, and one of the
540  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
541  *
542  * Since: 0.2
543  */
544
545 /**
546  * CLUTTER_ACTOR_IS_REACTIVE:
547  * @a: a #ClutterActor
548  *
549  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
550  *
551  * Only reactive actors will receive event-related signals.
552  *
553  * Since: 0.6
554  */
555
556 #ifdef HAVE_CONFIG_H
557 #include "config.h"
558 #endif
559
560 #include <math.h>
561
562 #include <gobject/gvaluecollector.h>
563
564 #include <cogl/cogl.h>
565
566 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
567 #define CLUTTER_ENABLE_EXPERIMENTAL_API
568
569 #include "clutter-actor-private.h"
570
571 #include "clutter-action.h"
572 #include "clutter-actor-meta-private.h"
573 #include "clutter-animatable.h"
574 #include "clutter-color-static.h"
575 #include "clutter-color.h"
576 #include "clutter-constraint.h"
577 #include "clutter-container.h"
578 #include "clutter-content-private.h"
579 #include "clutter-debug.h"
580 #include "clutter-effect-private.h"
581 #include "clutter-enum-types.h"
582 #include "clutter-fixed-layout.h"
583 #include "clutter-flatten-effect.h"
584 #include "clutter-interval.h"
585 #include "clutter-main.h"
586 #include "clutter-marshal.h"
587 #include "clutter-paint-nodes.h"
588 #include "clutter-paint-node-private.h"
589 #include "clutter-paint-volume-private.h"
590 #include "clutter-private.h"
591 #include "clutter-profile.h"
592 #include "clutter-property-transition.h"
593 #include "clutter-scriptable.h"
594 #include "clutter-script-private.h"
595 #include "clutter-stage-private.h"
596 #include "clutter-timeline.h"
597 #include "clutter-transition.h"
598 #include "clutter-units.h"
599
600 #include "deprecated/clutter-actor.h"
601 #include "deprecated/clutter-behaviour.h"
602 #include "deprecated/clutter-container.h"
603
604 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
605 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
606
607 /* Internal enum used to control mapped state update.  This is a hint
608  * which indicates when to do something other than just enforce
609  * invariants.
610  */
611 typedef enum {
612   MAP_STATE_CHECK,           /* just enforce invariants. */
613   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
614                               * used when about to unparent.
615                               */
616   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
617                               * used to set mapped on toplevels.
618                               */
619   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
620                               * used just before unmapping parent.
621                               */
622 } MapStateChange;
623
624 /* 3 entries should be a good compromise, few layout managers
625  * will ask for 3 different preferred size in each allocation cycle */
626 #define N_CACHED_SIZE_REQUESTS 3
627
628 struct _ClutterActorPrivate
629 {
630   /* request mode */
631   ClutterRequestMode request_mode;
632
633   /* our cached size requests for different width / height */
634   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
635   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
636
637   /* An age of 0 means the entry is not set */
638   guint cached_height_age;
639   guint cached_width_age;
640
641   /* the bounding box of the actor, relative to the parent's
642    * allocation
643    */
644   ClutterActorBox allocation;
645   ClutterAllocationFlags allocation_flags;
646
647   /* clip, in actor coordinates */
648   cairo_rectangle_t clip;
649
650   /* the cached transformation matrix; see apply_transform() */
651   CoglMatrix transform;
652
653   guint8 opacity;
654   gint opacity_override;
655
656   ClutterOffscreenRedirect offscreen_redirect;
657
658   /* This is an internal effect used to implement the
659      offscreen-redirect property */
660   ClutterEffect *flatten_effect;
661
662   /* scene graph */
663   ClutterActor *parent;
664   ClutterActor *prev_sibling;
665   ClutterActor *next_sibling;
666   ClutterActor *first_child;
667   ClutterActor *last_child;
668
669   gint n_children;
670
671   /* tracks whenever the children of an actor are changed; the
672    * age is incremented by 1 whenever an actor is added or
673    * removed. the age is not incremented when the first or the
674    * last child pointers are changed, or when grandchildren of
675    * an actor are changed.
676    */
677   gint age;
678
679   gchar *name; /* a non-unique name, used for debugging */
680   guint32 id; /* unique id, used for backward compatibility */
681
682   gint32 pick_id; /* per-stage unique id, used for picking */
683
684   /* a back-pointer to the Pango context that we can use
685    * to create pre-configured PangoLayout
686    */
687   PangoContext *pango_context;
688
689   /* the text direction configured for this child - either by
690    * application code, or by the actor's parent
691    */
692   ClutterTextDirection text_direction;
693
694   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
695   gint internal_child;
696
697   /* meta classes */
698   ClutterMetaGroup *actions;
699   ClutterMetaGroup *constraints;
700   ClutterMetaGroup *effects;
701
702   /* delegate object used to allocate the children of this actor */
703   ClutterLayoutManager *layout_manager;
704
705   /* delegate object used to paint the contents of this actor */
706   ClutterContent *content;
707
708   ClutterContentGravity content_gravity;
709   ClutterScalingFilter min_filter;
710   ClutterScalingFilter mag_filter;
711
712   /* used when painting, to update the paint volume */
713   ClutterEffect *current_effect;
714
715   /* This is used to store an effect which needs to be redrawn. A
716      redraw can be queued to start from a particular effect. This is
717      used by parametrised effects that can cache an image of the
718      actor. If a parameter of the effect changes then it only needs to
719      redraw the cached image, not the actual actor. The pointer is
720      only valid if is_dirty == TRUE. If the pointer is NULL then the
721      whole actor is dirty. */
722   ClutterEffect *effect_to_redraw;
723
724   /* This is used when painting effects to implement the
725      clutter_actor_continue_paint() function. It points to the node in
726      the list of effects that is next in the chain */
727   const GList *next_effect_to_paint;
728
729   ClutterPaintVolume paint_volume;
730
731   /* NB: This volume isn't relative to this actor, it is in eye
732    * coordinates so that it can remain valid after the actor changes.
733    */
734   ClutterPaintVolume last_paint_volume;
735
736   ClutterStageQueueRedrawEntry *queue_redraw_entry;
737
738   ClutterColor bg_color;
739
740   /* bitfields */
741
742   /* fixed position and sizes */
743   guint position_set                : 1;
744   guint min_width_set               : 1;
745   guint min_height_set              : 1;
746   guint natural_width_set           : 1;
747   guint natural_height_set          : 1;
748   /* cached request is invalid (implies allocation is too) */
749   guint needs_width_request         : 1;
750   /* cached request is invalid (implies allocation is too) */
751   guint needs_height_request        : 1;
752   /* cached allocation is invalid (request has changed, probably) */
753   guint needs_allocation            : 1;
754   guint show_on_set_parent          : 1;
755   guint has_clip                    : 1;
756   guint clip_to_allocation          : 1;
757   guint enable_model_view_transform : 1;
758   guint enable_paint_unmapped       : 1;
759   guint has_pointer                 : 1;
760   guint propagated_one_redraw       : 1;
761   guint paint_volume_valid          : 1;
762   guint last_paint_volume_valid     : 1;
763   guint in_clone_paint              : 1;
764   guint transform_valid             : 1;
765   /* This is TRUE if anything has queued a redraw since we were last
766      painted. In this case effect_to_redraw will point to an effect
767      the redraw was queued from or it will be NULL if the redraw was
768      queued without an effect. */
769   guint is_dirty                    : 1;
770   guint bg_color_set                : 1;
771 };
772
773 enum
774 {
775   PROP_0,
776
777   PROP_NAME,
778
779   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
780    * when set they force a size request, when gotten they
781    * get the allocation if the allocation is valid, and the
782    * request otherwise
783    */
784   PROP_X,
785   PROP_Y,
786   PROP_WIDTH,
787   PROP_HEIGHT,
788
789   /* Then the rest of these size-related properties are the "actual"
790    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
791    */
792   PROP_FIXED_X,
793   PROP_FIXED_Y,
794
795   PROP_FIXED_POSITION_SET,
796
797   PROP_MIN_WIDTH,
798   PROP_MIN_WIDTH_SET,
799
800   PROP_MIN_HEIGHT,
801   PROP_MIN_HEIGHT_SET,
802
803   PROP_NATURAL_WIDTH,
804   PROP_NATURAL_WIDTH_SET,
805
806   PROP_NATURAL_HEIGHT,
807   PROP_NATURAL_HEIGHT_SET,
808
809   PROP_REQUEST_MODE,
810
811   /* Allocation properties are read-only */
812   PROP_ALLOCATION,
813
814   PROP_DEPTH,
815
816   PROP_CLIP,
817   PROP_HAS_CLIP,
818   PROP_CLIP_TO_ALLOCATION,
819
820   PROP_OPACITY,
821
822   PROP_OFFSCREEN_REDIRECT,
823
824   PROP_VISIBLE,
825   PROP_MAPPED,
826   PROP_REALIZED,
827   PROP_REACTIVE,
828
829   PROP_SCALE_X,
830   PROP_SCALE_Y,
831   PROP_SCALE_CENTER_X,
832   PROP_SCALE_CENTER_Y,
833   PROP_SCALE_GRAVITY,
834
835   PROP_ROTATION_ANGLE_X,
836   PROP_ROTATION_ANGLE_Y,
837   PROP_ROTATION_ANGLE_Z,
838   PROP_ROTATION_CENTER_X,
839   PROP_ROTATION_CENTER_Y,
840   PROP_ROTATION_CENTER_Z,
841   /* This property only makes sense for the z rotation because the
842      others would depend on the actor having a size along the
843      z-axis */
844   PROP_ROTATION_CENTER_Z_GRAVITY,
845
846   PROP_ANCHOR_X,
847   PROP_ANCHOR_Y,
848   PROP_ANCHOR_GRAVITY,
849
850   PROP_SHOW_ON_SET_PARENT,
851
852   PROP_TEXT_DIRECTION,
853   PROP_HAS_POINTER,
854
855   PROP_ACTIONS,
856   PROP_CONSTRAINTS,
857   PROP_EFFECT,
858
859   PROP_LAYOUT_MANAGER,
860
861   PROP_X_ALIGN,
862   PROP_Y_ALIGN,
863   PROP_MARGIN_TOP,
864   PROP_MARGIN_BOTTOM,
865   PROP_MARGIN_LEFT,
866   PROP_MARGIN_RIGHT,
867
868   PROP_BACKGROUND_COLOR,
869   PROP_BACKGROUND_COLOR_SET,
870
871   PROP_FIRST_CHILD,
872   PROP_LAST_CHILD,
873
874   PROP_CONTENT,
875   PROP_CONTENT_GRAVITY,
876   PROP_CONTENT_BOX,
877   PROP_MINIFICATION_FILTER,
878   PROP_MAGNIFICATION_FILTER,
879
880   PROP_LAST
881 };
882
883 static GParamSpec *obj_props[PROP_LAST];
884
885 enum
886 {
887   SHOW,
888   HIDE,
889   DESTROY,
890   PARENT_SET,
891   KEY_FOCUS_IN,
892   KEY_FOCUS_OUT,
893   PAINT,
894   PICK,
895   REALIZE,
896   UNREALIZE,
897   QUEUE_REDRAW,
898   QUEUE_RELAYOUT,
899   EVENT,
900   CAPTURED_EVENT,
901   BUTTON_PRESS_EVENT,
902   BUTTON_RELEASE_EVENT,
903   SCROLL_EVENT,
904   KEY_PRESS_EVENT,
905   KEY_RELEASE_EVENT,
906   MOTION_EVENT,
907   ENTER_EVENT,
908   LEAVE_EVENT,
909   ALLOCATION_CHANGED,
910   TRANSITIONS_COMPLETED,
911
912   LAST_SIGNAL
913 };
914
915 static guint actor_signals[LAST_SIGNAL] = { 0, };
916
917 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
918 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
919 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
920 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
921
922 /* These setters are all static for now, maybe they should be in the
923  * public API, but they are perhaps obscure enough to leave only as
924  * properties
925  */
926 static void clutter_actor_set_min_width          (ClutterActor *self,
927                                                   gfloat        min_width);
928 static void clutter_actor_set_min_height         (ClutterActor *self,
929                                                   gfloat        min_height);
930 static void clutter_actor_set_natural_width      (ClutterActor *self,
931                                                   gfloat        natural_width);
932 static void clutter_actor_set_natural_height     (ClutterActor *self,
933                                                   gfloat        natural_height);
934 static void clutter_actor_set_min_width_set      (ClutterActor *self,
935                                                   gboolean      use_min_width);
936 static void clutter_actor_set_min_height_set     (ClutterActor *self,
937                                                   gboolean      use_min_height);
938 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
939                                                   gboolean  use_natural_width);
940 static void clutter_actor_set_natural_height_set (ClutterActor *self,
941                                                   gboolean  use_natural_height);
942 static void clutter_actor_update_map_state       (ClutterActor  *self,
943                                                   MapStateChange change);
944 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
945
946 /* Helper routines for managing anchor coords */
947 static void clutter_anchor_coord_get_units (ClutterActor      *self,
948                                             const AnchorCoord *coord,
949                                             gfloat            *x,
950                                             gfloat            *y,
951                                             gfloat            *z);
952 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
953                                             gfloat             x,
954                                             gfloat             y,
955                                             gfloat             z);
956
957 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
958 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
959                                                         ClutterGravity     gravity);
960
961 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
962
963 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
964
965 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
966                                                                ClutterActor *ancestor,
967                                                                CoglMatrix *matrix);
968
969 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
970
971 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
972
973 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
974                                                                 const ClutterColor *color);
975
976 static void on_layout_manager_changed (ClutterLayoutManager *manager,
977                                        ClutterActor         *self);
978
979 /* Helper macro which translates by the anchor coord, applies the
980    given transformation and then translates back */
981 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
982   gfloat _tx, _ty, _tz;                                                \
983   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
984   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
985   { _transform; }                                                      \
986   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
987
988 static GQuark quark_shader_data = 0;
989 static GQuark quark_actor_layout_info = 0;
990 static GQuark quark_actor_transform_info = 0;
991 static GQuark quark_actor_animation_info = 0;
992
993 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
994                          clutter_actor,
995                          G_TYPE_INITIALLY_UNOWNED,
996                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
997                                                 clutter_container_iface_init)
998                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
999                                                 clutter_scriptable_iface_init)
1000                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1001                                                 clutter_animatable_iface_init)
1002                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1003                                                 atk_implementor_iface_init));
1004
1005 /*< private >
1006  * clutter_actor_get_debug_name:
1007  * @actor: a #ClutterActor
1008  *
1009  * Retrieves a printable name of @actor for debugging messages
1010  *
1011  * Return value: a string with a printable name
1012  */
1013 const gchar *
1014 _clutter_actor_get_debug_name (ClutterActor *actor)
1015 {
1016   return actor->priv->name != NULL ? actor->priv->name
1017                                    : G_OBJECT_TYPE_NAME (actor);
1018 }
1019
1020 #ifdef CLUTTER_ENABLE_DEBUG
1021 /* XXX - this is for debugging only, remove once working (or leave
1022  * in only in some debug mode). Should leave it for a little while
1023  * until we're confident in the new map/realize/visible handling.
1024  */
1025 static inline void
1026 clutter_actor_verify_map_state (ClutterActor *self)
1027 {
1028   ClutterActorPrivate *priv = self->priv;
1029
1030   if (CLUTTER_ACTOR_IS_REALIZED (self))
1031     {
1032       /* all bets are off during reparent when we're potentially realized,
1033        * but should not be according to invariants
1034        */
1035       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1036         {
1037           if (priv->parent == NULL)
1038             {
1039               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1040                 {
1041                 }
1042               else
1043                 g_warning ("Realized non-toplevel actor '%s' should "
1044                            "have a parent",
1045                            _clutter_actor_get_debug_name (self));
1046             }
1047           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1048             {
1049               g_warning ("Realized actor %s has an unrealized parent %s",
1050                          _clutter_actor_get_debug_name (self),
1051                          _clutter_actor_get_debug_name (priv->parent));
1052             }
1053         }
1054     }
1055
1056   if (CLUTTER_ACTOR_IS_MAPPED (self))
1057     {
1058       if (!CLUTTER_ACTOR_IS_REALIZED (self))
1059         g_warning ("Actor '%s' is mapped but not realized",
1060                    _clutter_actor_get_debug_name (self));
1061
1062       /* remaining bets are off during reparent when we're potentially
1063        * mapped, but should not be according to invariants
1064        */
1065       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1066         {
1067           if (priv->parent == NULL)
1068             {
1069               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1070                 {
1071                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1072                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1073                     {
1074                       g_warning ("Toplevel actor '%s' is mapped "
1075                                  "but not visible",
1076                                  _clutter_actor_get_debug_name (self));
1077                     }
1078                 }
1079               else
1080                 {
1081                   g_warning ("Mapped actor '%s' should have a parent",
1082                              _clutter_actor_get_debug_name (self));
1083                 }
1084             }
1085           else
1086             {
1087               ClutterActor *iter = self;
1088
1089               /* check for the enable_paint_unmapped flag on the actor
1090                * and parents; if the flag is enabled at any point of this
1091                * branch of the scene graph then all the later checks
1092                * become pointless
1093                */
1094               while (iter != NULL)
1095                 {
1096                   if (iter->priv->enable_paint_unmapped)
1097                     return;
1098
1099                   iter = iter->priv->parent;
1100                 }
1101
1102               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1103                 {
1104                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1105                              "is not visible",
1106                              _clutter_actor_get_debug_name (self),
1107                              _clutter_actor_get_debug_name (priv->parent));
1108                 }
1109
1110               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1111                 {
1112                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1113                              "is not realized",
1114                              _clutter_actor_get_debug_name (self),
1115                              _clutter_actor_get_debug_name (priv->parent));
1116                 }
1117
1118               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1119                 {
1120                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1121                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1122                                "parent '%s' is not mapped",
1123                                _clutter_actor_get_debug_name (self),
1124                                _clutter_actor_get_debug_name (priv->parent));
1125                 }
1126             }
1127         }
1128     }
1129 }
1130
1131 #endif /* CLUTTER_ENABLE_DEBUG */
1132
1133 static void
1134 clutter_actor_set_mapped (ClutterActor *self,
1135                           gboolean      mapped)
1136 {
1137   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1138     return;
1139
1140   if (mapped)
1141     {
1142       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1143       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1144     }
1145   else
1146     {
1147       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1148       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1149     }
1150 }
1151
1152 /* this function updates the mapped and realized states according to
1153  * invariants, in the appropriate order.
1154  */
1155 static void
1156 clutter_actor_update_map_state (ClutterActor  *self,
1157                                 MapStateChange change)
1158 {
1159   gboolean was_mapped;
1160
1161   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1162
1163   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1164     {
1165       /* the mapped flag on top-level actors must be set by the
1166        * per-backend implementation because it might be asynchronous.
1167        *
1168        * That is, the MAPPED flag on toplevels currently tracks the X
1169        * server mapped-ness of the window, while the expected behavior
1170        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1171        * This creates some weird complexity by breaking the invariant
1172        * that if we're visible and all ancestors shown then we are
1173        * also mapped - instead, we are mapped if all ancestors
1174        * _possibly excepting_ the stage are mapped. The stage
1175        * will map/unmap for example when it is minimized or
1176        * moved to another workspace.
1177        *
1178        * So, the only invariant on the stage is that if visible it
1179        * should be realized, and that it has to be visible to be
1180        * mapped.
1181        */
1182       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1183         clutter_actor_realize (self);
1184
1185       switch (change)
1186         {
1187         case MAP_STATE_CHECK:
1188           break;
1189
1190         case MAP_STATE_MAKE_MAPPED:
1191           g_assert (!was_mapped);
1192           clutter_actor_set_mapped (self, TRUE);
1193           break;
1194
1195         case MAP_STATE_MAKE_UNMAPPED:
1196           g_assert (was_mapped);
1197           clutter_actor_set_mapped (self, FALSE);
1198           break;
1199
1200         case MAP_STATE_MAKE_UNREALIZED:
1201           /* we only use MAKE_UNREALIZED in unparent,
1202            * and unparenting a stage isn't possible.
1203            * If someone wants to just unrealize a stage
1204            * then clutter_actor_unrealize() doesn't
1205            * go through this codepath.
1206            */
1207           g_warning ("Trying to force unrealize stage is not allowed");
1208           break;
1209         }
1210
1211       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1212           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1213           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1214         {
1215           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1216                      "it is somehow still mapped",
1217                      _clutter_actor_get_debug_name (self));
1218         }
1219     }
1220   else
1221     {
1222       ClutterActorPrivate *priv = self->priv;
1223       ClutterActor *parent = priv->parent;
1224       gboolean should_be_mapped;
1225       gboolean may_be_realized;
1226       gboolean must_be_realized;
1227
1228       should_be_mapped = FALSE;
1229       may_be_realized = TRUE;
1230       must_be_realized = FALSE;
1231
1232       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1233         {
1234           may_be_realized = FALSE;
1235         }
1236       else
1237         {
1238           /* Maintain invariant that if parent is mapped, and we are
1239            * visible, then we are mapped ...  unless parent is a
1240            * stage, in which case we map regardless of parent's map
1241            * state but do require stage to be visible and realized.
1242            *
1243            * If parent is realized, that does not force us to be
1244            * realized; but if parent is unrealized, that does force
1245            * us to be unrealized.
1246            *
1247            * The reason we don't force children to realize with
1248            * parents is _clutter_actor_rerealize(); if we require that
1249            * a realized parent means children are realized, then to
1250            * unrealize an actor we would have to unrealize its
1251            * parents, which would end up meaning unrealizing and
1252            * hiding the entire stage. So we allow unrealizing a
1253            * child (as long as that child is not mapped) while that
1254            * child still has a realized parent.
1255            *
1256            * Also, if we unrealize from leaf nodes to root, and
1257            * realize from root to leaf, the invariants are never
1258            * violated if we allow children to be unrealized
1259            * while parents are realized.
1260            *
1261            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1262            * to force us to unmap, even though parent is still
1263            * mapped. This is because we're unmapping from leaf nodes
1264            * up to root nodes.
1265            */
1266           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1267               change != MAP_STATE_MAKE_UNMAPPED)
1268             {
1269               gboolean parent_is_visible_realized_toplevel;
1270
1271               parent_is_visible_realized_toplevel =
1272                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1273                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1274                  CLUTTER_ACTOR_IS_REALIZED (parent));
1275
1276               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1277                   parent_is_visible_realized_toplevel)
1278                 {
1279                   must_be_realized = TRUE;
1280                   should_be_mapped = TRUE;
1281                 }
1282             }
1283
1284           /* if the actor has been set to be painted even if unmapped
1285            * then we should map it and check for realization as well;
1286            * this is an override for the branch of the scene graph
1287            * which begins with this node
1288            */
1289           if (priv->enable_paint_unmapped)
1290             {
1291               if (priv->parent == NULL)
1292                 g_warning ("Attempting to map an unparented actor '%s'",
1293                            _clutter_actor_get_debug_name (self));
1294
1295               should_be_mapped = TRUE;
1296               must_be_realized = TRUE;
1297             }
1298
1299           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1300             may_be_realized = FALSE;
1301         }
1302
1303       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1304         {
1305           if (parent == NULL)
1306             g_warning ("Attempting to map a child that does not "
1307                        "meet the necessary invariants: the actor '%s' "
1308                        "has no parent",
1309                        _clutter_actor_get_debug_name (self));
1310           else
1311             g_warning ("Attempting to map a child that does not "
1312                        "meet the necessary invariants: the actor '%s' "
1313                        "is parented to an unmapped actor '%s'",
1314                        _clutter_actor_get_debug_name (self),
1315                        _clutter_actor_get_debug_name (priv->parent));
1316         }
1317
1318       /* If in reparent, we temporarily suspend unmap and unrealize.
1319        *
1320        * We want to go in the order "realize, map" and "unmap, unrealize"
1321        */
1322
1323       /* Unmap */
1324       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1325         clutter_actor_set_mapped (self, FALSE);
1326
1327       /* Realize */
1328       if (must_be_realized)
1329         clutter_actor_realize (self);
1330
1331       /* if we must be realized then we may be, presumably */
1332       g_assert (!(must_be_realized && !may_be_realized));
1333
1334       /* Unrealize */
1335       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1336         clutter_actor_unrealize_not_hiding (self);
1337
1338       /* Map */
1339       if (should_be_mapped)
1340         {
1341           if (!must_be_realized)
1342             g_warning ("Somehow we think actor '%s' should be mapped but "
1343                        "not realized, which isn't allowed",
1344                        _clutter_actor_get_debug_name (self));
1345
1346           /* realization is allowed to fail (though I don't know what
1347            * an app is supposed to do about that - shouldn't it just
1348            * be a g_error? anyway, we have to avoid mapping if this
1349            * happens)
1350            */
1351           if (CLUTTER_ACTOR_IS_REALIZED (self))
1352             clutter_actor_set_mapped (self, TRUE);
1353         }
1354     }
1355
1356 #ifdef CLUTTER_ENABLE_DEBUG
1357   /* check all invariants were kept */
1358   clutter_actor_verify_map_state (self);
1359 #endif
1360 }
1361
1362 static void
1363 clutter_actor_real_map (ClutterActor *self)
1364 {
1365   ClutterActorPrivate *priv = self->priv;
1366   ClutterActor *stage, *iter;
1367
1368   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1369
1370   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1371                 _clutter_actor_get_debug_name (self));
1372
1373   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1374
1375   stage = _clutter_actor_get_stage_internal (self);
1376   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1377
1378   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1379                 priv->pick_id,
1380                 _clutter_actor_get_debug_name (self));
1381
1382   /* notify on parent mapped before potentially mapping
1383    * children, so apps see a top-down notification.
1384    */
1385   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1386
1387   for (iter = self->priv->first_child;
1388        iter != NULL;
1389        iter = iter->priv->next_sibling)
1390     {
1391       clutter_actor_map (iter);
1392     }
1393 }
1394
1395 /**
1396  * clutter_actor_map:
1397  * @self: A #ClutterActor
1398  *
1399  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1400  * and realizes its children if they are visible. Does nothing if the
1401  * actor is not visible.
1402  *
1403  * Calling this function is strongly disencouraged: the default
1404  * implementation of #ClutterActorClass.map() will map all the children
1405  * of an actor when mapping its parent.
1406  *
1407  * When overriding map, it is mandatory to chain up to the parent
1408  * implementation.
1409  *
1410  * Since: 1.0
1411  */
1412 void
1413 clutter_actor_map (ClutterActor *self)
1414 {
1415   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1416
1417   if (CLUTTER_ACTOR_IS_MAPPED (self))
1418     return;
1419
1420   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1421     return;
1422
1423   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1424 }
1425
1426 static void
1427 clutter_actor_real_unmap (ClutterActor *self)
1428 {
1429   ClutterActorPrivate *priv = self->priv;
1430   ClutterActor *iter;
1431
1432   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1433
1434   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1435                 _clutter_actor_get_debug_name (self));
1436
1437   for (iter = self->priv->first_child;
1438        iter != NULL;
1439        iter = iter->priv->next_sibling)
1440     {
1441       clutter_actor_unmap (iter);
1442     }
1443
1444   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1445
1446   /* clear the contents of the last paint volume, so that hiding + moving +
1447    * showing will not result in the wrong area being repainted
1448    */
1449   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1450   priv->last_paint_volume_valid = TRUE;
1451
1452   /* notify on parent mapped after potentially unmapping
1453    * children, so apps see a bottom-up notification.
1454    */
1455   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1456
1457   /* relinquish keyboard focus if we were unmapped while owning it */
1458   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1459     {
1460       ClutterStage *stage;
1461
1462       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1463
1464       if (stage != NULL)
1465         _clutter_stage_release_pick_id (stage, priv->pick_id);
1466
1467       priv->pick_id = -1;
1468
1469       if (stage != NULL &&
1470           clutter_stage_get_key_focus (stage) == self)
1471         {
1472           clutter_stage_set_key_focus (stage, NULL);
1473         }
1474     }
1475 }
1476
1477 /**
1478  * clutter_actor_unmap:
1479  * @self: A #ClutterActor
1480  *
1481  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1482  * unmaps its children if they were mapped.
1483  *
1484  * Calling this function is not encouraged: the default #ClutterActor
1485  * implementation of #ClutterActorClass.unmap() will also unmap any
1486  * eventual children by default when their parent is unmapped.
1487  *
1488  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1489  * chain up to the parent implementation.
1490  *
1491  * <note>It is important to note that the implementation of the
1492  * #ClutterActorClass.unmap() virtual function may be called after
1493  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1494  * implementation, but it is guaranteed to be called before the
1495  * #GObjectClass.finalize() implementation.</note>
1496  *
1497  * Since: 1.0
1498  */
1499 void
1500 clutter_actor_unmap (ClutterActor *self)
1501 {
1502   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1503
1504   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1505     return;
1506
1507   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1508 }
1509
1510 static void
1511 clutter_actor_real_show (ClutterActor *self)
1512 {
1513   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1514     {
1515       ClutterActorPrivate *priv = self->priv;
1516
1517       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1518
1519       /* we notify on the "visible" flag in the clutter_actor_show()
1520        * wrapper so the entire show signal emission completes first
1521        * (?)
1522        */
1523       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1524
1525       /* we queue a relayout unless the actor is inside a
1526        * container that explicitly told us not to
1527        */
1528       if (priv->parent != NULL &&
1529           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1530         {
1531           /* While an actor is hidden the parent may not have
1532            * allocated/requested so we need to start from scratch
1533            * and avoid the short-circuiting in
1534            * clutter_actor_queue_relayout().
1535            */
1536           priv->needs_width_request  = FALSE;
1537           priv->needs_height_request = FALSE;
1538           priv->needs_allocation     = FALSE;
1539           clutter_actor_queue_relayout (self);
1540         }
1541     }
1542 }
1543
1544 static inline void
1545 set_show_on_set_parent (ClutterActor *self,
1546                         gboolean      set_show)
1547 {
1548   ClutterActorPrivate *priv = self->priv;
1549
1550   set_show = !!set_show;
1551
1552   if (priv->show_on_set_parent == set_show)
1553     return;
1554
1555   if (priv->parent == NULL)
1556     {
1557       priv->show_on_set_parent = set_show;
1558       g_object_notify_by_pspec (G_OBJECT (self),
1559                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1560     }
1561 }
1562
1563 /**
1564  * clutter_actor_show:
1565  * @self: A #ClutterActor
1566  *
1567  * Flags an actor to be displayed. An actor that isn't shown will not
1568  * be rendered on the stage.
1569  *
1570  * Actors are visible by default.
1571  *
1572  * If this function is called on an actor without a parent, the
1573  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1574  * effect.
1575  */
1576 void
1577 clutter_actor_show (ClutterActor *self)
1578 {
1579   ClutterActorPrivate *priv;
1580
1581   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1582
1583   /* simple optimization */
1584   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1585     {
1586       /* we still need to set the :show-on-set-parent property, in
1587        * case show() is called on an unparented actor
1588        */
1589       set_show_on_set_parent (self, TRUE);
1590       return;
1591     }
1592
1593 #ifdef CLUTTER_ENABLE_DEBUG
1594   clutter_actor_verify_map_state (self);
1595 #endif
1596
1597   priv = self->priv;
1598
1599   g_object_freeze_notify (G_OBJECT (self));
1600
1601   set_show_on_set_parent (self, TRUE);
1602
1603   g_signal_emit (self, actor_signals[SHOW], 0);
1604   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1605
1606   if (priv->parent != NULL)
1607     clutter_actor_queue_redraw (priv->parent);
1608
1609   g_object_thaw_notify (G_OBJECT (self));
1610 }
1611
1612 /**
1613  * clutter_actor_show_all:
1614  * @self: a #ClutterActor
1615  *
1616  * Calls clutter_actor_show() on all children of an actor (if any).
1617  *
1618  * Since: 0.2
1619  *
1620  * Deprecated: 1.10: Actors are visible by default
1621  */
1622 void
1623 clutter_actor_show_all (ClutterActor *self)
1624 {
1625   ClutterActorClass *klass;
1626
1627   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1628
1629   klass = CLUTTER_ACTOR_GET_CLASS (self);
1630   if (klass->show_all)
1631     klass->show_all (self);
1632 }
1633
1634 static void
1635 clutter_actor_real_hide (ClutterActor *self)
1636 {
1637   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1638     {
1639       ClutterActorPrivate *priv = self->priv;
1640
1641       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1642
1643       /* we notify on the "visible" flag in the clutter_actor_hide()
1644        * wrapper so the entire hide signal emission completes first
1645        * (?)
1646        */
1647       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1648
1649       /* we queue a relayout unless the actor is inside a
1650        * container that explicitly told us not to
1651        */
1652       if (priv->parent != NULL &&
1653           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1654         clutter_actor_queue_relayout (priv->parent);
1655     }
1656 }
1657
1658 /**
1659  * clutter_actor_hide:
1660  * @self: A #ClutterActor
1661  *
1662  * Flags an actor to be hidden. A hidden actor will not be
1663  * rendered on the stage.
1664  *
1665  * Actors are visible by default.
1666  *
1667  * If this function is called on an actor without a parent, the
1668  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1669  * as a side-effect.
1670  */
1671 void
1672 clutter_actor_hide (ClutterActor *self)
1673 {
1674   ClutterActorPrivate *priv;
1675
1676   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1677
1678   /* simple optimization */
1679   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1680     {
1681       /* we still need to set the :show-on-set-parent property, in
1682        * case hide() is called on an unparented actor
1683        */
1684       set_show_on_set_parent (self, FALSE);
1685       return;
1686     }
1687
1688 #ifdef CLUTTER_ENABLE_DEBUG
1689   clutter_actor_verify_map_state (self);
1690 #endif
1691
1692   priv = self->priv;
1693
1694   g_object_freeze_notify (G_OBJECT (self));
1695
1696   set_show_on_set_parent (self, FALSE);
1697
1698   g_signal_emit (self, actor_signals[HIDE], 0);
1699   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1700
1701   if (priv->parent != NULL)
1702     clutter_actor_queue_redraw (priv->parent);
1703
1704   g_object_thaw_notify (G_OBJECT (self));
1705 }
1706
1707 /**
1708  * clutter_actor_hide_all:
1709  * @self: a #ClutterActor
1710  *
1711  * Calls clutter_actor_hide() on all child actors (if any).
1712  *
1713  * Since: 0.2
1714  *
1715  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1716  *   prevent its children from being painted as well.
1717  */
1718 void
1719 clutter_actor_hide_all (ClutterActor *self)
1720 {
1721   ClutterActorClass *klass;
1722
1723   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1724
1725   klass = CLUTTER_ACTOR_GET_CLASS (self);
1726   if (klass->hide_all)
1727     klass->hide_all (self);
1728 }
1729
1730 /**
1731  * clutter_actor_realize:
1732  * @self: A #ClutterActor
1733  *
1734  * Realization informs the actor that it is attached to a stage. It
1735  * can use this to allocate resources if it wanted to delay allocation
1736  * until it would be rendered. However it is perfectly acceptable for
1737  * an actor to create resources before being realized because Clutter
1738  * only ever has a single rendering context so that actor is free to
1739  * be moved from one stage to another.
1740  *
1741  * This function does nothing if the actor is already realized.
1742  *
1743  * Because a realized actor must have realized parent actors, calling
1744  * clutter_actor_realize() will also realize all parents of the actor.
1745  *
1746  * This function does not realize child actors, except in the special
1747  * case that realizing the stage, when the stage is visible, will
1748  * suddenly map (and thus realize) the children of the stage.
1749  **/
1750 void
1751 clutter_actor_realize (ClutterActor *self)
1752 {
1753   ClutterActorPrivate *priv;
1754
1755   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1756
1757   priv = self->priv;
1758
1759 #ifdef CLUTTER_ENABLE_DEBUG
1760   clutter_actor_verify_map_state (self);
1761 #endif
1762
1763   if (CLUTTER_ACTOR_IS_REALIZED (self))
1764     return;
1765
1766   /* To be realized, our parent actors must be realized first.
1767    * This will only succeed if we're inside a toplevel.
1768    */
1769   if (priv->parent != NULL)
1770     clutter_actor_realize (priv->parent);
1771
1772   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1773     {
1774       /* toplevels can be realized at any time */
1775     }
1776   else
1777     {
1778       /* "Fail" the realization if parent is missing or unrealized;
1779        * this should really be a g_warning() not some kind of runtime
1780        * failure; how can an app possibly recover? Instead it's a bug
1781        * in the app and the app should get an explanatory warning so
1782        * someone can fix it. But for now it's too hard to fix this
1783        * because e.g. ClutterTexture needs reworking.
1784        */
1785       if (priv->parent == NULL ||
1786           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1787         return;
1788     }
1789
1790   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1791
1792   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1793   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1794
1795   g_signal_emit (self, actor_signals[REALIZE], 0);
1796
1797   /* Stage actor is allowed to unset the realized flag again in its
1798    * default signal handler, though that is a pathological situation.
1799    */
1800
1801   /* If realization "failed" we'll have to update child state. */
1802   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1803 }
1804
1805 static void
1806 clutter_actor_real_unrealize (ClutterActor *self)
1807 {
1808   /* we must be unmapped (implying our children are also unmapped) */
1809   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1810 }
1811
1812 /**
1813  * clutter_actor_unrealize:
1814  * @self: A #ClutterActor
1815  *
1816  * Unrealization informs the actor that it may be being destroyed or
1817  * moved to another stage. The actor may want to destroy any
1818  * underlying graphics resources at this point. However it is
1819  * perfectly acceptable for it to retain the resources until the actor
1820  * is destroyed because Clutter only ever uses a single rendering
1821  * context and all of the graphics resources are valid on any stage.
1822  *
1823  * Because mapped actors must be realized, actors may not be
1824  * unrealized if they are mapped. This function hides the actor to be
1825  * sure it isn't mapped, an application-visible side effect that you
1826  * may not be expecting.
1827  *
1828  * This function should not be called by application code.
1829  */
1830 void
1831 clutter_actor_unrealize (ClutterActor *self)
1832 {
1833   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1834   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1835
1836 /* This function should not really be in the public API, because
1837  * there isn't a good reason to call it. ClutterActor will already
1838  * unrealize things for you when it's important to do so.
1839  *
1840  * If you were using clutter_actor_unrealize() in a dispose
1841  * implementation, then don't, just chain up to ClutterActor's
1842  * dispose.
1843  *
1844  * If you were using clutter_actor_unrealize() to implement
1845  * unrealizing children of your container, then don't, ClutterActor
1846  * will already take care of that.
1847  *
1848  * If you were using clutter_actor_unrealize() to re-realize to
1849  * create your resources in a different way, then use
1850  * _clutter_actor_rerealize() (inside Clutter) or just call your
1851  * code that recreates your resources directly (outside Clutter).
1852  */
1853
1854 #ifdef CLUTTER_ENABLE_DEBUG
1855   clutter_actor_verify_map_state (self);
1856 #endif
1857
1858   clutter_actor_hide (self);
1859
1860   clutter_actor_unrealize_not_hiding (self);
1861 }
1862
1863 static ClutterActorTraverseVisitFlags
1864 unrealize_actor_before_children_cb (ClutterActor *self,
1865                                     int depth,
1866                                     void *user_data)
1867 {
1868   /* If an actor is already unrealized we know its children have also
1869    * already been unrealized... */
1870   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1871     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1872
1873   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1874
1875   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1876 }
1877
1878 static ClutterActorTraverseVisitFlags
1879 unrealize_actor_after_children_cb (ClutterActor *self,
1880                                    int depth,
1881                                    void *user_data)
1882 {
1883   /* We want to unset the realized flag only _after_
1884    * child actors are unrealized, to maintain invariants.
1885    */
1886   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1887   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1888   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1889 }
1890
1891 /*
1892  * clutter_actor_unrealize_not_hiding:
1893  * @self: A #ClutterActor
1894  *
1895  * Unrealization informs the actor that it may be being destroyed or
1896  * moved to another stage. The actor may want to destroy any
1897  * underlying graphics resources at this point. However it is
1898  * perfectly acceptable for it to retain the resources until the actor
1899  * is destroyed because Clutter only ever uses a single rendering
1900  * context and all of the graphics resources are valid on any stage.
1901  *
1902  * Because mapped actors must be realized, actors may not be
1903  * unrealized if they are mapped. You must hide the actor or one of
1904  * its parents before attempting to unrealize.
1905  *
1906  * This function is separate from clutter_actor_unrealize() because it
1907  * does not automatically hide the actor.
1908  * Actors need not be hidden to be unrealized, they just need to
1909  * be unmapped. In fact we don't want to mess up the application's
1910  * setting of the "visible" flag, so hiding is very undesirable.
1911  *
1912  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1913  * backward compatibility.
1914  */
1915 static void
1916 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1917 {
1918   _clutter_actor_traverse (self,
1919                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1920                            unrealize_actor_before_children_cb,
1921                            unrealize_actor_after_children_cb,
1922                            NULL);
1923 }
1924
1925 /*
1926  * _clutter_actor_rerealize:
1927  * @self: A #ClutterActor
1928  * @callback: Function to call while unrealized
1929  * @data: data for callback
1930  *
1931  * If an actor is already unrealized, this just calls the callback.
1932  *
1933  * If it is realized, it unrealizes temporarily, calls the callback,
1934  * and then re-realizes the actor.
1935  *
1936  * As a side effect, leaves all children of the actor unrealized if
1937  * the actor was realized but not showing.  This is because when we
1938  * unrealize the actor temporarily we must unrealize its children
1939  * (e.g. children of a stage can't be realized if stage window is
1940  * gone). And we aren't clever enough to save the realization state of
1941  * all children. In most cases this should not matter, because
1942  * the children will automatically realize when they next become mapped.
1943  */
1944 void
1945 _clutter_actor_rerealize (ClutterActor    *self,
1946                           ClutterCallback  callback,
1947                           void            *data)
1948 {
1949   gboolean was_mapped;
1950   gboolean was_showing;
1951   gboolean was_realized;
1952
1953   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1954
1955 #ifdef CLUTTER_ENABLE_DEBUG
1956   clutter_actor_verify_map_state (self);
1957 #endif
1958
1959   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1960   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1961   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1962
1963   /* Must be unmapped to unrealize. Note we only have to hide this
1964    * actor if it was mapped (if all parents were showing).  If actor
1965    * is merely visible (but not mapped), then that's fine, we can
1966    * leave it visible.
1967    */
1968   if (was_mapped)
1969     clutter_actor_hide (self);
1970
1971   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1972
1973   /* unrealize self and all children */
1974   clutter_actor_unrealize_not_hiding (self);
1975
1976   if (callback != NULL)
1977     {
1978       (* callback) (self, data);
1979     }
1980
1981   if (was_showing)
1982     clutter_actor_show (self); /* will realize only if mapping implies it */
1983   else if (was_realized)
1984     clutter_actor_realize (self); /* realize self and all parents */
1985 }
1986
1987 static void
1988 clutter_actor_real_pick (ClutterActor       *self,
1989                          const ClutterColor *color)
1990 {
1991   /* the default implementation is just to paint a rectangle
1992    * with the same size of the actor using the passed color
1993    */
1994   if (clutter_actor_should_pick_paint (self))
1995     {
1996       ClutterActorBox box = { 0, };
1997       float width, height;
1998
1999       clutter_actor_get_allocation_box (self, &box);
2000
2001       width = box.x2 - box.x1;
2002       height = box.y2 - box.y1;
2003
2004       cogl_set_source_color4ub (color->red,
2005                                 color->green,
2006                                 color->blue,
2007                                 color->alpha);
2008
2009       cogl_rectangle (0, 0, width, height);
2010     }
2011
2012   /* XXX - this thoroughly sucks, but we need to maintain compatibility
2013    * with existing container classes that override the pick() virtual
2014    * and chain up to the default implementation - otherwise we'll end up
2015    * painting our children twice.
2016    *
2017    * this has to go away for 2.0; hopefully along the pick() itself.
2018    */
2019   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2020     {
2021       ClutterActor *iter;
2022
2023       for (iter = self->priv->first_child;
2024            iter != NULL;
2025            iter = iter->priv->next_sibling)
2026         clutter_actor_paint (iter);
2027     }
2028 }
2029
2030 /**
2031  * clutter_actor_should_pick_paint:
2032  * @self: A #ClutterActor
2033  *
2034  * Should be called inside the implementation of the
2035  * #ClutterActor::pick virtual function in order to check whether
2036  * the actor should paint itself in pick mode or not.
2037  *
2038  * This function should never be called directly by applications.
2039  *
2040  * Return value: %TRUE if the actor should paint its silhouette,
2041  *   %FALSE otherwise
2042  */
2043 gboolean
2044 clutter_actor_should_pick_paint (ClutterActor *self)
2045 {
2046   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2047
2048   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2049       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2050        CLUTTER_ACTOR_IS_REACTIVE (self)))
2051     return TRUE;
2052
2053   return FALSE;
2054 }
2055
2056 static void
2057 clutter_actor_real_get_preferred_width (ClutterActor *self,
2058                                         gfloat        for_height,
2059                                         gfloat       *min_width_p,
2060                                         gfloat       *natural_width_p)
2061 {
2062   ClutterActorPrivate *priv = self->priv;
2063
2064   if (priv->n_children != 0 &&
2065       priv->layout_manager != NULL)
2066     {
2067       ClutterContainer *container = CLUTTER_CONTAINER (self);
2068
2069       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2070                     "for the preferred width",
2071                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2072                     priv->layout_manager);
2073
2074       clutter_layout_manager_get_preferred_width (priv->layout_manager,
2075                                                   container,
2076                                                   for_height,
2077                                                   min_width_p,
2078                                                   natural_width_p);
2079
2080       return;
2081     }
2082
2083   /* Default implementation is always 0x0, usually an actor
2084    * using this default is relying on someone to set the
2085    * request manually
2086    */
2087   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2088
2089   if (min_width_p)
2090     *min_width_p = 0;
2091
2092   if (natural_width_p)
2093     *natural_width_p = 0;
2094 }
2095
2096 static void
2097 clutter_actor_real_get_preferred_height (ClutterActor *self,
2098                                          gfloat        for_width,
2099                                          gfloat       *min_height_p,
2100                                          gfloat       *natural_height_p)
2101 {
2102   ClutterActorPrivate *priv = self->priv;
2103
2104   if (priv->n_children != 0 &&
2105       priv->layout_manager != NULL)
2106     {
2107       ClutterContainer *container = CLUTTER_CONTAINER (self);
2108
2109       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2110                     "for the preferred height",
2111                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2112                     priv->layout_manager);
2113
2114       clutter_layout_manager_get_preferred_height (priv->layout_manager,
2115                                                    container,
2116                                                    for_width,
2117                                                    min_height_p,
2118                                                    natural_height_p);
2119
2120       return;
2121     }
2122   /* Default implementation is always 0x0, usually an actor
2123    * using this default is relying on someone to set the
2124    * request manually
2125    */
2126   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2127
2128   if (min_height_p)
2129     *min_height_p = 0;
2130
2131   if (natural_height_p)
2132     *natural_height_p = 0;
2133 }
2134
2135 static void
2136 clutter_actor_store_old_geometry (ClutterActor    *self,
2137                                   ClutterActorBox *box)
2138 {
2139   *box = self->priv->allocation;
2140 }
2141
2142 static inline void
2143 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2144                                           const ClutterActorBox *old)
2145 {
2146   ClutterActorPrivate *priv = self->priv;
2147   GObject *obj = G_OBJECT (self);
2148
2149   g_object_freeze_notify (obj);
2150
2151   /* to avoid excessive requisition or allocation cycles we
2152    * use the cached values.
2153    *
2154    * - if we don't have an allocation we assume that we need
2155    *   to notify anyway
2156    * - if we don't have a width or a height request we notify
2157    *   width and height
2158    * - if we have a valid allocation then we check the old
2159    *   bounding box with the current allocation and we notify
2160    *   the changes
2161    */
2162   if (priv->needs_allocation)
2163     {
2164       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2165       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2166       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2167       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2168     }
2169   else if (priv->needs_width_request || priv->needs_height_request)
2170     {
2171       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2172       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2173     }
2174   else
2175     {
2176       gfloat x, y;
2177       gfloat width, height;
2178
2179       x = priv->allocation.x1;
2180       y = priv->allocation.y1;
2181       width = priv->allocation.x2 - priv->allocation.x1;
2182       height = priv->allocation.y2 - priv->allocation.y1;
2183
2184       if (x != old->x1)
2185         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2186
2187       if (y != old->y1)
2188         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2189
2190       if (width != (old->x2 - old->x1))
2191         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2192
2193       if (height != (old->y2 - old->y1))
2194         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2195     }
2196
2197   g_object_thaw_notify (obj);
2198 }
2199
2200 /*< private >
2201  * clutter_actor_set_allocation_internal:
2202  * @self: a #ClutterActor
2203  * @box: a #ClutterActorBox
2204  * @flags: allocation flags
2205  *
2206  * Stores the allocation of @self.
2207  *
2208  * This function only performs basic storage and property notification.
2209  *
2210  * This function should be called by clutter_actor_set_allocation()
2211  * and by the default implementation of #ClutterActorClass.allocate().
2212  *
2213  * Return value: %TRUE if the allocation of the #ClutterActor has been
2214  *   changed, and %FALSE otherwise
2215  */
2216 static inline gboolean
2217 clutter_actor_set_allocation_internal (ClutterActor           *self,
2218                                        const ClutterActorBox  *box,
2219                                        ClutterAllocationFlags  flags)
2220 {
2221   ClutterActorPrivate *priv = self->priv;
2222   GObject *obj;
2223   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2224   gboolean flags_changed;
2225   gboolean retval;
2226   ClutterActorBox old_alloc = { 0, };
2227
2228   obj = G_OBJECT (self);
2229
2230   g_object_freeze_notify (obj);
2231
2232   clutter_actor_store_old_geometry (self, &old_alloc);
2233
2234   x1_changed = priv->allocation.x1 != box->x1;
2235   y1_changed = priv->allocation.y1 != box->y1;
2236   x2_changed = priv->allocation.x2 != box->x2;
2237   y2_changed = priv->allocation.y2 != box->y2;
2238
2239   flags_changed = priv->allocation_flags != flags;
2240
2241   priv->allocation = *box;
2242   priv->allocation_flags = flags;
2243
2244   /* allocation is authoritative */
2245   priv->needs_width_request = FALSE;
2246   priv->needs_height_request = FALSE;
2247   priv->needs_allocation = FALSE;
2248
2249   if (x1_changed || y1_changed ||
2250       x2_changed || y2_changed ||
2251       flags_changed)
2252     {
2253       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2254                     _clutter_actor_get_debug_name (self));
2255
2256       priv->transform_valid = FALSE;
2257
2258       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2259
2260       /* if the allocation changes, so does the content box */
2261       if (priv->content != NULL)
2262         g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2263
2264       retval = TRUE;
2265     }
2266   else
2267     retval = FALSE;
2268
2269   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2270
2271   g_object_thaw_notify (obj);
2272
2273   return retval;
2274 }
2275
2276 static void clutter_actor_real_allocate (ClutterActor           *self,
2277                                          const ClutterActorBox  *box,
2278                                          ClutterAllocationFlags  flags);
2279
2280 static inline void
2281 clutter_actor_maybe_layout_children (ClutterActor           *self,
2282                                      const ClutterActorBox  *allocation,
2283                                      ClutterAllocationFlags  flags)
2284 {
2285   ClutterActorPrivate *priv = self->priv;
2286
2287   /* this is going to be a bit hard to follow, so let's put an explanation
2288    * here.
2289    *
2290    * we want ClutterActor to have a default layout manager if the actor was
2291    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2292    *
2293    * we also want any subclass of ClutterActor that does not override the
2294    * ::allocate() virtual function to delegate to a layout manager.
2295    *
2296    * finally, we want to allow people subclassing ClutterActor and overriding
2297    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2298    *
2299    * on the other hand, we want existing actor subclasses overriding the
2300    * ::allocate() virtual function and chaining up to the parent's
2301    * implementation to continue working without allocating their children
2302    * twice, or without entering an allocation loop.
2303    *
2304    * for the first two points, we check if the class of the actor is
2305    * overridding the ::allocate() virtual function; if it isn't, then we
2306    * follow through with checking whether we have children and a layout
2307    * manager, and eventually calling clutter_layout_manager_allocate().
2308    *
2309    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2310    * allocation flags that we got passed, and if it is present, we continue
2311    * with the check above.
2312    *
2313    * if neither of these two checks yields a positive result, we just
2314    * assume that the ::allocate() virtual function that resulted in this
2315    * function being called will also allocate the children of the actor.
2316    */
2317
2318   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2319     goto check_layout;
2320
2321   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2322     goto check_layout;
2323
2324   return;
2325
2326 check_layout:
2327   if (priv->n_children != 0 &&
2328       priv->layout_manager != NULL)
2329     {
2330       ClutterContainer *container = CLUTTER_CONTAINER (self);
2331       ClutterAllocationFlags children_flags;
2332       ClutterActorBox children_box;
2333
2334       /* normalize the box passed to the layout manager */
2335       children_box.x1 = children_box.y1 = 0.f;
2336       children_box.x2 = (allocation->x2 - allocation->x1);
2337       children_box.y2 = (allocation->y2 - allocation->y1);
2338
2339       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2340        * the actor's children, since it refers only to the current
2341        * actor's allocation.
2342        */
2343       children_flags = flags;
2344       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2345
2346       CLUTTER_NOTE (LAYOUT,
2347                     "Allocating %d children of %s "
2348                     "at { %.2f, %.2f - %.2f x %.2f } "
2349                     "using %s",
2350                     priv->n_children,
2351                     _clutter_actor_get_debug_name (self),
2352                     allocation->x1,
2353                     allocation->y1,
2354                     (allocation->x2 - allocation->x1),
2355                     (allocation->y2 - allocation->y1),
2356                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2357
2358       clutter_layout_manager_allocate (priv->layout_manager,
2359                                        container,
2360                                        &children_box,
2361                                        children_flags);
2362     }
2363 }
2364
2365 static void
2366 clutter_actor_real_allocate (ClutterActor           *self,
2367                              const ClutterActorBox  *box,
2368                              ClutterAllocationFlags  flags)
2369 {
2370   ClutterActorPrivate *priv = self->priv;
2371   gboolean changed;
2372
2373   g_object_freeze_notify (G_OBJECT (self));
2374
2375   changed = clutter_actor_set_allocation_internal (self, box, flags);
2376
2377   /* we allocate our children before we notify changes in our geometry,
2378    * so that people connecting to properties will be able to get valid
2379    * data out of the sub-tree of the scene graph that has this actor at
2380    * the root.
2381    */
2382   clutter_actor_maybe_layout_children (self, box, flags);
2383
2384   if (changed)
2385     {
2386       ClutterActorBox signal_box = priv->allocation;
2387       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2388
2389       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2390                      &signal_box,
2391                      signal_flags);
2392     }
2393
2394   g_object_thaw_notify (G_OBJECT (self));
2395 }
2396
2397 static void
2398 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2399                                     ClutterActor *origin)
2400 {
2401   /* no point in queuing a redraw on a destroyed actor */
2402   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2403     return;
2404
2405   /* NB: We can't bail out early here if the actor is hidden in case
2406    * the actor bas been cloned. In this case the clone will need to
2407    * receive the signal so it can queue its own redraw.
2408    */
2409
2410   /* calls klass->queue_redraw in default handler */
2411   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2412 }
2413
2414 static void
2415 clutter_actor_real_queue_redraw (ClutterActor *self,
2416                                  ClutterActor *origin)
2417 {
2418   ClutterActor *parent;
2419
2420   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2421                 _clutter_actor_get_debug_name (self),
2422                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2423                                : "same actor");
2424
2425   /* no point in queuing a redraw on a destroyed actor */
2426   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2427     return;
2428
2429   /* If the queue redraw is coming from a child then the actor has
2430      become dirty and any queued effect is no longer valid */
2431   if (self != origin)
2432     {
2433       self->priv->is_dirty = TRUE;
2434       self->priv->effect_to_redraw = NULL;
2435     }
2436
2437   /* If the actor isn't visible, we still had to emit the signal
2438    * to allow for a ClutterClone, but the appearance of the parent
2439    * won't change so we don't have to propagate up the hierarchy.
2440    */
2441   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2442     return;
2443
2444   /* Although we could determine here that a full stage redraw
2445    * has already been queued and immediately bail out, we actually
2446    * guarantee that we will propagate a queue-redraw signal to our
2447    * parent at least once so that it's possible to implement a
2448    * container that tracks which of its children have queued a
2449    * redraw.
2450    */
2451   if (self->priv->propagated_one_redraw)
2452     {
2453       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2454       if (stage != NULL &&
2455           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2456         return;
2457     }
2458
2459   self->priv->propagated_one_redraw = TRUE;
2460
2461   /* notify parents, if they are all visible eventually we'll
2462    * queue redraw on the stage, which queues the redraw idle.
2463    */
2464   parent = clutter_actor_get_parent (self);
2465   if (parent != NULL)
2466     {
2467       /* this will go up recursively */
2468       _clutter_actor_signal_queue_redraw (parent, origin);
2469     }
2470 }
2471
2472 static void
2473 clutter_actor_real_queue_relayout (ClutterActor *self)
2474 {
2475   ClutterActorPrivate *priv = self->priv;
2476
2477   /* no point in queueing a redraw on a destroyed actor */
2478   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2479     return;
2480
2481   priv->needs_width_request  = TRUE;
2482   priv->needs_height_request = TRUE;
2483   priv->needs_allocation     = TRUE;
2484
2485   /* reset the cached size requests */
2486   memset (priv->width_requests, 0,
2487           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2488   memset (priv->height_requests, 0,
2489           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2490
2491   /* We need to go all the way up the hierarchy */
2492   if (priv->parent != NULL)
2493     _clutter_actor_queue_only_relayout (priv->parent);
2494 }
2495
2496 /**
2497  * clutter_actor_apply_relative_transform_to_point:
2498  * @self: A #ClutterActor
2499  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2500  *   default #ClutterStage
2501  * @point: A point as #ClutterVertex
2502  * @vertex: (out caller-allocates): The translated #ClutterVertex
2503  *
2504  * Transforms @point in coordinates relative to the actor into
2505  * ancestor-relative coordinates using the relevant transform
2506  * stack (i.e. scale, rotation, etc).
2507  *
2508  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2509  * this case, the coordinates returned will be the coordinates on
2510  * the stage before the projection is applied. This is different from
2511  * the behaviour of clutter_actor_apply_transform_to_point().
2512  *
2513  * Since: 0.6
2514  */
2515 void
2516 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2517                                                  ClutterActor        *ancestor,
2518                                                  const ClutterVertex *point,
2519                                                  ClutterVertex       *vertex)
2520 {
2521   gfloat w;
2522   CoglMatrix matrix;
2523
2524   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2525   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2526   g_return_if_fail (point != NULL);
2527   g_return_if_fail (vertex != NULL);
2528
2529   *vertex = *point;
2530   w = 1.0;
2531
2532   if (ancestor == NULL)
2533     ancestor = _clutter_actor_get_stage_internal (self);
2534
2535   if (ancestor == NULL)
2536     {
2537       *vertex = *point;
2538       return;
2539     }
2540
2541   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2542   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2543 }
2544
2545 static gboolean
2546 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2547                                          const ClutterVertex *vertices_in,
2548                                          ClutterVertex *vertices_out,
2549                                          int n_vertices)
2550 {
2551   ClutterActor *stage;
2552   CoglMatrix modelview;
2553   CoglMatrix projection;
2554   float viewport[4];
2555
2556   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2557
2558   stage = _clutter_actor_get_stage_internal (self);
2559
2560   /* We really can't do anything meaningful in this case so don't try
2561    * to do any transform */
2562   if (stage == NULL)
2563     return FALSE;
2564
2565   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2566    * that gets us to stage coordinates, we want to go all the way to eye
2567    * coordinates */
2568   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2569
2570   /* Fetch the projection and viewport */
2571   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2572   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2573                                &viewport[0],
2574                                &viewport[1],
2575                                &viewport[2],
2576                                &viewport[3]);
2577
2578   _clutter_util_fully_transform_vertices (&modelview,
2579                                           &projection,
2580                                           viewport,
2581                                           vertices_in,
2582                                           vertices_out,
2583                                           n_vertices);
2584
2585   return TRUE;
2586 }
2587
2588 /**
2589  * clutter_actor_apply_transform_to_point:
2590  * @self: A #ClutterActor
2591  * @point: A point as #ClutterVertex
2592  * @vertex: (out caller-allocates): The translated #ClutterVertex
2593  *
2594  * Transforms @point in coordinates relative to the actor
2595  * into screen-relative coordinates with the current actor
2596  * transformation (i.e. scale, rotation, etc)
2597  *
2598  * Since: 0.4
2599  **/
2600 void
2601 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2602                                         const ClutterVertex *point,
2603                                         ClutterVertex       *vertex)
2604 {
2605   g_return_if_fail (point != NULL);
2606   g_return_if_fail (vertex != NULL);
2607   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2608 }
2609
2610 /*
2611  * _clutter_actor_get_relative_transformation_matrix:
2612  * @self: The actor whose coordinate space you want to transform from.
2613  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2614  *            or %NULL if you want to transform all the way to eye coordinates.
2615  * @matrix: A #CoglMatrix to store the transformation
2616  *
2617  * This gets a transformation @matrix that will transform coordinates from the
2618  * coordinate space of @self into the coordinate space of @ancestor.
2619  *
2620  * For example if you need a matrix that can transform the local actor
2621  * coordinates of @self into stage coordinates you would pass the actor's stage
2622  * pointer as the @ancestor.
2623  *
2624  * If you pass %NULL then the transformation will take you all the way through
2625  * to eye coordinates. This can be useful if you want to extract the entire
2626  * modelview transform that Clutter applies before applying the projection
2627  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2628  * using cogl_set_modelview_matrix() for example then you would want a matrix
2629  * that transforms into eye coordinates.
2630  *
2631  * <note><para>This function explicitly initializes the given @matrix. If you just
2632  * want clutter to multiply a relative transformation with an existing matrix
2633  * you can use clutter_actor_apply_relative_transformation_matrix()
2634  * instead.</para></note>
2635  *
2636  */
2637 /* XXX: We should consider caching the stage relative modelview along with
2638  * the actor itself */
2639 static void
2640 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2641                                                    ClutterActor *ancestor,
2642                                                    CoglMatrix *matrix)
2643 {
2644   cogl_matrix_init_identity (matrix);
2645
2646   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2647 }
2648
2649 /* Project the given @box into stage window coordinates, writing the
2650  * transformed vertices to @verts[]. */
2651 static gboolean
2652 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2653                                           const ClutterActorBox *box,
2654                                           ClutterVertex          verts[])
2655 {
2656   ClutterVertex box_vertices[4];
2657
2658   box_vertices[0].x = box->x1;
2659   box_vertices[0].y = box->y1;
2660   box_vertices[0].z = 0;
2661   box_vertices[1].x = box->x2;
2662   box_vertices[1].y = box->y1;
2663   box_vertices[1].z = 0;
2664   box_vertices[2].x = box->x1;
2665   box_vertices[2].y = box->y2;
2666   box_vertices[2].z = 0;
2667   box_vertices[3].x = box->x2;
2668   box_vertices[3].y = box->y2;
2669   box_vertices[3].z = 0;
2670
2671   return
2672     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2673 }
2674
2675 /**
2676  * clutter_actor_get_allocation_vertices:
2677  * @self: A #ClutterActor
2678  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2679  *   against, or %NULL to use the #ClutterStage
2680  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2681  *   location for an array of 4 #ClutterVertex in which to store the result
2682  *
2683  * Calculates the transformed coordinates of the four corners of the
2684  * actor in the plane of @ancestor. The returned vertices relate to
2685  * the #ClutterActorBox coordinates as follows:
2686  * <itemizedlist>
2687  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2688  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2689  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2690  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2691  * </itemizedlist>
2692  *
2693  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2694  * this case, the coordinates returned will be the coordinates on
2695  * the stage before the projection is applied. This is different from
2696  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2697  *
2698  * Since: 0.6
2699  */
2700 void
2701 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2702                                        ClutterActor  *ancestor,
2703                                        ClutterVertex  verts[])
2704 {
2705   ClutterActorPrivate *priv;
2706   ClutterActorBox box;
2707   ClutterVertex vertices[4];
2708   CoglMatrix modelview;
2709
2710   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2711   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2712
2713   if (ancestor == NULL)
2714     ancestor = _clutter_actor_get_stage_internal (self);
2715
2716   /* Fallback to a NOP transform if the actor isn't parented under a
2717    * stage. */
2718   if (ancestor == NULL)
2719     ancestor = self;
2720
2721   priv = self->priv;
2722
2723   /* if the actor needs to be allocated we force a relayout, so that
2724    * we will have valid values to use in the transformations */
2725   if (priv->needs_allocation)
2726     {
2727       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2728       if (stage)
2729         _clutter_stage_maybe_relayout (stage);
2730       else
2731         {
2732           box.x1 = box.y1 = 0;
2733           /* The result isn't really meaningful in this case but at
2734            * least try to do something *vaguely* reasonable... */
2735           clutter_actor_get_size (self, &box.x2, &box.y2);
2736         }
2737     }
2738
2739   clutter_actor_get_allocation_box (self, &box);
2740
2741   vertices[0].x = box.x1;
2742   vertices[0].y = box.y1;
2743   vertices[0].z = 0;
2744   vertices[1].x = box.x2;
2745   vertices[1].y = box.y1;
2746   vertices[1].z = 0;
2747   vertices[2].x = box.x1;
2748   vertices[2].y = box.y2;
2749   vertices[2].z = 0;
2750   vertices[3].x = box.x2;
2751   vertices[3].y = box.y2;
2752   vertices[3].z = 0;
2753
2754   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2755                                                      &modelview);
2756
2757   cogl_matrix_transform_points (&modelview,
2758                                 3,
2759                                 sizeof (ClutterVertex),
2760                                 vertices,
2761                                 sizeof (ClutterVertex),
2762                                 vertices,
2763                                 4);
2764 }
2765
2766 /**
2767  * clutter_actor_get_abs_allocation_vertices:
2768  * @self: A #ClutterActor
2769  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2770  *   of 4 #ClutterVertex where to store the result.
2771  *
2772  * Calculates the transformed screen coordinates of the four corners of
2773  * the actor; the returned vertices relate to the #ClutterActorBox
2774  * coordinates  as follows:
2775  * <itemizedlist>
2776  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2777  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2778  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2779  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2780  * </itemizedlist>
2781  *
2782  * Since: 0.4
2783  */
2784 void
2785 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2786                                            ClutterVertex  verts[])
2787 {
2788   ClutterActorPrivate *priv;
2789   ClutterActorBox actor_space_allocation;
2790
2791   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2792
2793   priv = self->priv;
2794
2795   /* if the actor needs to be allocated we force a relayout, so that
2796    * the actor allocation box will be valid for
2797    * _clutter_actor_transform_and_project_box()
2798    */
2799   if (priv->needs_allocation)
2800     {
2801       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2802       /* There's nothing meaningful we can do now */
2803       if (!stage)
2804         return;
2805
2806       _clutter_stage_maybe_relayout (stage);
2807     }
2808
2809   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2810    * own coordinate space... */
2811   actor_space_allocation.x1 = 0;
2812   actor_space_allocation.y1 = 0;
2813   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2814   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2815   _clutter_actor_transform_and_project_box (self,
2816                                             &actor_space_allocation,
2817                                             verts);
2818 }
2819
2820 static void
2821 clutter_actor_real_apply_transform (ClutterActor *self,
2822                                     CoglMatrix   *matrix)
2823 {
2824   ClutterActorPrivate *priv = self->priv;
2825
2826   if (!priv->transform_valid)
2827     {
2828       CoglMatrix *transform = &priv->transform;
2829       const ClutterTransformInfo *info;
2830
2831       info = _clutter_actor_get_transform_info_or_defaults (self);
2832
2833       cogl_matrix_init_identity (transform);
2834
2835       cogl_matrix_translate (transform,
2836                              priv->allocation.x1,
2837                              priv->allocation.y1,
2838                              0.0);
2839
2840       if (info->depth)
2841         cogl_matrix_translate (transform, 0, 0, info->depth);
2842
2843       /*
2844        * because the rotation involves translations, we must scale
2845        * before applying the rotations (if we apply the scale after
2846        * the rotations, the translations included in the rotation are
2847        * not scaled and so the entire object will move on the screen
2848        * as a result of rotating it).
2849        */
2850       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2851         {
2852           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2853                                         &info->scale_center,
2854                                         cogl_matrix_scale (transform,
2855                                                            info->scale_x,
2856                                                            info->scale_y,
2857                                                            1.0));
2858         }
2859
2860       if (info->rz_angle)
2861         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2862                                       &info->rz_center,
2863                                       cogl_matrix_rotate (transform,
2864                                                           info->rz_angle,
2865                                                           0, 0, 1.0));
2866
2867       if (info->ry_angle)
2868         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2869                                       &info->ry_center,
2870                                       cogl_matrix_rotate (transform,
2871                                                           info->ry_angle,
2872                                                           0, 1.0, 0));
2873
2874       if (info->rx_angle)
2875         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2876                                       &info->rx_center,
2877                                       cogl_matrix_rotate (transform,
2878                                                           info->rx_angle,
2879                                                           1.0, 0, 0));
2880
2881       if (!clutter_anchor_coord_is_zero (&info->anchor))
2882         {
2883           gfloat x, y, z;
2884
2885           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2886           cogl_matrix_translate (transform, -x, -y, -z);
2887         }
2888
2889       priv->transform_valid = TRUE;
2890     }
2891
2892   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2893 }
2894
2895 /* Applies the transforms associated with this actor to the given
2896  * matrix. */
2897 void
2898 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2899                                           CoglMatrix *matrix)
2900 {
2901   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2902 }
2903
2904 /*
2905  * clutter_actor_apply_relative_transformation_matrix:
2906  * @self: The actor whose coordinate space you want to transform from.
2907  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2908  *            or %NULL if you want to transform all the way to eye coordinates.
2909  * @matrix: A #CoglMatrix to apply the transformation too.
2910  *
2911  * This multiplies a transform with @matrix that will transform coordinates
2912  * from the coordinate space of @self into the coordinate space of @ancestor.
2913  *
2914  * For example if you need a matrix that can transform the local actor
2915  * coordinates of @self into stage coordinates you would pass the actor's stage
2916  * pointer as the @ancestor.
2917  *
2918  * If you pass %NULL then the transformation will take you all the way through
2919  * to eye coordinates. This can be useful if you want to extract the entire
2920  * modelview transform that Clutter applies before applying the projection
2921  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2922  * using cogl_set_modelview_matrix() for example then you would want a matrix
2923  * that transforms into eye coordinates.
2924  *
2925  * <note>This function doesn't initialize the given @matrix, it simply
2926  * multiplies the requested transformation matrix with the existing contents of
2927  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2928  * before calling this function, or you can use
2929  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2930  */
2931 void
2932 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2933                                                      ClutterActor *ancestor,
2934                                                      CoglMatrix *matrix)
2935 {
2936   ClutterActor *parent;
2937
2938   /* Note we terminate before ever calling stage->apply_transform()
2939    * since that would conceptually be relative to the underlying
2940    * window OpenGL coordinates so we'd need a special @ancestor
2941    * value to represent the fake parent of the stage. */
2942   if (self == ancestor)
2943     return;
2944
2945   parent = clutter_actor_get_parent (self);
2946
2947   if (parent != NULL)
2948     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2949                                                          matrix);
2950
2951   _clutter_actor_apply_modelview_transform (self, matrix);
2952 }
2953
2954 static void
2955 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2956                                        ClutterPaintVolume *pv,
2957                                        const char *label,
2958                                        const CoglColor *color)
2959 {
2960   static CoglPipeline *outline = NULL;
2961   CoglPrimitive *prim;
2962   ClutterVertex line_ends[12 * 2];
2963   int n_vertices;
2964   CoglContext *ctx =
2965     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2966   /* XXX: at some point we'll query this from the stage but we can't
2967    * do that until the osx backend uses Cogl natively. */
2968   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2969
2970   if (outline == NULL)
2971     outline = cogl_pipeline_new (ctx);
2972
2973   _clutter_paint_volume_complete (pv);
2974
2975   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2976
2977   /* Front face */
2978   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2979   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2980   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2981   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2982
2983   if (!pv->is_2d)
2984     {
2985       /* Back face */
2986       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2987       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2988       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2989       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2990
2991       /* Lines connecting front face to back face */
2992       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2993       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2994       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2995       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2996     }
2997
2998   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2999                                 n_vertices,
3000                                 (CoglVertexP3 *)line_ends);
3001
3002   cogl_pipeline_set_color (outline, color);
3003   cogl_framebuffer_draw_primitive (fb, outline, prim);
3004   cogl_object_unref (prim);
3005
3006   if (label)
3007     {
3008       PangoLayout *layout;
3009       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3010       pango_layout_set_text (layout, label, -1);
3011       cogl_pango_render_layout (layout,
3012                                 pv->vertices[0].x,
3013                                 pv->vertices[0].y,
3014                                 color,
3015                                 0);
3016       g_object_unref (layout);
3017     }
3018 }
3019
3020 static void
3021 _clutter_actor_draw_paint_volume (ClutterActor *self)
3022 {
3023   ClutterPaintVolume *pv;
3024   CoglColor color;
3025
3026   pv = _clutter_actor_get_paint_volume_mutable (self);
3027   if (!pv)
3028     {
3029       gfloat width, height;
3030       ClutterPaintVolume fake_pv;
3031
3032       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3033       _clutter_paint_volume_init_static (&fake_pv, stage);
3034
3035       clutter_actor_get_size (self, &width, &height);
3036       clutter_paint_volume_set_width (&fake_pv, width);
3037       clutter_paint_volume_set_height (&fake_pv, height);
3038
3039       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3040       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3041                                              _clutter_actor_get_debug_name (self),
3042                                              &color);
3043
3044       clutter_paint_volume_free (&fake_pv);
3045     }
3046   else
3047     {
3048       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3049       _clutter_actor_draw_paint_volume_full (self, pv,
3050                                              _clutter_actor_get_debug_name (self),
3051                                              &color);
3052     }
3053 }
3054
3055 static void
3056 _clutter_actor_paint_cull_result (ClutterActor *self,
3057                                   gboolean success,
3058                                   ClutterCullResult result)
3059 {
3060   ClutterPaintVolume *pv;
3061   CoglColor color;
3062
3063   if (success)
3064     {
3065       if (result == CLUTTER_CULL_RESULT_IN)
3066         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3067       else if (result == CLUTTER_CULL_RESULT_OUT)
3068         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3069       else
3070         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3071     }
3072   else
3073     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3074
3075   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3076     _clutter_actor_draw_paint_volume_full (self, pv,
3077                                            _clutter_actor_get_debug_name (self),
3078                                            &color);
3079   else
3080     {
3081       PangoLayout *layout;
3082       char *label =
3083         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3084       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3085       cogl_set_source_color (&color);
3086
3087       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3088       pango_layout_set_text (layout, label, -1);
3089       cogl_pango_render_layout (layout,
3090                                 0,
3091                                 0,
3092                                 &color,
3093                                 0);
3094       g_free (label);
3095       g_object_unref (layout);
3096     }
3097 }
3098
3099 static int clone_paint_level = 0;
3100
3101 void
3102 _clutter_actor_push_clone_paint (void)
3103 {
3104   clone_paint_level++;
3105 }
3106
3107 void
3108 _clutter_actor_pop_clone_paint (void)
3109 {
3110   clone_paint_level--;
3111 }
3112
3113 static gboolean
3114 in_clone_paint (void)
3115 {
3116   return clone_paint_level > 0;
3117 }
3118
3119 /* Returns TRUE if the actor can be ignored */
3120 /* FIXME: we should return a ClutterCullResult, and
3121  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3122  * means there's no point in trying to cull descendants of the current
3123  * node. */
3124 static gboolean
3125 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3126 {
3127   ClutterActorPrivate *priv = self->priv;
3128   ClutterActor *stage;
3129   const ClutterPlane *stage_clip;
3130
3131   if (!priv->last_paint_volume_valid)
3132     {
3133       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3134                     "->last_paint_volume_valid == FALSE",
3135                     _clutter_actor_get_debug_name (self));
3136       return FALSE;
3137     }
3138
3139   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3140     return FALSE;
3141
3142   stage = _clutter_actor_get_stage_internal (self);
3143   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3144   if (G_UNLIKELY (!stage_clip))
3145     {
3146       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3147                     "No stage clip set",
3148                     _clutter_actor_get_debug_name (self));
3149       return FALSE;
3150     }
3151
3152   if (cogl_get_draw_framebuffer () !=
3153       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3154     {
3155       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3156                     "Current framebuffer doesn't correspond to stage",
3157                     _clutter_actor_get_debug_name (self));
3158       return FALSE;
3159     }
3160
3161   *result_out =
3162     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3163   return TRUE;
3164 }
3165
3166 static void
3167 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3168 {
3169   ClutterActorPrivate *priv = self->priv;
3170   const ClutterPaintVolume *pv;
3171
3172   if (priv->last_paint_volume_valid)
3173     {
3174       clutter_paint_volume_free (&priv->last_paint_volume);
3175       priv->last_paint_volume_valid = FALSE;
3176     }
3177
3178   pv = clutter_actor_get_paint_volume (self);
3179   if (!pv)
3180     {
3181       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3182                     "Actor failed to report a paint volume",
3183                     _clutter_actor_get_debug_name (self));
3184       return;
3185     }
3186
3187   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3188
3189   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3190                                             NULL); /* eye coordinates */
3191
3192   priv->last_paint_volume_valid = TRUE;
3193 }
3194
3195 static inline gboolean
3196 actor_has_shader_data (ClutterActor *self)
3197 {
3198   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3199 }
3200
3201 guint32
3202 _clutter_actor_get_pick_id (ClutterActor *self)
3203 {
3204   if (self->priv->pick_id < 0)
3205     return 0;
3206
3207   return self->priv->pick_id;
3208 }
3209
3210 /* This is the same as clutter_actor_add_effect except that it doesn't
3211    queue a redraw and it doesn't notify on the effect property */
3212 static void
3213 _clutter_actor_add_effect_internal (ClutterActor  *self,
3214                                     ClutterEffect *effect)
3215 {
3216   ClutterActorPrivate *priv = self->priv;
3217
3218   if (priv->effects == NULL)
3219     {
3220       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3221       priv->effects->actor = self;
3222     }
3223
3224   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3225 }
3226
3227 /* This is the same as clutter_actor_remove_effect except that it doesn't
3228    queue a redraw and it doesn't notify on the effect property */
3229 static void
3230 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3231                                        ClutterEffect *effect)
3232 {
3233   ClutterActorPrivate *priv = self->priv;
3234
3235   if (priv->effects == NULL)
3236     return;
3237
3238   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3239 }
3240
3241 static gboolean
3242 needs_flatten_effect (ClutterActor *self)
3243 {
3244   ClutterActorPrivate *priv = self->priv;
3245
3246   if (G_UNLIKELY (clutter_paint_debug_flags &
3247                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3248     return FALSE;
3249
3250   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3251     return TRUE;
3252   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3253     {
3254       if (clutter_actor_get_paint_opacity (self) < 255 &&
3255           clutter_actor_has_overlaps (self))
3256         return TRUE;
3257     }
3258
3259   return FALSE;
3260 }
3261
3262 static void
3263 add_or_remove_flatten_effect (ClutterActor *self)
3264 {
3265   ClutterActorPrivate *priv = self->priv;
3266
3267   /* Add or remove the flatten effect depending on the
3268      offscreen-redirect property. */
3269   if (needs_flatten_effect (self))
3270     {
3271       if (priv->flatten_effect == NULL)
3272         {
3273           ClutterActorMeta *actor_meta;
3274           gint priority;
3275
3276           priv->flatten_effect = _clutter_flatten_effect_new ();
3277           /* Keep a reference to the effect so that we can queue
3278              redraws from it */
3279           g_object_ref_sink (priv->flatten_effect);
3280
3281           /* Set the priority of the effect to high so that it will
3282              always be applied to the actor first. It uses an internal
3283              priority so that it won't be visible to applications */
3284           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3285           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3286           _clutter_actor_meta_set_priority (actor_meta, priority);
3287
3288           /* This will add the effect without queueing a redraw */
3289           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3290         }
3291     }
3292   else
3293     {
3294       if (priv->flatten_effect != NULL)
3295         {
3296           /* Destroy the effect so that it will lose its fbo cache of
3297              the actor */
3298           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3299           g_clear_object (&priv->flatten_effect);
3300         }
3301     }
3302 }
3303
3304 static void
3305 clutter_actor_real_paint (ClutterActor *actor)
3306 {
3307   ClutterActorPrivate *priv = actor->priv;
3308   ClutterActor *iter;
3309
3310   for (iter = priv->first_child;
3311        iter != NULL;
3312        iter = iter->priv->next_sibling)
3313     {
3314       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3315                     _clutter_actor_get_debug_name (iter),
3316                     _clutter_actor_get_debug_name (actor),
3317                     iter->priv->allocation.x1,
3318                     iter->priv->allocation.y1,
3319                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3320                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3321
3322       clutter_actor_paint (iter);
3323     }
3324 }
3325
3326 static gboolean
3327 clutter_actor_paint_node (ClutterActor     *actor,
3328                           ClutterPaintNode *root)
3329 {
3330   ClutterActorPrivate *priv = actor->priv;
3331
3332   if (root == NULL)
3333     return FALSE;
3334
3335   if (priv->bg_color_set &&
3336       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3337     {
3338       ClutterPaintNode *node;
3339       ClutterColor bg_color;
3340       ClutterActorBox box;
3341
3342       box.x1 = 0.f;
3343       box.y1 = 0.f;
3344       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3345       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3346
3347       bg_color = priv->bg_color;
3348       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3349                      * priv->bg_color.alpha
3350                      / 255;
3351
3352       node = clutter_color_node_new (&bg_color);
3353       clutter_paint_node_set_name (node, "backgroundColor");
3354       clutter_paint_node_add_rectangle (node, &box);
3355       clutter_paint_node_add_child (root, node);
3356       clutter_paint_node_unref (node);
3357     }
3358
3359   if (priv->content != NULL)
3360     _clutter_content_paint_content (priv->content, actor, root);
3361
3362   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3363     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3364
3365   if (clutter_paint_node_get_n_children (root) == 0)
3366     return FALSE;
3367
3368 #ifdef CLUTTER_ENABLE_DEBUG
3369   if (CLUTTER_HAS_DEBUG (PAINT))
3370     {
3371       /* dump the tree only if we have one */
3372       _clutter_paint_node_dump_tree (root);
3373     }
3374 #endif /* CLUTTER_ENABLE_DEBUG */
3375
3376   _clutter_paint_node_paint (root);
3377
3378 #if 0
3379   /* XXX: Uncomment this when we disable emitting the paint signal */
3380   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3381 #endif
3382
3383   return TRUE;
3384 }
3385
3386 /**
3387  * clutter_actor_paint:
3388  * @self: A #ClutterActor
3389  *
3390  * Renders the actor to display.
3391  *
3392  * This function should not be called directly by applications.
3393  * Call clutter_actor_queue_redraw() to queue paints, instead.
3394  *
3395  * This function is context-aware, and will either cause a
3396  * regular paint or a pick paint.
3397  *
3398  * This function will emit the #ClutterActor::paint signal or
3399  * the #ClutterActor::pick signal, depending on the context.
3400  *
3401  * This function does not paint the actor if the actor is set to 0,
3402  * unless it is performing a pick paint.
3403  */
3404 void
3405 clutter_actor_paint (ClutterActor *self)
3406 {
3407   ClutterActorPrivate *priv;
3408   ClutterPickMode pick_mode;
3409   gboolean clip_set = FALSE;
3410   gboolean shader_applied = FALSE;
3411
3412   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3413                           "Actor real-paint counter",
3414                           "Increments each time any actor is painted",
3415                           0 /* no application private data */);
3416   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3417                           "Actor pick-paint counter",
3418                           "Increments each time any actor is painted "
3419                           "for picking",
3420                           0 /* no application private data */);
3421
3422   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3423
3424   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3425     return;
3426
3427   priv = self->priv;
3428
3429   pick_mode = _clutter_context_get_pick_mode ();
3430
3431   if (pick_mode == CLUTTER_PICK_NONE)
3432     priv->propagated_one_redraw = FALSE;
3433
3434   /* It's an important optimization that we consider painting of
3435    * actors with 0 opacity to be a NOP... */
3436   if (pick_mode == CLUTTER_PICK_NONE &&
3437       /* ignore top-levels, since they might be transparent */
3438       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3439       /* Use the override opacity if its been set */
3440       ((priv->opacity_override >= 0) ?
3441        priv->opacity_override : priv->opacity) == 0)
3442     return;
3443
3444   /* if we aren't paintable (not in a toplevel with all
3445    * parents paintable) then do nothing.
3446    */
3447   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3448     return;
3449
3450   /* mark that we are in the paint process */
3451   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3452
3453   cogl_push_matrix();
3454
3455   if (priv->enable_model_view_transform)
3456     {
3457       CoglMatrix matrix;
3458
3459       /* XXX: It could be better to cache the modelview with the actor
3460        * instead of progressively building up the transformations on
3461        * the matrix stack every time we paint. */
3462       cogl_get_modelview_matrix (&matrix);
3463       _clutter_actor_apply_modelview_transform (self, &matrix);
3464
3465 #ifdef CLUTTER_ENABLE_DEBUG
3466       /* Catch when out-of-band transforms have been made by actors not as part
3467        * of an apply_transform vfunc... */
3468       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3469         {
3470           CoglMatrix expected_matrix;
3471
3472           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3473                                                              &expected_matrix);
3474
3475           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3476             {
3477               GString *buf = g_string_sized_new (1024);
3478               ClutterActor *parent;
3479
3480               parent = self;
3481               while (parent != NULL)
3482                 {
3483                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3484
3485                   if (parent->priv->parent != NULL)
3486                     g_string_append (buf, "->");
3487
3488                   parent = parent->priv->parent;
3489                 }
3490
3491               g_warning ("Unexpected transform found when painting actor "
3492                          "\"%s\". This will be caused by one of the actor's "
3493                          "ancestors (%s) using the Cogl API directly to transform "
3494                          "children instead of using ::apply_transform().",
3495                          _clutter_actor_get_debug_name (self),
3496                          buf->str);
3497
3498               g_string_free (buf, TRUE);
3499             }
3500         }
3501 #endif /* CLUTTER_ENABLE_DEBUG */
3502
3503       cogl_set_modelview_matrix (&matrix);
3504     }
3505
3506   if (priv->has_clip)
3507     {
3508       cogl_clip_push_rectangle (priv->clip.x,
3509                                 priv->clip.y,
3510                                 priv->clip.x + priv->clip.width,
3511                                 priv->clip.y + priv->clip.height);
3512       clip_set = TRUE;
3513     }
3514   else if (priv->clip_to_allocation)
3515     {
3516       gfloat width, height;
3517
3518       width  = priv->allocation.x2 - priv->allocation.x1;
3519       height = priv->allocation.y2 - priv->allocation.y1;
3520
3521       cogl_clip_push_rectangle (0, 0, width, height);
3522       clip_set = TRUE;
3523     }
3524
3525   if (pick_mode == CLUTTER_PICK_NONE)
3526     {
3527       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3528
3529       /* We check whether we need to add the flatten effect before
3530          each paint so that we can avoid having a mechanism for
3531          applications to notify when the value of the
3532          has_overlaps virtual changes. */
3533       add_or_remove_flatten_effect (self);
3534     }
3535   else
3536     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3537
3538   /* We save the current paint volume so that the next time the
3539    * actor queues a redraw we can constrain the redraw to just
3540    * cover the union of the new bounding box and the old.
3541    *
3542    * We also fetch the current paint volume to perform culling so
3543    * we can avoid painting actors outside the current clip region.
3544    *
3545    * If we are painting inside a clone, we should neither update
3546    * the paint volume or use it to cull painting, since the paint
3547    * box represents the location of the source actor on the
3548    * screen.
3549    *
3550    * XXX: We are starting to do a lot of vertex transforms on
3551    * the CPU in a typical paint, so at some point we should
3552    * audit these and consider caching some things.
3553    *
3554    * NB: We don't perform culling while picking at this point because
3555    * clutter-stage.c doesn't setup the clipping planes appropriately.
3556    *
3557    * NB: We don't want to update the last-paint-volume during picking
3558    * because the last-paint-volume is used to determine the old screen
3559    * space location of an actor that has moved so we can know the
3560    * minimal region to redraw to clear an old view of the actor. If we
3561    * update this during picking then by the time we come around to
3562    * paint then the last-paint-volume would likely represent the new
3563    * actor position not the old.
3564    */
3565   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3566     {
3567       gboolean success;
3568       /* annoyingly gcc warns if uninitialized even though
3569        * the initialization is redundant :-( */
3570       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3571
3572       if (G_LIKELY ((clutter_paint_debug_flags &
3573                      (CLUTTER_DEBUG_DISABLE_CULLING |
3574                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3575                     (CLUTTER_DEBUG_DISABLE_CULLING |
3576                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3577         _clutter_actor_update_last_paint_volume (self);
3578
3579       success = cull_actor (self, &result);
3580
3581       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3582         _clutter_actor_paint_cull_result (self, success, result);
3583       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3584         goto done;
3585     }
3586
3587   if (priv->effects == NULL)
3588     {
3589       if (pick_mode == CLUTTER_PICK_NONE &&
3590           actor_has_shader_data (self))
3591         {
3592           _clutter_actor_shader_pre_paint (self, FALSE);
3593           shader_applied = TRUE;
3594         }
3595
3596       priv->next_effect_to_paint = NULL;
3597     }
3598   else
3599     priv->next_effect_to_paint =
3600       _clutter_meta_group_peek_metas (priv->effects);
3601
3602   clutter_actor_continue_paint (self);
3603
3604   if (shader_applied)
3605     _clutter_actor_shader_post_paint (self);
3606
3607   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3608                   pick_mode == CLUTTER_PICK_NONE))
3609     _clutter_actor_draw_paint_volume (self);
3610
3611 done:
3612   /* If we make it here then the actor has run through a complete
3613      paint run including all the effects so it's no longer dirty */
3614   if (pick_mode == CLUTTER_PICK_NONE)
3615     priv->is_dirty = FALSE;
3616
3617   if (clip_set)
3618     cogl_clip_pop();
3619
3620   cogl_pop_matrix();
3621
3622   /* paint sequence complete */
3623   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3624 }
3625
3626 /**
3627  * clutter_actor_continue_paint:
3628  * @self: A #ClutterActor
3629  *
3630  * Run the next stage of the paint sequence. This function should only
3631  * be called within the implementation of the ‘run’ virtual of a
3632  * #ClutterEffect. It will cause the run method of the next effect to
3633  * be applied, or it will paint the actual actor if the current effect
3634  * is the last effect in the chain.
3635  *
3636  * Since: 1.8
3637  */
3638 void
3639 clutter_actor_continue_paint (ClutterActor *self)
3640 {
3641   ClutterActorPrivate *priv;
3642
3643   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3644   /* This should only be called from with in the ‘run’ implementation
3645      of a ClutterEffect */
3646   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3647
3648   priv = self->priv;
3649
3650   /* Skip any effects that are disabled */
3651   while (priv->next_effect_to_paint &&
3652          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3653     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3654
3655   /* If this has come from the last effect then we'll just paint the
3656      actual actor */
3657   if (priv->next_effect_to_paint == NULL)
3658     {
3659       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3660         {
3661           ClutterPaintNode *dummy;
3662
3663           /* XXX - this will go away in 2.0, when we can get rid of this
3664            * stuff and switch to a pure retained render tree of PaintNodes
3665            * for the entire frame, starting from the Stage; the paint()
3666            * virtual function can then be called directly.
3667            */
3668           dummy = _clutter_dummy_node_new (self);
3669           clutter_paint_node_set_name (dummy, "Root");
3670
3671           /* XXX - for 1.12, we use the return value of paint_node() to
3672            * decide whether we should emit the ::paint signal.
3673            */
3674           clutter_actor_paint_node (self, dummy);
3675           clutter_paint_node_unref (dummy);
3676
3677           g_signal_emit (self, actor_signals[PAINT], 0);
3678         }
3679       else
3680         {
3681           ClutterColor col = { 0, };
3682
3683           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3684
3685           /* Actor will then paint silhouette of itself in supplied
3686            * color.  See clutter_stage_get_actor_at_pos() for where
3687            * picking is enabled.
3688            */
3689           g_signal_emit (self, actor_signals[PICK], 0, &col);
3690         }
3691     }
3692   else
3693     {
3694       ClutterEffect *old_current_effect;
3695       ClutterEffectPaintFlags run_flags = 0;
3696
3697       /* Cache the current effect so that we can put it back before
3698          returning */
3699       old_current_effect = priv->current_effect;
3700
3701       priv->current_effect = priv->next_effect_to_paint->data;
3702       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3703
3704       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3705         {
3706           if (priv->is_dirty)
3707             {
3708               /* If there's an effect queued with this redraw then all
3709                  effects up to that one will be considered dirty. It
3710                  is expected the queued effect will paint the cached
3711                  image and not call clutter_actor_continue_paint again
3712                  (although it should work ok if it does) */
3713               if (priv->effect_to_redraw == NULL ||
3714                   priv->current_effect != priv->effect_to_redraw)
3715                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3716             }
3717
3718           _clutter_effect_paint (priv->current_effect, run_flags);
3719         }
3720       else
3721         {
3722           /* We can't determine when an actor has been modified since
3723              its last pick so lets just assume it has always been
3724              modified */
3725           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3726
3727           _clutter_effect_pick (priv->current_effect, run_flags);
3728         }
3729
3730       priv->current_effect = old_current_effect;
3731     }
3732 }
3733
3734 static ClutterActorTraverseVisitFlags
3735 invalidate_queue_redraw_entry (ClutterActor *self,
3736                                int           depth,
3737                                gpointer      user_data)
3738 {
3739   ClutterActorPrivate *priv = self->priv;
3740
3741   if (priv->queue_redraw_entry != NULL)
3742     {
3743       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3744       priv->queue_redraw_entry = NULL;
3745     }
3746
3747   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3748 }
3749
3750 static inline void
3751 remove_child (ClutterActor *self,
3752               ClutterActor *child)
3753 {
3754   ClutterActor *prev_sibling, *next_sibling;
3755
3756   prev_sibling = child->priv->prev_sibling;
3757   next_sibling = child->priv->next_sibling;
3758
3759   if (prev_sibling != NULL)
3760     prev_sibling->priv->next_sibling = next_sibling;
3761
3762   if (next_sibling != NULL)
3763     next_sibling->priv->prev_sibling = prev_sibling;
3764
3765   if (self->priv->first_child == child)
3766     self->priv->first_child = next_sibling;
3767
3768   if (self->priv->last_child == child)
3769     self->priv->last_child = prev_sibling;
3770
3771   child->priv->parent = NULL;
3772   child->priv->prev_sibling = NULL;
3773   child->priv->next_sibling = NULL;
3774 }
3775
3776 typedef enum {
3777   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3778   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3779   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3780   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3781   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3782   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3783
3784   /* default flags for public API */
3785   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3786                                     REMOVE_CHILD_EMIT_PARENT_SET |
3787                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3788                                     REMOVE_CHILD_CHECK_STATE |
3789                                     REMOVE_CHILD_FLUSH_QUEUE |
3790                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3791
3792   /* flags for legacy/deprecated API */
3793   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3794                                     REMOVE_CHILD_FLUSH_QUEUE |
3795                                     REMOVE_CHILD_EMIT_PARENT_SET |
3796                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3797 } ClutterActorRemoveChildFlags;
3798
3799 /*< private >
3800  * clutter_actor_remove_child_internal:
3801  * @self: a #ClutterActor
3802  * @child: the child of @self that has to be removed
3803  * @flags: control the removal operations
3804  *
3805  * Removes @child from the list of children of @self.
3806  */
3807 static void
3808 clutter_actor_remove_child_internal (ClutterActor                 *self,
3809                                      ClutterActor                 *child,
3810                                      ClutterActorRemoveChildFlags  flags)
3811 {
3812   ClutterActor *old_first, *old_last;
3813   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3814   gboolean flush_queue;
3815   gboolean notify_first_last;
3816   gboolean was_mapped;
3817
3818   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3819   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3820   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3821   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3822   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3823   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3824
3825   g_object_freeze_notify (G_OBJECT (self));
3826
3827   if (destroy_meta)
3828     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3829
3830   if (check_state)
3831     {
3832       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3833
3834       /* we need to unrealize *before* we set parent_actor to NULL,
3835        * because in an unrealize method actors are dissociating from the
3836        * stage, which means they need to be able to
3837        * clutter_actor_get_stage().
3838        *
3839        * yhis should unmap and unrealize, unless we're reparenting.
3840        */
3841       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3842     }
3843   else
3844     was_mapped = FALSE;
3845
3846   if (flush_queue)
3847     {
3848       /* We take this opportunity to invalidate any queue redraw entry
3849        * associated with the actor and descendants since we won't be able to
3850        * determine the appropriate stage after this.
3851        *
3852        * we do this after we updated the mapped state because actors might
3853        * end up queueing redraws inside their mapped/unmapped virtual
3854        * functions, and if we invalidate the redraw entry we could end up
3855        * with an inconsistent state and weird memory corruption. see
3856        * bugs:
3857        *
3858        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3859        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3860        */
3861       _clutter_actor_traverse (child,
3862                                0,
3863                                invalidate_queue_redraw_entry,
3864                                NULL,
3865                                NULL);
3866     }
3867
3868   old_first = self->priv->first_child;
3869   old_last = self->priv->last_child;
3870
3871   remove_child (self, child);
3872
3873   self->priv->n_children -= 1;
3874
3875   self->priv->age += 1;
3876
3877   /* clutter_actor_reparent() will emit ::parent-set for us */
3878   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3879     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3880
3881   /* if the child was mapped then we need to relayout ourselves to account
3882    * for the removed child
3883    */
3884   if (was_mapped)
3885     clutter_actor_queue_relayout (self);
3886
3887   /* we need to emit the signal before dropping the reference */
3888   if (emit_actor_removed)
3889     g_signal_emit_by_name (self, "actor-removed", child);
3890
3891   if (notify_first_last)
3892     {
3893       if (old_first != self->priv->first_child)
3894         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3895
3896       if (old_last != self->priv->last_child)
3897         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3898     }
3899
3900   g_object_thaw_notify (G_OBJECT (self));
3901
3902   /* remove the reference we acquired in clutter_actor_add_child() */
3903   g_object_unref (child);
3904 }
3905
3906 static const ClutterTransformInfo default_transform_info = {
3907   0.0, { 0, },          /* rotation-x */
3908   0.0, { 0, },          /* rotation-y */
3909   0.0, { 0, },          /* rotation-z */
3910
3911   1.0, 1.0, { 0, },     /* scale */
3912
3913   { 0, },               /* anchor */
3914
3915   0.0,                  /* depth */
3916 };
3917
3918 /*< private >
3919  * _clutter_actor_get_transform_info_or_defaults:
3920  * @self: a #ClutterActor
3921  *
3922  * Retrieves the ClutterTransformInfo structure associated to an actor.
3923  *
3924  * If the actor does not have a ClutterTransformInfo structure associated
3925  * to it, then the default structure will be returned.
3926  *
3927  * This function should only be used for getters.
3928  *
3929  * Return value: a const pointer to the ClutterTransformInfo structure
3930  */
3931 const ClutterTransformInfo *
3932 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3933 {
3934   ClutterTransformInfo *info;
3935
3936   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3937   if (info != NULL)
3938     return info;
3939
3940   return &default_transform_info;
3941 }
3942
3943 static void
3944 clutter_transform_info_free (gpointer data)
3945 {
3946   if (data != NULL)
3947     g_slice_free (ClutterTransformInfo, data);
3948 }
3949
3950 /*< private >
3951  * _clutter_actor_get_transform_info:
3952  * @self: a #ClutterActor
3953  *
3954  * Retrieves a pointer to the ClutterTransformInfo structure.
3955  *
3956  * If the actor does not have a ClutterTransformInfo associated to it, one
3957  * will be created and initialized to the default values.
3958  *
3959  * This function should be used for setters.
3960  *
3961  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3962  * instead.
3963  *
3964  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3965  *   structure
3966  */
3967 ClutterTransformInfo *
3968 _clutter_actor_get_transform_info (ClutterActor *self)
3969 {
3970   ClutterTransformInfo *info;
3971
3972   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3973   if (info == NULL)
3974     {
3975       info = g_slice_new (ClutterTransformInfo);
3976
3977       *info = default_transform_info;
3978
3979       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3980                                info,
3981                                clutter_transform_info_free);
3982     }
3983
3984   return info;
3985 }
3986
3987 /*< private >
3988  * clutter_actor_set_rotation_angle_internal:
3989  * @self: a #ClutterActor
3990  * @axis: the axis of the angle to change
3991  * @angle: the angle of rotation
3992  *
3993  * Sets the rotation angle on the given axis without affecting the
3994  * rotation center point.
3995  */
3996 static inline void
3997 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
3998                                            ClutterRotateAxis  axis,
3999                                            gdouble            angle)
4000 {
4001   GObject *obj = G_OBJECT (self);
4002   ClutterTransformInfo *info;
4003
4004   info = _clutter_actor_get_transform_info (self);
4005
4006   g_object_freeze_notify (obj);
4007
4008   switch (axis)
4009     {
4010     case CLUTTER_X_AXIS:
4011       info->rx_angle = angle;
4012       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4013       break;
4014
4015     case CLUTTER_Y_AXIS:
4016       info->ry_angle = angle;
4017       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4018       break;
4019
4020     case CLUTTER_Z_AXIS:
4021       info->rz_angle = angle;
4022       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4023       break;
4024     }
4025
4026   self->priv->transform_valid = FALSE;
4027
4028   g_object_thaw_notify (obj);
4029
4030   clutter_actor_queue_redraw (self);
4031 }
4032
4033 static inline void
4034 clutter_actor_set_rotation_angle (ClutterActor      *self,
4035                                   ClutterRotateAxis  axis,
4036                                   gdouble            angle)
4037 {
4038   const ClutterTransformInfo *info;
4039   const double *cur_angle_p = NULL;
4040   GParamSpec *pspec = NULL;
4041
4042   info = _clutter_actor_get_transform_info_or_defaults (self);
4043
4044   switch (axis)
4045     {
4046     case CLUTTER_X_AXIS:
4047       cur_angle_p = &info->rx_angle;
4048       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4049       break;
4050
4051     case CLUTTER_Y_AXIS:
4052       cur_angle_p = &info->ry_angle;
4053       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4054       break;
4055
4056     case CLUTTER_Z_AXIS:
4057       cur_angle_p = &info->rz_angle;
4058       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4059       break;
4060     }
4061
4062   g_assert (pspec != NULL);
4063   g_assert (cur_angle_p != NULL);
4064
4065   if (_clutter_actor_get_transition (self, pspec) == NULL)
4066     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4067   else
4068     _clutter_actor_update_transition (self, pspec, angle);
4069
4070   clutter_actor_queue_redraw (self);
4071 }
4072
4073 /*< private >
4074  * clutter_actor_set_rotation_center_internal:
4075  * @self: a #ClutterActor
4076  * @axis: the axis of the center to change
4077  * @center: the coordinates of the rotation center
4078  *
4079  * Sets the rotation center on the given axis without affecting the
4080  * rotation angle.
4081  */
4082 static inline void
4083 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4084                                             ClutterRotateAxis    axis,
4085                                             const ClutterVertex *center)
4086 {
4087   GObject *obj = G_OBJECT (self);
4088   ClutterTransformInfo *info;
4089   ClutterVertex v = { 0, 0, 0 };
4090
4091   info = _clutter_actor_get_transform_info (self);
4092
4093   if (center != NULL)
4094     v = *center;
4095
4096   g_object_freeze_notify (obj);
4097
4098   switch (axis)
4099     {
4100     case CLUTTER_X_AXIS:
4101       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4102       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4103       break;
4104
4105     case CLUTTER_Y_AXIS:
4106       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4107       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4108       break;
4109
4110     case CLUTTER_Z_AXIS:
4111       /* if the previously set rotation center was fractional, then
4112        * setting explicit coordinates will have to notify the
4113        * :rotation-center-z-gravity property as well
4114        */
4115       if (info->rz_center.is_fractional)
4116         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4117
4118       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4119       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4120       break;
4121     }
4122
4123   self->priv->transform_valid = FALSE;
4124
4125   g_object_thaw_notify (obj);
4126
4127   clutter_actor_queue_redraw (self);
4128 }
4129
4130 static void
4131 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4132                                          double factor,
4133                                          GParamSpec *pspec)
4134 {
4135   GObject *obj = G_OBJECT (self);
4136   ClutterTransformInfo *info;
4137
4138   info = _clutter_actor_get_transform_info (self);
4139
4140   if (pspec == obj_props[PROP_SCALE_X])
4141     info->scale_x = factor;
4142   else
4143     info->scale_y = factor;
4144
4145   self->priv->transform_valid = FALSE;
4146   clutter_actor_queue_redraw (self);
4147   g_object_notify_by_pspec (obj, pspec);
4148 }
4149
4150 static inline void
4151 clutter_actor_set_scale_factor (ClutterActor      *self,
4152                                 ClutterRotateAxis  axis,
4153                                 gdouble            factor)
4154 {
4155   const ClutterTransformInfo *info;
4156   const double *scale_p = NULL;
4157   GParamSpec *pspec = NULL;
4158
4159   info = _clutter_actor_get_transform_info_or_defaults (self);
4160
4161   switch (axis)
4162     {
4163     case CLUTTER_X_AXIS:
4164       pspec = obj_props[PROP_SCALE_X];
4165       scale_p = &info->scale_x;
4166       break;
4167
4168     case CLUTTER_Y_AXIS:
4169       pspec = obj_props[PROP_SCALE_Y];
4170       scale_p = &info->scale_y;
4171       break;
4172
4173     case CLUTTER_Z_AXIS:
4174       break;
4175     }
4176
4177   g_assert (pspec != NULL);
4178   g_assert (scale_p != NULL);
4179
4180   if (_clutter_actor_get_transition (self, pspec) == NULL)
4181     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4182   else
4183     _clutter_actor_update_transition (self, pspec, factor);
4184
4185   clutter_actor_queue_redraw (self);
4186 }
4187
4188 static inline void
4189 clutter_actor_set_scale_center (ClutterActor      *self,
4190                                 ClutterRotateAxis  axis,
4191                                 gfloat             coord)
4192 {
4193   GObject *obj = G_OBJECT (self);
4194   ClutterTransformInfo *info;
4195   gfloat center_x, center_y;
4196
4197   info = _clutter_actor_get_transform_info (self);
4198
4199   g_object_freeze_notify (obj);
4200
4201   /* get the current scale center coordinates */
4202   clutter_anchor_coord_get_units (self, &info->scale_center,
4203                                   &center_x,
4204                                   &center_y,
4205                                   NULL);
4206
4207   /* we need to notify this too, because setting explicit coordinates will
4208    * change the gravity as a side effect
4209    */
4210   if (info->scale_center.is_fractional)
4211     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4212
4213   switch (axis)
4214     {
4215     case CLUTTER_X_AXIS:
4216       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4217       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4218       break;
4219
4220     case CLUTTER_Y_AXIS:
4221       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4222       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4223       break;
4224
4225     default:
4226       g_assert_not_reached ();
4227     }
4228
4229   self->priv->transform_valid = FALSE;
4230
4231   clutter_actor_queue_redraw (self);
4232
4233   g_object_thaw_notify (obj);
4234 }
4235
4236 static inline void
4237 clutter_actor_set_scale_gravity (ClutterActor   *self,
4238                                  ClutterGravity  gravity)
4239 {
4240   ClutterTransformInfo *info;
4241   GObject *obj;
4242
4243   info = _clutter_actor_get_transform_info (self);
4244   obj = G_OBJECT (self);
4245
4246   if (gravity == CLUTTER_GRAVITY_NONE)
4247     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4248   else
4249     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4250
4251   self->priv->transform_valid = FALSE;
4252
4253   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4254   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4255   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4256
4257   clutter_actor_queue_redraw (self);
4258 }
4259
4260 static inline void
4261 clutter_actor_set_anchor_coord (ClutterActor      *self,
4262                                 ClutterRotateAxis  axis,
4263                                 gfloat             coord)
4264 {
4265   GObject *obj = G_OBJECT (self);
4266   ClutterTransformInfo *info;
4267   gfloat anchor_x, anchor_y;
4268
4269   info = _clutter_actor_get_transform_info (self);
4270
4271   g_object_freeze_notify (obj);
4272
4273   clutter_anchor_coord_get_units (self, &info->anchor,
4274                                   &anchor_x,
4275                                   &anchor_y,
4276                                   NULL);
4277
4278   if (info->anchor.is_fractional)
4279     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4280
4281   switch (axis)
4282     {
4283     case CLUTTER_X_AXIS:
4284       clutter_anchor_coord_set_units (&info->anchor,
4285                                       coord,
4286                                       anchor_y,
4287                                       0.0);
4288       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4289       break;
4290
4291     case CLUTTER_Y_AXIS:
4292       clutter_anchor_coord_set_units (&info->anchor,
4293                                       anchor_x,
4294                                       coord,
4295                                       0.0);
4296       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4297       break;
4298
4299     default:
4300       g_assert_not_reached ();
4301     }
4302
4303   self->priv->transform_valid = FALSE;
4304
4305   clutter_actor_queue_redraw (self);
4306
4307   g_object_thaw_notify (obj);
4308 }
4309
4310 static void
4311 clutter_actor_set_property (GObject      *object,
4312                             guint         prop_id,
4313                             const GValue *value,
4314                             GParamSpec   *pspec)
4315 {
4316   ClutterActor *actor = CLUTTER_ACTOR (object);
4317   ClutterActorPrivate *priv = actor->priv;
4318
4319   switch (prop_id)
4320     {
4321     case PROP_X:
4322       clutter_actor_set_x (actor, g_value_get_float (value));
4323       break;
4324
4325     case PROP_Y:
4326       clutter_actor_set_y (actor, g_value_get_float (value));
4327       break;
4328
4329     case PROP_WIDTH:
4330       clutter_actor_set_width (actor, g_value_get_float (value));
4331       break;
4332
4333     case PROP_HEIGHT:
4334       clutter_actor_set_height (actor, g_value_get_float (value));
4335       break;
4336
4337     case PROP_FIXED_X:
4338       clutter_actor_set_x (actor, g_value_get_float (value));
4339       break;
4340
4341     case PROP_FIXED_Y:
4342       clutter_actor_set_y (actor, g_value_get_float (value));
4343       break;
4344
4345     case PROP_FIXED_POSITION_SET:
4346       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4347       break;
4348
4349     case PROP_MIN_WIDTH:
4350       clutter_actor_set_min_width (actor, g_value_get_float (value));
4351       break;
4352
4353     case PROP_MIN_HEIGHT:
4354       clutter_actor_set_min_height (actor, g_value_get_float (value));
4355       break;
4356
4357     case PROP_NATURAL_WIDTH:
4358       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4359       break;
4360
4361     case PROP_NATURAL_HEIGHT:
4362       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4363       break;
4364
4365     case PROP_MIN_WIDTH_SET:
4366       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4367       break;
4368
4369     case PROP_MIN_HEIGHT_SET:
4370       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4371       break;
4372
4373     case PROP_NATURAL_WIDTH_SET:
4374       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4375       break;
4376
4377     case PROP_NATURAL_HEIGHT_SET:
4378       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4379       break;
4380
4381     case PROP_REQUEST_MODE:
4382       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4383       break;
4384
4385     case PROP_DEPTH:
4386       clutter_actor_set_depth (actor, g_value_get_float (value));
4387       break;
4388
4389     case PROP_OPACITY:
4390       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4391       break;
4392
4393     case PROP_OFFSCREEN_REDIRECT:
4394       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4395       break;
4396
4397     case PROP_NAME:
4398       clutter_actor_set_name (actor, g_value_get_string (value));
4399       break;
4400
4401     case PROP_VISIBLE:
4402       if (g_value_get_boolean (value) == TRUE)
4403         clutter_actor_show (actor);
4404       else
4405         clutter_actor_hide (actor);
4406       break;
4407
4408     case PROP_SCALE_X:
4409       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4410                                       g_value_get_double (value));
4411       break;
4412
4413     case PROP_SCALE_Y:
4414       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4415                                       g_value_get_double (value));
4416       break;
4417
4418     case PROP_SCALE_CENTER_X:
4419       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4420                                       g_value_get_float (value));
4421       break;
4422
4423     case PROP_SCALE_CENTER_Y:
4424       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4425                                       g_value_get_float (value));
4426       break;
4427
4428     case PROP_SCALE_GRAVITY:
4429       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4430       break;
4431
4432     case PROP_CLIP:
4433       {
4434         const ClutterGeometry *geom = g_value_get_boxed (value);
4435
4436         clutter_actor_set_clip (actor,
4437                                 geom->x, geom->y,
4438                                 geom->width, geom->height);
4439       }
4440       break;
4441
4442     case PROP_CLIP_TO_ALLOCATION:
4443       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4444       break;
4445
4446     case PROP_REACTIVE:
4447       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4448       break;
4449
4450     case PROP_ROTATION_ANGLE_X:
4451       clutter_actor_set_rotation_angle (actor,
4452                                         CLUTTER_X_AXIS,
4453                                         g_value_get_double (value));
4454       break;
4455
4456     case PROP_ROTATION_ANGLE_Y:
4457       clutter_actor_set_rotation_angle (actor,
4458                                         CLUTTER_Y_AXIS,
4459                                         g_value_get_double (value));
4460       break;
4461
4462     case PROP_ROTATION_ANGLE_Z:
4463       clutter_actor_set_rotation_angle (actor,
4464                                         CLUTTER_Z_AXIS,
4465                                         g_value_get_double (value));
4466       break;
4467
4468     case PROP_ROTATION_CENTER_X:
4469       clutter_actor_set_rotation_center_internal (actor,
4470                                                   CLUTTER_X_AXIS,
4471                                                   g_value_get_boxed (value));
4472       break;
4473
4474     case PROP_ROTATION_CENTER_Y:
4475       clutter_actor_set_rotation_center_internal (actor,
4476                                                   CLUTTER_Y_AXIS,
4477                                                   g_value_get_boxed (value));
4478       break;
4479
4480     case PROP_ROTATION_CENTER_Z:
4481       clutter_actor_set_rotation_center_internal (actor,
4482                                                   CLUTTER_Z_AXIS,
4483                                                   g_value_get_boxed (value));
4484       break;
4485
4486     case PROP_ROTATION_CENTER_Z_GRAVITY:
4487       {
4488         const ClutterTransformInfo *info;
4489
4490         info = _clutter_actor_get_transform_info_or_defaults (actor);
4491         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4492                                                    g_value_get_enum (value));
4493       }
4494       break;
4495
4496     case PROP_ANCHOR_X:
4497       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4498                                       g_value_get_float (value));
4499       break;
4500
4501     case PROP_ANCHOR_Y:
4502       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4503                                       g_value_get_float (value));
4504       break;
4505
4506     case PROP_ANCHOR_GRAVITY:
4507       clutter_actor_set_anchor_point_from_gravity (actor,
4508                                                    g_value_get_enum (value));
4509       break;
4510
4511     case PROP_SHOW_ON_SET_PARENT:
4512       priv->show_on_set_parent = g_value_get_boolean (value);
4513       break;
4514
4515     case PROP_TEXT_DIRECTION:
4516       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4517       break;
4518
4519     case PROP_ACTIONS:
4520       clutter_actor_add_action (actor, g_value_get_object (value));
4521       break;
4522
4523     case PROP_CONSTRAINTS:
4524       clutter_actor_add_constraint (actor, g_value_get_object (value));
4525       break;
4526
4527     case PROP_EFFECT:
4528       clutter_actor_add_effect (actor, g_value_get_object (value));
4529       break;
4530
4531     case PROP_LAYOUT_MANAGER:
4532       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4533       break;
4534
4535     case PROP_X_ALIGN:
4536       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4537       break;
4538
4539     case PROP_Y_ALIGN:
4540       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4541       break;
4542
4543     case PROP_MARGIN_TOP:
4544       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4545       break;
4546
4547     case PROP_MARGIN_BOTTOM:
4548       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4549       break;
4550
4551     case PROP_MARGIN_LEFT:
4552       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4553       break;
4554
4555     case PROP_MARGIN_RIGHT:
4556       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4557       break;
4558
4559     case PROP_BACKGROUND_COLOR:
4560       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4561       break;
4562
4563     case PROP_CONTENT:
4564       clutter_actor_set_content (actor, g_value_get_object (value));
4565       break;
4566
4567     case PROP_CONTENT_GRAVITY:
4568       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4569       break;
4570
4571     case PROP_MINIFICATION_FILTER:
4572       clutter_actor_set_content_scaling_filters (actor,
4573                                                  g_value_get_enum (value),
4574                                                  actor->priv->mag_filter);
4575       break;
4576
4577     case PROP_MAGNIFICATION_FILTER:
4578       clutter_actor_set_content_scaling_filters (actor,
4579                                                  actor->priv->min_filter,
4580                                                  g_value_get_enum (value));
4581       break;
4582
4583     default:
4584       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4585       break;
4586     }
4587 }
4588
4589 static void
4590 clutter_actor_get_property (GObject    *object,
4591                             guint       prop_id,
4592                             GValue     *value,
4593                             GParamSpec *pspec)
4594 {
4595   ClutterActor *actor = CLUTTER_ACTOR (object);
4596   ClutterActorPrivate *priv = actor->priv;
4597
4598   switch (prop_id)
4599     {
4600     case PROP_X:
4601       g_value_set_float (value, clutter_actor_get_x (actor));
4602       break;
4603
4604     case PROP_Y:
4605       g_value_set_float (value, clutter_actor_get_y (actor));
4606       break;
4607
4608     case PROP_WIDTH:
4609       g_value_set_float (value, clutter_actor_get_width (actor));
4610       break;
4611
4612     case PROP_HEIGHT:
4613       g_value_set_float (value, clutter_actor_get_height (actor));
4614       break;
4615
4616     case PROP_FIXED_X:
4617       {
4618         const ClutterLayoutInfo *info;
4619
4620         info = _clutter_actor_get_layout_info_or_defaults (actor);
4621         g_value_set_float (value, info->fixed_x);
4622       }
4623       break;
4624
4625     case PROP_FIXED_Y:
4626       {
4627         const ClutterLayoutInfo *info;
4628
4629         info = _clutter_actor_get_layout_info_or_defaults (actor);
4630         g_value_set_float (value, info->fixed_y);
4631       }
4632       break;
4633
4634     case PROP_FIXED_POSITION_SET:
4635       g_value_set_boolean (value, priv->position_set);
4636       break;
4637
4638     case PROP_MIN_WIDTH:
4639       {
4640         const ClutterLayoutInfo *info;
4641
4642         info = _clutter_actor_get_layout_info_or_defaults (actor);
4643         g_value_set_float (value, info->min_width);
4644       }
4645       break;
4646
4647     case PROP_MIN_HEIGHT:
4648       {
4649         const ClutterLayoutInfo *info;
4650
4651         info = _clutter_actor_get_layout_info_or_defaults (actor);
4652         g_value_set_float (value, info->min_height);
4653       }
4654       break;
4655
4656     case PROP_NATURAL_WIDTH:
4657       {
4658         const ClutterLayoutInfo *info;
4659
4660         info = _clutter_actor_get_layout_info_or_defaults (actor);
4661         g_value_set_float (value, info->natural_width);
4662       }
4663       break;
4664
4665     case PROP_NATURAL_HEIGHT:
4666       {
4667         const ClutterLayoutInfo *info;
4668
4669         info = _clutter_actor_get_layout_info_or_defaults (actor);
4670         g_value_set_float (value, info->natural_height);
4671       }
4672       break;
4673
4674     case PROP_MIN_WIDTH_SET:
4675       g_value_set_boolean (value, priv->min_width_set);
4676       break;
4677
4678     case PROP_MIN_HEIGHT_SET:
4679       g_value_set_boolean (value, priv->min_height_set);
4680       break;
4681
4682     case PROP_NATURAL_WIDTH_SET:
4683       g_value_set_boolean (value, priv->natural_width_set);
4684       break;
4685
4686     case PROP_NATURAL_HEIGHT_SET:
4687       g_value_set_boolean (value, priv->natural_height_set);
4688       break;
4689
4690     case PROP_REQUEST_MODE:
4691       g_value_set_enum (value, priv->request_mode);
4692       break;
4693
4694     case PROP_ALLOCATION:
4695       g_value_set_boxed (value, &priv->allocation);
4696       break;
4697
4698     case PROP_DEPTH:
4699       g_value_set_float (value, clutter_actor_get_depth (actor));
4700       break;
4701
4702     case PROP_OPACITY:
4703       g_value_set_uint (value, priv->opacity);
4704       break;
4705
4706     case PROP_OFFSCREEN_REDIRECT:
4707       g_value_set_enum (value, priv->offscreen_redirect);
4708       break;
4709
4710     case PROP_NAME:
4711       g_value_set_string (value, priv->name);
4712       break;
4713
4714     case PROP_VISIBLE:
4715       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4716       break;
4717
4718     case PROP_MAPPED:
4719       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4720       break;
4721
4722     case PROP_REALIZED:
4723       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4724       break;
4725
4726     case PROP_HAS_CLIP:
4727       g_value_set_boolean (value, priv->has_clip);
4728       break;
4729
4730     case PROP_CLIP:
4731       {
4732         ClutterGeometry clip;
4733
4734         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4735         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4736         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4737         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4738
4739         g_value_set_boxed (value, &clip);
4740       }
4741       break;
4742
4743     case PROP_CLIP_TO_ALLOCATION:
4744       g_value_set_boolean (value, priv->clip_to_allocation);
4745       break;
4746
4747     case PROP_SCALE_X:
4748       {
4749         const ClutterTransformInfo *info;
4750
4751         info = _clutter_actor_get_transform_info_or_defaults (actor);
4752         g_value_set_double (value, info->scale_x);
4753       }
4754       break;
4755
4756     case PROP_SCALE_Y:
4757       {
4758         const ClutterTransformInfo *info;
4759
4760         info = _clutter_actor_get_transform_info_or_defaults (actor);
4761         g_value_set_double (value, info->scale_y);
4762       }
4763       break;
4764
4765     case PROP_SCALE_CENTER_X:
4766       {
4767         gfloat center;
4768
4769         clutter_actor_get_scale_center (actor, &center, NULL);
4770
4771         g_value_set_float (value, center);
4772       }
4773       break;
4774
4775     case PROP_SCALE_CENTER_Y:
4776       {
4777         gfloat center;
4778
4779         clutter_actor_get_scale_center (actor, NULL, &center);
4780
4781         g_value_set_float (value, center);
4782       }
4783       break;
4784
4785     case PROP_SCALE_GRAVITY:
4786       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4787       break;
4788
4789     case PROP_REACTIVE:
4790       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4791       break;
4792
4793     case PROP_ROTATION_ANGLE_X:
4794       {
4795         const ClutterTransformInfo *info;
4796
4797         info = _clutter_actor_get_transform_info_or_defaults (actor);
4798         g_value_set_double (value, info->rx_angle);
4799       }
4800       break;
4801
4802     case PROP_ROTATION_ANGLE_Y:
4803       {
4804         const ClutterTransformInfo *info;
4805
4806         info = _clutter_actor_get_transform_info_or_defaults (actor);
4807         g_value_set_double (value, info->ry_angle);
4808       }
4809       break;
4810
4811     case PROP_ROTATION_ANGLE_Z:
4812       {
4813         const ClutterTransformInfo *info;
4814
4815         info = _clutter_actor_get_transform_info_or_defaults (actor);
4816         g_value_set_double (value, info->rz_angle);
4817       }
4818       break;
4819
4820     case PROP_ROTATION_CENTER_X:
4821       {
4822         ClutterVertex center;
4823
4824         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4825                                     &center.x,
4826                                     &center.y,
4827                                     &center.z);
4828
4829         g_value_set_boxed (value, &center);
4830       }
4831       break;
4832
4833     case PROP_ROTATION_CENTER_Y:
4834       {
4835         ClutterVertex center;
4836
4837         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4838                                     &center.x,
4839                                     &center.y,
4840                                     &center.z);
4841
4842         g_value_set_boxed (value, &center);
4843       }
4844       break;
4845
4846     case PROP_ROTATION_CENTER_Z:
4847       {
4848         ClutterVertex center;
4849
4850         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4851                                     &center.x,
4852                                     &center.y,
4853                                     &center.z);
4854
4855         g_value_set_boxed (value, &center);
4856       }
4857       break;
4858
4859     case PROP_ROTATION_CENTER_Z_GRAVITY:
4860       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4861       break;
4862
4863     case PROP_ANCHOR_X:
4864       {
4865         const ClutterTransformInfo *info;
4866         gfloat anchor_x;
4867
4868         info = _clutter_actor_get_transform_info_or_defaults (actor);
4869         clutter_anchor_coord_get_units (actor, &info->anchor,
4870                                         &anchor_x,
4871                                         NULL,
4872                                         NULL);
4873         g_value_set_float (value, anchor_x);
4874       }
4875       break;
4876
4877     case PROP_ANCHOR_Y:
4878       {
4879         const ClutterTransformInfo *info;
4880         gfloat anchor_y;
4881
4882         info = _clutter_actor_get_transform_info_or_defaults (actor);
4883         clutter_anchor_coord_get_units (actor, &info->anchor,
4884                                         NULL,
4885                                         &anchor_y,
4886                                         NULL);
4887         g_value_set_float (value, anchor_y);
4888       }
4889       break;
4890
4891     case PROP_ANCHOR_GRAVITY:
4892       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4893       break;
4894
4895     case PROP_SHOW_ON_SET_PARENT:
4896       g_value_set_boolean (value, priv->show_on_set_parent);
4897       break;
4898
4899     case PROP_TEXT_DIRECTION:
4900       g_value_set_enum (value, priv->text_direction);
4901       break;
4902
4903     case PROP_HAS_POINTER:
4904       g_value_set_boolean (value, priv->has_pointer);
4905       break;
4906
4907     case PROP_LAYOUT_MANAGER:
4908       g_value_set_object (value, priv->layout_manager);
4909       break;
4910
4911     case PROP_X_ALIGN:
4912       {
4913         const ClutterLayoutInfo *info;
4914
4915         info = _clutter_actor_get_layout_info_or_defaults (actor);
4916         g_value_set_enum (value, info->x_align);
4917       }
4918       break;
4919
4920     case PROP_Y_ALIGN:
4921       {
4922         const ClutterLayoutInfo *info;
4923
4924         info = _clutter_actor_get_layout_info_or_defaults (actor);
4925         g_value_set_enum (value, info->y_align);
4926       }
4927       break;
4928
4929     case PROP_MARGIN_TOP:
4930       {
4931         const ClutterLayoutInfo *info;
4932
4933         info = _clutter_actor_get_layout_info_or_defaults (actor);
4934         g_value_set_float (value, info->margin.top);
4935       }
4936       break;
4937
4938     case PROP_MARGIN_BOTTOM:
4939       {
4940         const ClutterLayoutInfo *info;
4941
4942         info = _clutter_actor_get_layout_info_or_defaults (actor);
4943         g_value_set_float (value, info->margin.bottom);
4944       }
4945       break;
4946
4947     case PROP_MARGIN_LEFT:
4948       {
4949         const ClutterLayoutInfo *info;
4950
4951         info = _clutter_actor_get_layout_info_or_defaults (actor);
4952         g_value_set_float (value, info->margin.left);
4953       }
4954       break;
4955
4956     case PROP_MARGIN_RIGHT:
4957       {
4958         const ClutterLayoutInfo *info;
4959
4960         info = _clutter_actor_get_layout_info_or_defaults (actor);
4961         g_value_set_float (value, info->margin.right);
4962       }
4963       break;
4964
4965     case PROP_BACKGROUND_COLOR_SET:
4966       g_value_set_boolean (value, priv->bg_color_set);
4967       break;
4968
4969     case PROP_BACKGROUND_COLOR:
4970       g_value_set_boxed (value, &priv->bg_color);
4971       break;
4972
4973     case PROP_FIRST_CHILD:
4974       g_value_set_object (value, priv->first_child);
4975       break;
4976
4977     case PROP_LAST_CHILD:
4978       g_value_set_object (value, priv->last_child);
4979       break;
4980
4981     case PROP_CONTENT:
4982       g_value_set_object (value, priv->content);
4983       break;
4984
4985     case PROP_CONTENT_GRAVITY:
4986       g_value_set_enum (value, priv->content_gravity);
4987       break;
4988
4989     case PROP_CONTENT_BOX:
4990       {
4991         ClutterActorBox box = { 0, };
4992
4993         clutter_actor_get_content_box (actor, &box);
4994         g_value_set_boxed (value, &box);
4995       }
4996       break;
4997
4998     case PROP_MINIFICATION_FILTER:
4999       g_value_set_enum (value, priv->min_filter);
5000       break;
5001
5002     case PROP_MAGNIFICATION_FILTER:
5003       g_value_set_enum (value, priv->mag_filter);
5004       break;
5005
5006     default:
5007       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5008       break;
5009     }
5010 }
5011
5012 static void
5013 clutter_actor_dispose (GObject *object)
5014 {
5015   ClutterActor *self = CLUTTER_ACTOR (object);
5016   ClutterActorPrivate *priv = self->priv;
5017
5018   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5019                 priv->id,
5020                 g_type_name (G_OBJECT_TYPE (self)),
5021                 object->ref_count);
5022
5023   g_signal_emit (self, actor_signals[DESTROY], 0);
5024
5025   /* avoid recursing when called from clutter_actor_destroy() */
5026   if (priv->parent != NULL)
5027     {
5028       ClutterActor *parent = priv->parent;
5029
5030       /* go through the Container implementation unless this
5031        * is an internal child and has been marked as such.
5032        *
5033        * removing the actor from its parent will reset the
5034        * realized and mapped states.
5035        */
5036       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5037         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5038       else
5039         clutter_actor_remove_child_internal (parent, self,
5040                                              REMOVE_CHILD_LEGACY_FLAGS);
5041     }
5042
5043   /* parent must be gone at this point */
5044   g_assert (priv->parent == NULL);
5045
5046   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5047     {
5048       /* can't be mapped or realized with no parent */
5049       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5050       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5051     }
5052
5053   g_clear_object (&priv->pango_context);
5054   g_clear_object (&priv->actions);
5055   g_clear_object (&priv->constraints);
5056   g_clear_object (&priv->effects);
5057   g_clear_object (&priv->flatten_effect);
5058
5059   if (priv->layout_manager != NULL)
5060     {
5061       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5062       g_clear_object (&priv->layout_manager);
5063     }
5064
5065   if (priv->content != NULL)
5066     {
5067       _clutter_content_detached (priv->content, self);
5068       g_clear_object (&priv->content);
5069     }
5070
5071   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5072 }
5073
5074 static void
5075 clutter_actor_finalize (GObject *object)
5076 {
5077   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5078
5079   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5080                 priv->name != NULL ? priv->name : "<none>",
5081                 priv->id,
5082                 g_type_name (G_OBJECT_TYPE (object)));
5083
5084   _clutter_context_release_id (priv->id);
5085
5086   g_free (priv->name);
5087
5088   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5089 }
5090
5091
5092 /**
5093  * clutter_actor_get_accessible:
5094  * @self: a #ClutterActor
5095  *
5096  * Returns the accessible object that describes the actor to an
5097  * assistive technology.
5098  *
5099  * If no class-specific #AtkObject implementation is available for the
5100  * actor instance in question, it will inherit an #AtkObject
5101  * implementation from the first ancestor class for which such an
5102  * implementation is defined.
5103  *
5104  * The documentation of the <ulink
5105  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5106  * library contains more information about accessible objects and
5107  * their uses.
5108  *
5109  * Returns: (transfer none): the #AtkObject associated with @actor
5110  */
5111 AtkObject *
5112 clutter_actor_get_accessible (ClutterActor *self)
5113 {
5114   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5115
5116   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5117 }
5118
5119 static AtkObject *
5120 clutter_actor_real_get_accessible (ClutterActor *actor)
5121 {
5122   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5123 }
5124
5125 static AtkObject *
5126 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5127 {
5128   AtkObject *accessible;
5129
5130   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5131   if (accessible != NULL)
5132     g_object_ref (accessible);
5133
5134   return accessible;
5135 }
5136
5137 static void
5138 atk_implementor_iface_init (AtkImplementorIface *iface)
5139 {
5140   iface->ref_accessible = _clutter_actor_ref_accessible;
5141 }
5142
5143 static gboolean
5144 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5145                                            ClutterPaintVolume *volume)
5146 {
5147   ClutterActorPrivate *priv = self->priv;
5148   gboolean res = FALSE;
5149
5150   /* we start from the allocation */
5151   clutter_paint_volume_set_width (volume,
5152                                   priv->allocation.x2 - priv->allocation.x1);
5153   clutter_paint_volume_set_height (volume,
5154                                    priv->allocation.y2 - priv->allocation.y1);
5155
5156   /* if the actor has a clip set then we have a pretty definite
5157    * size for the paint volume: the actor cannot possibly paint
5158    * outside the clip region.
5159    */
5160   if (priv->clip_to_allocation)
5161     {
5162       /* the allocation has already been set, so we just flip the
5163        * return value
5164        */
5165       res = TRUE;
5166     }
5167   else
5168     {
5169       ClutterActor *child;
5170
5171       if (priv->has_clip &&
5172           priv->clip.width >= 0 &&
5173           priv->clip.height >= 0)
5174         {
5175           ClutterVertex origin;
5176
5177           origin.x = priv->clip.x;
5178           origin.y = priv->clip.y;
5179           origin.z = 0;
5180
5181           clutter_paint_volume_set_origin (volume, &origin);
5182           clutter_paint_volume_set_width (volume, priv->clip.width);
5183           clutter_paint_volume_set_height (volume, priv->clip.height);
5184
5185           res = TRUE;
5186         }
5187
5188       /* if we don't have children we just bail out here... */
5189       if (priv->n_children == 0)
5190         return res;
5191
5192       /* ...but if we have children then we ask for their paint volume in
5193        * our coordinates. if any of our children replies that it doesn't
5194        * have a paint volume, we bail out
5195        */
5196       for (child = priv->first_child;
5197            child != NULL;
5198            child = child->priv->next_sibling)
5199         {
5200           const ClutterPaintVolume *child_volume;
5201
5202           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5203           if (child_volume == NULL)
5204             {
5205               res = FALSE;
5206               break;
5207             }
5208
5209           clutter_paint_volume_union (volume, child_volume);
5210           res = TRUE;
5211         }
5212     }
5213
5214   return res;
5215
5216 }
5217
5218 static gboolean
5219 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5220                                      ClutterPaintVolume *volume)
5221 {
5222   ClutterActorClass *klass;
5223   gboolean res;
5224
5225   klass = CLUTTER_ACTOR_GET_CLASS (self);
5226
5227   /* XXX - this thoroughly sucks, but we don't want to penalize users
5228    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5229    * redraw. This should go away in 2.0.
5230    */
5231   if (klass->paint == clutter_actor_real_paint &&
5232       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5233     {
5234       res = TRUE;
5235     }
5236   else
5237     {
5238       /* this is the default return value: we cannot know if a class
5239        * is going to paint outside its allocation, so we take the
5240        * conservative approach.
5241        */
5242       res = FALSE;
5243     }
5244
5245   if (clutter_actor_update_default_paint_volume (self, volume))
5246     return res;
5247
5248   return FALSE;
5249 }
5250
5251 /**
5252  * clutter_actor_get_default_paint_volume:
5253  * @self: a #ClutterActor
5254  *
5255  * Retrieves the default paint volume for @self.
5256  *
5257  * This function provides the same #ClutterPaintVolume that would be
5258  * computed by the default implementation inside #ClutterActor of the
5259  * #ClutterActorClass.get_paint_volume() virtual function.
5260  *
5261  * This function should only be used by #ClutterActor subclasses that
5262  * cannot chain up to the parent implementation when computing their
5263  * paint volume.
5264  *
5265  * Return value: (transfer none): a pointer to the default
5266  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5267  *   the actor could not compute a valid paint volume. The returned value
5268  *   is not guaranteed to be stable across multiple frames, so if you
5269  *   want to retain it, you will need to copy it using
5270  *   clutter_paint_volume_copy().
5271  *
5272  * Since: 1.10
5273  */
5274 const ClutterPaintVolume *
5275 clutter_actor_get_default_paint_volume (ClutterActor *self)
5276 {
5277   ClutterPaintVolume volume;
5278   ClutterPaintVolume *res;
5279
5280   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5281
5282   res = NULL;
5283   _clutter_paint_volume_init_static (&volume, self);
5284   if (clutter_actor_update_default_paint_volume (self, &volume))
5285     {
5286       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5287
5288       if (stage != NULL)
5289         {
5290           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5291           _clutter_paint_volume_copy_static (&volume, res);
5292         }
5293     }
5294
5295   clutter_paint_volume_free (&volume);
5296
5297   return res;
5298 }
5299
5300 static gboolean
5301 clutter_actor_real_has_overlaps (ClutterActor *self)
5302 {
5303   /* By default we'll assume that all actors need an offscreen redirect to get
5304    * the correct opacity. Actors such as ClutterTexture that would never need
5305    * an offscreen redirect can override this to return FALSE. */
5306   return TRUE;
5307 }
5308
5309 static void
5310 clutter_actor_real_destroy (ClutterActor *actor)
5311 {
5312   ClutterActorIter iter;
5313
5314   g_object_freeze_notify (G_OBJECT (actor));
5315
5316   clutter_actor_iter_init (&iter, actor);
5317   while (clutter_actor_iter_next (&iter, NULL))
5318     clutter_actor_iter_destroy (&iter);
5319
5320   g_object_thaw_notify (G_OBJECT (actor));
5321 }
5322
5323 static GObject *
5324 clutter_actor_constructor (GType gtype,
5325                            guint n_props,
5326                            GObjectConstructParam *props)
5327 {
5328   GObjectClass *gobject_class;
5329   ClutterActor *self;
5330   GObject *retval;
5331
5332   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5333   retval = gobject_class->constructor (gtype, n_props, props);
5334   self = CLUTTER_ACTOR (retval);
5335
5336   if (self->priv->layout_manager == NULL)
5337     {
5338       ClutterLayoutManager *default_layout;
5339
5340       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5341
5342       default_layout = clutter_fixed_layout_new ();
5343       clutter_actor_set_layout_manager (self, default_layout);
5344     }
5345
5346   return retval;
5347 }
5348
5349 static void
5350 clutter_actor_class_init (ClutterActorClass *klass)
5351 {
5352   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5353
5354   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5355   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5356   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5357   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5358
5359   object_class->constructor = clutter_actor_constructor;
5360   object_class->set_property = clutter_actor_set_property;
5361   object_class->get_property = clutter_actor_get_property;
5362   object_class->dispose = clutter_actor_dispose;
5363   object_class->finalize = clutter_actor_finalize;
5364
5365   klass->show = clutter_actor_real_show;
5366   klass->show_all = clutter_actor_show;
5367   klass->hide = clutter_actor_real_hide;
5368   klass->hide_all = clutter_actor_hide;
5369   klass->map = clutter_actor_real_map;
5370   klass->unmap = clutter_actor_real_unmap;
5371   klass->unrealize = clutter_actor_real_unrealize;
5372   klass->pick = clutter_actor_real_pick;
5373   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5374   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5375   klass->allocate = clutter_actor_real_allocate;
5376   klass->queue_redraw = clutter_actor_real_queue_redraw;
5377   klass->queue_relayout = clutter_actor_real_queue_relayout;
5378   klass->apply_transform = clutter_actor_real_apply_transform;
5379   klass->get_accessible = clutter_actor_real_get_accessible;
5380   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5381   klass->has_overlaps = clutter_actor_real_has_overlaps;
5382   klass->paint = clutter_actor_real_paint;
5383   klass->destroy = clutter_actor_real_destroy;
5384
5385   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5386
5387   /**
5388    * ClutterActor:x:
5389    *
5390    * X coordinate of the actor in pixels. If written, forces a fixed
5391    * position for the actor. If read, returns the fixed position if any,
5392    * otherwise the allocation if available, otherwise 0.
5393    *
5394    * The #ClutterActor:x property is animatable.
5395    */
5396   obj_props[PROP_X] =
5397     g_param_spec_float ("x",
5398                         P_("X coordinate"),
5399                         P_("X coordinate of the actor"),
5400                         -G_MAXFLOAT, G_MAXFLOAT,
5401                         0.0,
5402                         G_PARAM_READWRITE |
5403                         G_PARAM_STATIC_STRINGS |
5404                         CLUTTER_PARAM_ANIMATABLE);
5405
5406   /**
5407    * ClutterActor:y:
5408    *
5409    * Y coordinate of the actor in pixels. If written, forces a fixed
5410    * position for the actor.  If read, returns the fixed position if
5411    * any, otherwise the allocation if available, otherwise 0.
5412    *
5413    * The #ClutterActor:y property is animatable.
5414    */
5415   obj_props[PROP_Y] =
5416     g_param_spec_float ("y",
5417                         P_("Y coordinate"),
5418                         P_("Y coordinate of the actor"),
5419                         -G_MAXFLOAT, G_MAXFLOAT,
5420                         0.0,
5421                         G_PARAM_READWRITE |
5422                         G_PARAM_STATIC_STRINGS |
5423                         CLUTTER_PARAM_ANIMATABLE);
5424
5425   /**
5426    * ClutterActor:width:
5427    *
5428    * Width of the actor (in pixels). If written, forces the minimum and
5429    * natural size request of the actor to the given width. If read, returns
5430    * the allocated width if available, otherwise the width request.
5431    *
5432    * The #ClutterActor:width property is animatable.
5433    */
5434   obj_props[PROP_WIDTH] =
5435     g_param_spec_float ("width",
5436                         P_("Width"),
5437                         P_("Width of the actor"),
5438                         0.0, G_MAXFLOAT,
5439                         0.0,
5440                         G_PARAM_READWRITE |
5441                         G_PARAM_STATIC_STRINGS |
5442                         CLUTTER_PARAM_ANIMATABLE);
5443
5444   /**
5445    * ClutterActor:height:
5446    *
5447    * Height of the actor (in pixels).  If written, forces the minimum and
5448    * natural size request of the actor to the given height. If read, returns
5449    * the allocated height if available, otherwise the height request.
5450    *
5451    * The #ClutterActor:height property is animatable.
5452    */
5453   obj_props[PROP_HEIGHT] =
5454     g_param_spec_float ("height",
5455                         P_("Height"),
5456                         P_("Height of the actor"),
5457                         0.0, G_MAXFLOAT,
5458                         0.0,
5459                         G_PARAM_READWRITE |
5460                         G_PARAM_STATIC_STRINGS |
5461                         CLUTTER_PARAM_ANIMATABLE);
5462
5463   /**
5464    * ClutterActor:fixed-x:
5465    *
5466    * The fixed X position of the actor in pixels.
5467    *
5468    * Writing this property sets #ClutterActor:fixed-position-set
5469    * property as well, as a side effect
5470    *
5471    * Since: 0.8
5472    */
5473   obj_props[PROP_FIXED_X] =
5474     g_param_spec_float ("fixed-x",
5475                         P_("Fixed X"),
5476                         P_("Forced X position of the actor"),
5477                         -G_MAXFLOAT, G_MAXFLOAT,
5478                         0.0,
5479                         CLUTTER_PARAM_READWRITE);
5480
5481   /**
5482    * ClutterActor:fixed-y:
5483    *
5484    * The fixed Y position of the actor in pixels.
5485    *
5486    * Writing this property sets the #ClutterActor:fixed-position-set
5487    * property as well, as a side effect
5488    *
5489    * Since: 0.8
5490    */
5491   obj_props[PROP_FIXED_Y] =
5492     g_param_spec_float ("fixed-y",
5493                         P_("Fixed Y"),
5494                         P_("Forced Y position of the actor"),
5495                         -G_MAXFLOAT, G_MAXFLOAT,
5496                         0,
5497                         CLUTTER_PARAM_READWRITE);
5498
5499   /**
5500    * ClutterActor:fixed-position-set:
5501    *
5502    * This flag controls whether the #ClutterActor:fixed-x and
5503    * #ClutterActor:fixed-y properties are used
5504    *
5505    * Since: 0.8
5506    */
5507   obj_props[PROP_FIXED_POSITION_SET] =
5508     g_param_spec_boolean ("fixed-position-set",
5509                           P_("Fixed position set"),
5510                           P_("Whether to use fixed positioning for the actor"),
5511                           FALSE,
5512                           CLUTTER_PARAM_READWRITE);
5513
5514   /**
5515    * ClutterActor:min-width:
5516    *
5517    * A forced minimum width request for the actor, in pixels
5518    *
5519    * Writing this property sets the #ClutterActor:min-width-set property
5520    * as well, as a side effect.
5521    *
5522    *This property overrides the usual width request of the actor.
5523    *
5524    * Since: 0.8
5525    */
5526   obj_props[PROP_MIN_WIDTH] =
5527     g_param_spec_float ("min-width",
5528                         P_("Min Width"),
5529                         P_("Forced minimum width request for the actor"),
5530                         0.0, G_MAXFLOAT,
5531                         0.0,
5532                         CLUTTER_PARAM_READWRITE);
5533
5534   /**
5535    * ClutterActor:min-height:
5536    *
5537    * A forced minimum height request for the actor, in pixels
5538    *
5539    * Writing this property sets the #ClutterActor:min-height-set property
5540    * as well, as a side effect. This property overrides the usual height
5541    * request of the actor.
5542    *
5543    * Since: 0.8
5544    */
5545   obj_props[PROP_MIN_HEIGHT] =
5546     g_param_spec_float ("min-height",
5547                         P_("Min Height"),
5548                         P_("Forced minimum height request for the actor"),
5549                         0.0, G_MAXFLOAT,
5550                         0.0,
5551                         CLUTTER_PARAM_READWRITE);
5552
5553   /**
5554    * ClutterActor:natural-width:
5555    *
5556    * A forced natural width request for the actor, in pixels
5557    *
5558    * Writing this property sets the #ClutterActor:natural-width-set
5559    * property as well, as a side effect. This property overrides the
5560    * usual width request of the actor
5561    *
5562    * Since: 0.8
5563    */
5564   obj_props[PROP_NATURAL_WIDTH] =
5565     g_param_spec_float ("natural-width",
5566                         P_("Natural Width"),
5567                         P_("Forced natural width request for the actor"),
5568                         0.0, G_MAXFLOAT,
5569                         0.0,
5570                         CLUTTER_PARAM_READWRITE);
5571
5572   /**
5573    * ClutterActor:natural-height:
5574    *
5575    * A forced natural height request for the actor, in pixels
5576    *
5577    * Writing this property sets the #ClutterActor:natural-height-set
5578    * property as well, as a side effect. This property overrides the
5579    * usual height request of the actor
5580    *
5581    * Since: 0.8
5582    */
5583   obj_props[PROP_NATURAL_HEIGHT] =
5584     g_param_spec_float ("natural-height",
5585                         P_("Natural Height"),
5586                         P_("Forced natural height request for the actor"),
5587                         0.0, G_MAXFLOAT,
5588                         0.0,
5589                         CLUTTER_PARAM_READWRITE);
5590
5591   /**
5592    * ClutterActor:min-width-set:
5593    *
5594    * This flag controls whether the #ClutterActor:min-width property
5595    * is used
5596    *
5597    * Since: 0.8
5598    */
5599   obj_props[PROP_MIN_WIDTH_SET] =
5600     g_param_spec_boolean ("min-width-set",
5601                           P_("Minimum width set"),
5602                           P_("Whether to use the min-width property"),
5603                           FALSE,
5604                           CLUTTER_PARAM_READWRITE);
5605
5606   /**
5607    * ClutterActor:min-height-set:
5608    *
5609    * This flag controls whether the #ClutterActor:min-height property
5610    * is used
5611    *
5612    * Since: 0.8
5613    */
5614   obj_props[PROP_MIN_HEIGHT_SET] =
5615     g_param_spec_boolean ("min-height-set",
5616                           P_("Minimum height set"),
5617                           P_("Whether to use the min-height property"),
5618                           FALSE,
5619                           CLUTTER_PARAM_READWRITE);
5620
5621   /**
5622    * ClutterActor:natural-width-set:
5623    *
5624    * This flag controls whether the #ClutterActor:natural-width property
5625    * is used
5626    *
5627    * Since: 0.8
5628    */
5629   obj_props[PROP_NATURAL_WIDTH_SET] =
5630     g_param_spec_boolean ("natural-width-set",
5631                           P_("Natural width set"),
5632                           P_("Whether to use the natural-width property"),
5633                           FALSE,
5634                           CLUTTER_PARAM_READWRITE);
5635
5636   /**
5637    * ClutterActor:natural-height-set:
5638    *
5639    * This flag controls whether the #ClutterActor:natural-height property
5640    * is used
5641    *
5642    * Since: 0.8
5643    */
5644   obj_props[PROP_NATURAL_HEIGHT_SET] =
5645     g_param_spec_boolean ("natural-height-set",
5646                           P_("Natural height set"),
5647                           P_("Whether to use the natural-height property"),
5648                           FALSE,
5649                           CLUTTER_PARAM_READWRITE);
5650
5651   /**
5652    * ClutterActor:allocation:
5653    *
5654    * The allocation for the actor, in pixels
5655    *
5656    * This is property is read-only, but you might monitor it to know when an
5657    * actor moves or resizes
5658    *
5659    * Since: 0.8
5660    */
5661   obj_props[PROP_ALLOCATION] =
5662     g_param_spec_boxed ("allocation",
5663                         P_("Allocation"),
5664                         P_("The actor's allocation"),
5665                         CLUTTER_TYPE_ACTOR_BOX,
5666                         CLUTTER_PARAM_READABLE);
5667
5668   /**
5669    * ClutterActor:request-mode:
5670    *
5671    * Request mode for the #ClutterActor. The request mode determines the
5672    * type of geometry management used by the actor, either height for width
5673    * (the default) or width for height.
5674    *
5675    * For actors implementing height for width, the parent container should get
5676    * the preferred width first, and then the preferred height for that width.
5677    *
5678    * For actors implementing width for height, the parent container should get
5679    * the preferred height first, and then the preferred width for that height.
5680    *
5681    * For instance:
5682    *
5683    * |[
5684    *   ClutterRequestMode mode;
5685    *   gfloat natural_width, min_width;
5686    *   gfloat natural_height, min_height;
5687    *
5688    *   mode = clutter_actor_get_request_mode (child);
5689    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5690    *     {
5691    *       clutter_actor_get_preferred_width (child, -1,
5692    *                                          &amp;min_width,
5693    *                                          &amp;natural_width);
5694    *       clutter_actor_get_preferred_height (child, natural_width,
5695    *                                           &amp;min_height,
5696    *                                           &amp;natural_height);
5697    *     }
5698    *   else
5699    *     {
5700    *       clutter_actor_get_preferred_height (child, -1,
5701    *                                           &amp;min_height,
5702    *                                           &amp;natural_height);
5703    *       clutter_actor_get_preferred_width (child, natural_height,
5704    *                                          &amp;min_width,
5705    *                                          &amp;natural_width);
5706    *     }
5707    * ]|
5708    *
5709    * will retrieve the minimum and natural width and height depending on the
5710    * preferred request mode of the #ClutterActor "child".
5711    *
5712    * The clutter_actor_get_preferred_size() function will implement this
5713    * check for you.
5714    *
5715    * Since: 0.8
5716    */
5717   obj_props[PROP_REQUEST_MODE] =
5718     g_param_spec_enum ("request-mode",
5719                        P_("Request Mode"),
5720                        P_("The actor's request mode"),
5721                        CLUTTER_TYPE_REQUEST_MODE,
5722                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5723                        CLUTTER_PARAM_READWRITE);
5724
5725   /**
5726    * ClutterActor:depth:
5727    *
5728    * The position of the actor on the Z axis.
5729    *
5730    * The #ClutterActor:depth property is relative to the parent's
5731    * modelview matrix.
5732    *
5733    * The #ClutterActor:depth property is animatable.
5734    *
5735    * Since: 0.6
5736    */
5737   obj_props[PROP_DEPTH] =
5738     g_param_spec_float ("depth",
5739                         P_("Depth"),
5740                         P_("Position on the Z axis"),
5741                         -G_MAXFLOAT, G_MAXFLOAT,
5742                         0.0,
5743                         G_PARAM_READWRITE |
5744                         G_PARAM_STATIC_STRINGS |
5745                         CLUTTER_PARAM_ANIMATABLE);
5746
5747   /**
5748    * ClutterActor:opacity:
5749    *
5750    * Opacity of an actor, between 0 (fully transparent) and
5751    * 255 (fully opaque)
5752    *
5753    * The #ClutterActor:opacity property is animatable.
5754    */
5755   obj_props[PROP_OPACITY] =
5756     g_param_spec_uint ("opacity",
5757                        P_("Opacity"),
5758                        P_("Opacity of an actor"),
5759                        0, 255,
5760                        255,
5761                        G_PARAM_READWRITE |
5762                        G_PARAM_STATIC_STRINGS |
5763                        CLUTTER_PARAM_ANIMATABLE);
5764
5765   /**
5766    * ClutterActor:offscreen-redirect:
5767    *
5768    * Determines the conditions in which the actor will be redirected
5769    * to an offscreen framebuffer while being painted. For example this
5770    * can be used to cache an actor in a framebuffer or for improved
5771    * handling of transparent actors. See
5772    * clutter_actor_set_offscreen_redirect() for details.
5773    *
5774    * Since: 1.8
5775    */
5776   obj_props[PROP_OFFSCREEN_REDIRECT] =
5777     g_param_spec_flags ("offscreen-redirect",
5778                         P_("Offscreen redirect"),
5779                         P_("Flags controlling when to flatten the actor into a single image"),
5780                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5781                         0,
5782                         CLUTTER_PARAM_READWRITE);
5783
5784   /**
5785    * ClutterActor:visible:
5786    *
5787    * Whether the actor is set to be visible or not
5788    *
5789    * See also #ClutterActor:mapped
5790    */
5791   obj_props[PROP_VISIBLE] =
5792     g_param_spec_boolean ("visible",
5793                           P_("Visible"),
5794                           P_("Whether the actor is visible or not"),
5795                           FALSE,
5796                           CLUTTER_PARAM_READWRITE);
5797
5798   /**
5799    * ClutterActor:mapped:
5800    *
5801    * Whether the actor is mapped (will be painted when the stage
5802    * to which it belongs is mapped)
5803    *
5804    * Since: 1.0
5805    */
5806   obj_props[PROP_MAPPED] =
5807     g_param_spec_boolean ("mapped",
5808                           P_("Mapped"),
5809                           P_("Whether the actor will be painted"),
5810                           FALSE,
5811                           CLUTTER_PARAM_READABLE);
5812
5813   /**
5814    * ClutterActor:realized:
5815    *
5816    * Whether the actor has been realized
5817    *
5818    * Since: 1.0
5819    */
5820   obj_props[PROP_REALIZED] =
5821     g_param_spec_boolean ("realized",
5822                           P_("Realized"),
5823                           P_("Whether the actor has been realized"),
5824                           FALSE,
5825                           CLUTTER_PARAM_READABLE);
5826
5827   /**
5828    * ClutterActor:reactive:
5829    *
5830    * Whether the actor is reactive to events or not
5831    *
5832    * Only reactive actors will emit event-related signals
5833    *
5834    * Since: 0.6
5835    */
5836   obj_props[PROP_REACTIVE] =
5837     g_param_spec_boolean ("reactive",
5838                           P_("Reactive"),
5839                           P_("Whether the actor is reactive to events"),
5840                           FALSE,
5841                           CLUTTER_PARAM_READWRITE);
5842
5843   /**
5844    * ClutterActor:has-clip:
5845    *
5846    * Whether the actor has the #ClutterActor:clip property set or not
5847    */
5848   obj_props[PROP_HAS_CLIP] =
5849     g_param_spec_boolean ("has-clip",
5850                           P_("Has Clip"),
5851                           P_("Whether the actor has a clip set"),
5852                           FALSE,
5853                           CLUTTER_PARAM_READABLE);
5854
5855   /**
5856    * ClutterActor:clip:
5857    *
5858    * The clip region for the actor, in actor-relative coordinates
5859    *
5860    * Every part of the actor outside the clip region will not be
5861    * painted
5862    */
5863   obj_props[PROP_CLIP] =
5864     g_param_spec_boxed ("clip",
5865                         P_("Clip"),
5866                         P_("The clip region for the actor"),
5867                         CLUTTER_TYPE_GEOMETRY,
5868                         CLUTTER_PARAM_READWRITE);
5869
5870   /**
5871    * ClutterActor:name:
5872    *
5873    * The name of the actor
5874    *
5875    * Since: 0.2
5876    */
5877   obj_props[PROP_NAME] =
5878     g_param_spec_string ("name",
5879                          P_("Name"),
5880                          P_("Name of the actor"),
5881                          NULL,
5882                          CLUTTER_PARAM_READWRITE);
5883
5884   /**
5885    * ClutterActor:scale-x:
5886    *
5887    * The horizontal scale of the actor.
5888    *
5889    * The #ClutterActor:scale-x property is animatable.
5890    *
5891    * Since: 0.6
5892    */
5893   obj_props[PROP_SCALE_X] =
5894     g_param_spec_double ("scale-x",
5895                          P_("Scale X"),
5896                          P_("Scale factor on the X axis"),
5897                          0.0, G_MAXDOUBLE,
5898                          1.0,
5899                          G_PARAM_READWRITE |
5900                          G_PARAM_STATIC_STRINGS |
5901                          CLUTTER_PARAM_ANIMATABLE);
5902
5903   /**
5904    * ClutterActor:scale-y:
5905    *
5906    * The vertical scale of the actor.
5907    *
5908    * The #ClutterActor:scale-y property is animatable.
5909    *
5910    * Since: 0.6
5911    */
5912   obj_props[PROP_SCALE_Y] =
5913     g_param_spec_double ("scale-y",
5914                          P_("Scale Y"),
5915                          P_("Scale factor on the Y axis"),
5916                          0.0, G_MAXDOUBLE,
5917                          1.0,
5918                          G_PARAM_READWRITE |
5919                          G_PARAM_STATIC_STRINGS |
5920                          CLUTTER_PARAM_ANIMATABLE);
5921
5922   /**
5923    * ClutterActor:scale-center-x:
5924    *
5925    * The horizontal center point for scaling
5926    *
5927    * Since: 1.0
5928    */
5929   obj_props[PROP_SCALE_CENTER_X] =
5930     g_param_spec_float ("scale-center-x",
5931                         P_("Scale Center X"),
5932                         P_("Horizontal scale center"),
5933                         -G_MAXFLOAT, G_MAXFLOAT,
5934                         0.0,
5935                         CLUTTER_PARAM_READWRITE);
5936
5937   /**
5938    * ClutterActor:scale-center-y:
5939    *
5940    * The vertical center point for scaling
5941    *
5942    * Since: 1.0
5943    */
5944   obj_props[PROP_SCALE_CENTER_Y] =
5945     g_param_spec_float ("scale-center-y",
5946                         P_("Scale Center Y"),
5947                         P_("Vertical scale center"),
5948                         -G_MAXFLOAT, G_MAXFLOAT,
5949                         0.0,
5950                         CLUTTER_PARAM_READWRITE);
5951
5952   /**
5953    * ClutterActor:scale-gravity:
5954    *
5955    * The center point for scaling expressed as a #ClutterGravity
5956    *
5957    * Since: 1.0
5958    */
5959   obj_props[PROP_SCALE_GRAVITY] =
5960     g_param_spec_enum ("scale-gravity",
5961                        P_("Scale Gravity"),
5962                        P_("The center of scaling"),
5963                        CLUTTER_TYPE_GRAVITY,
5964                        CLUTTER_GRAVITY_NONE,
5965                        CLUTTER_PARAM_READWRITE);
5966
5967   /**
5968    * ClutterActor:rotation-angle-x:
5969    *
5970    * The rotation angle on the X axis.
5971    *
5972    * The #ClutterActor:rotation-angle-x property is animatable.
5973    *
5974    * Since: 0.6
5975    */
5976   obj_props[PROP_ROTATION_ANGLE_X] =
5977     g_param_spec_double ("rotation-angle-x",
5978                          P_("Rotation Angle X"),
5979                          P_("The rotation angle on the X axis"),
5980                          -G_MAXDOUBLE, G_MAXDOUBLE,
5981                          0.0,
5982                          G_PARAM_READWRITE |
5983                          G_PARAM_STATIC_STRINGS |
5984                          CLUTTER_PARAM_ANIMATABLE);
5985
5986   /**
5987    * ClutterActor:rotation-angle-y:
5988    *
5989    * The rotation angle on the Y axis
5990    *
5991    * The #ClutterActor:rotation-angle-y property is animatable.
5992    *
5993    * Since: 0.6
5994    */
5995   obj_props[PROP_ROTATION_ANGLE_Y] =
5996     g_param_spec_double ("rotation-angle-y",
5997                          P_("Rotation Angle Y"),
5998                          P_("The rotation angle on the Y axis"),
5999                          -G_MAXDOUBLE, G_MAXDOUBLE,
6000                          0.0,
6001                          G_PARAM_READWRITE |
6002                          G_PARAM_STATIC_STRINGS |
6003                          CLUTTER_PARAM_ANIMATABLE);
6004
6005   /**
6006    * ClutterActor:rotation-angle-z:
6007    *
6008    * The rotation angle on the Z axis
6009    *
6010    * The #ClutterActor:rotation-angle-z property is animatable.
6011    *
6012    * Since: 0.6
6013    */
6014   obj_props[PROP_ROTATION_ANGLE_Z] =
6015     g_param_spec_double ("rotation-angle-z",
6016                          P_("Rotation Angle Z"),
6017                          P_("The rotation angle on the Z axis"),
6018                          -G_MAXDOUBLE, G_MAXDOUBLE,
6019                          0.0,
6020                          G_PARAM_READWRITE |
6021                          G_PARAM_STATIC_STRINGS |
6022                          CLUTTER_PARAM_ANIMATABLE);
6023
6024   /**
6025    * ClutterActor:rotation-center-x:
6026    *
6027    * The rotation center on the X axis.
6028    *
6029    * Since: 0.6
6030    */
6031   obj_props[PROP_ROTATION_CENTER_X] =
6032     g_param_spec_boxed ("rotation-center-x",
6033                         P_("Rotation Center X"),
6034                         P_("The rotation center on the X axis"),
6035                         CLUTTER_TYPE_VERTEX,
6036                         CLUTTER_PARAM_READWRITE);
6037
6038   /**
6039    * ClutterActor:rotation-center-y:
6040    *
6041    * The rotation center on the Y axis.
6042    *
6043    * Since: 0.6
6044    */
6045   obj_props[PROP_ROTATION_CENTER_Y] =
6046     g_param_spec_boxed ("rotation-center-y",
6047                         P_("Rotation Center Y"),
6048                         P_("The rotation center on the Y axis"),
6049                         CLUTTER_TYPE_VERTEX,
6050                         CLUTTER_PARAM_READWRITE);
6051
6052   /**
6053    * ClutterActor:rotation-center-z:
6054    *
6055    * The rotation center on the Z axis.
6056    *
6057    * Since: 0.6
6058    */
6059   obj_props[PROP_ROTATION_CENTER_Z] =
6060     g_param_spec_boxed ("rotation-center-z",
6061                         P_("Rotation Center Z"),
6062                         P_("The rotation center on the Z axis"),
6063                         CLUTTER_TYPE_VERTEX,
6064                         CLUTTER_PARAM_READWRITE);
6065
6066   /**
6067    * ClutterActor:rotation-center-z-gravity:
6068    *
6069    * The rotation center on the Z axis expressed as a #ClutterGravity.
6070    *
6071    * Since: 1.0
6072    */
6073   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6074     g_param_spec_enum ("rotation-center-z-gravity",
6075                        P_("Rotation Center Z Gravity"),
6076                        P_("Center point for rotation around the Z axis"),
6077                        CLUTTER_TYPE_GRAVITY,
6078                        CLUTTER_GRAVITY_NONE,
6079                        CLUTTER_PARAM_READWRITE);
6080
6081   /**
6082    * ClutterActor:anchor-x:
6083    *
6084    * The X coordinate of an actor's anchor point, relative to
6085    * the actor coordinate space, in pixels
6086    *
6087    * Since: 0.8
6088    */
6089   obj_props[PROP_ANCHOR_X] =
6090     g_param_spec_float ("anchor-x",
6091                         P_("Anchor X"),
6092                         P_("X coordinate of the anchor point"),
6093                         -G_MAXFLOAT, G_MAXFLOAT,
6094                         0,
6095                         CLUTTER_PARAM_READWRITE);
6096
6097   /**
6098    * ClutterActor:anchor-y:
6099    *
6100    * The Y coordinate of an actor's anchor point, relative to
6101    * the actor coordinate space, in pixels
6102    *
6103    * Since: 0.8
6104    */
6105   obj_props[PROP_ANCHOR_Y] =
6106     g_param_spec_float ("anchor-y",
6107                         P_("Anchor Y"),
6108                         P_("Y coordinate of the anchor point"),
6109                         -G_MAXFLOAT, G_MAXFLOAT,
6110                         0,
6111                         CLUTTER_PARAM_READWRITE);
6112
6113   /**
6114    * ClutterActor:anchor-gravity:
6115    *
6116    * The anchor point expressed as a #ClutterGravity
6117    *
6118    * Since: 1.0
6119    */
6120   obj_props[PROP_ANCHOR_GRAVITY] =
6121     g_param_spec_enum ("anchor-gravity",
6122                        P_("Anchor Gravity"),
6123                        P_("The anchor point as a ClutterGravity"),
6124                        CLUTTER_TYPE_GRAVITY,
6125                        CLUTTER_GRAVITY_NONE,
6126                        CLUTTER_PARAM_READWRITE);
6127
6128   /**
6129    * ClutterActor:show-on-set-parent:
6130    *
6131    * If %TRUE, the actor is automatically shown when parented.
6132    *
6133    * Calling clutter_actor_hide() on an actor which has not been
6134    * parented will set this property to %FALSE as a side effect.
6135    *
6136    * Since: 0.8
6137    */
6138   obj_props[PROP_SHOW_ON_SET_PARENT] =
6139     g_param_spec_boolean ("show-on-set-parent",
6140                           P_("Show on set parent"),
6141                           P_("Whether the actor is shown when parented"),
6142                           TRUE,
6143                           CLUTTER_PARAM_READWRITE);
6144
6145   /**
6146    * ClutterActor:clip-to-allocation:
6147    *
6148    * Whether the clip region should track the allocated area
6149    * of the actor.
6150    *
6151    * This property is ignored if a clip area has been explicitly
6152    * set using clutter_actor_set_clip().
6153    *
6154    * Since: 1.0
6155    */
6156   obj_props[PROP_CLIP_TO_ALLOCATION] =
6157     g_param_spec_boolean ("clip-to-allocation",
6158                           P_("Clip to Allocation"),
6159                           P_("Sets the clip region to track the actor's allocation"),
6160                           FALSE,
6161                           CLUTTER_PARAM_READWRITE);
6162
6163   /**
6164    * ClutterActor:text-direction:
6165    *
6166    * The direction of the text inside a #ClutterActor.
6167    *
6168    * Since: 1.0
6169    */
6170   obj_props[PROP_TEXT_DIRECTION] =
6171     g_param_spec_enum ("text-direction",
6172                        P_("Text Direction"),
6173                        P_("Direction of the text"),
6174                        CLUTTER_TYPE_TEXT_DIRECTION,
6175                        CLUTTER_TEXT_DIRECTION_LTR,
6176                        CLUTTER_PARAM_READWRITE);
6177
6178   /**
6179    * ClutterActor:has-pointer:
6180    *
6181    * Whether the actor contains the pointer of a #ClutterInputDevice
6182    * or not.
6183    *
6184    * Since: 1.2
6185    */
6186   obj_props[PROP_HAS_POINTER] =
6187     g_param_spec_boolean ("has-pointer",
6188                           P_("Has Pointer"),
6189                           P_("Whether the actor contains the pointer of an input device"),
6190                           FALSE,
6191                           CLUTTER_PARAM_READABLE);
6192
6193   /**
6194    * ClutterActor:actions:
6195    *
6196    * Adds a #ClutterAction to the actor
6197    *
6198    * Since: 1.4
6199    */
6200   obj_props[PROP_ACTIONS] =
6201     g_param_spec_object ("actions",
6202                          P_("Actions"),
6203                          P_("Adds an action to the actor"),
6204                          CLUTTER_TYPE_ACTION,
6205                          CLUTTER_PARAM_WRITABLE);
6206
6207   /**
6208    * ClutterActor:constraints:
6209    *
6210    * Adds a #ClutterConstraint to the actor
6211    *
6212    * Since: 1.4
6213    */
6214   obj_props[PROP_CONSTRAINTS] =
6215     g_param_spec_object ("constraints",
6216                          P_("Constraints"),
6217                          P_("Adds a constraint to the actor"),
6218                          CLUTTER_TYPE_CONSTRAINT,
6219                          CLUTTER_PARAM_WRITABLE);
6220
6221   /**
6222    * ClutterActor:effect:
6223    *
6224    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6225    *
6226    * Since: 1.4
6227    */
6228   obj_props[PROP_EFFECT] =
6229     g_param_spec_object ("effect",
6230                          P_("Effect"),
6231                          P_("Add an effect to be applied on the actor"),
6232                          CLUTTER_TYPE_EFFECT,
6233                          CLUTTER_PARAM_WRITABLE);
6234
6235   /**
6236    * ClutterActor:layout-manager:
6237    *
6238    * A delegate object for controlling the layout of the children of
6239    * an actor.
6240    *
6241    * Since: 1.10
6242    */
6243   obj_props[PROP_LAYOUT_MANAGER] =
6244     g_param_spec_object ("layout-manager",
6245                          P_("Layout Manager"),
6246                          P_("The object controlling the layout of an actor's children"),
6247                          CLUTTER_TYPE_LAYOUT_MANAGER,
6248                          CLUTTER_PARAM_READWRITE);
6249
6250
6251   /**
6252    * ClutterActor:x-align:
6253    *
6254    * The alignment of an actor on the X axis, if the actor has been given
6255    * extra space for its allocation.
6256    *
6257    * Since: 1.10
6258    */
6259   obj_props[PROP_X_ALIGN] =
6260     g_param_spec_enum ("x-align",
6261                        P_("X Alignment"),
6262                        P_("The alignment of the actor on the X axis within its allocation"),
6263                        CLUTTER_TYPE_ACTOR_ALIGN,
6264                        CLUTTER_ACTOR_ALIGN_FILL,
6265                        CLUTTER_PARAM_READWRITE);
6266
6267   /**
6268    * ClutterActor:y-align:
6269    *
6270    * The alignment of an actor on the Y axis, if the actor has been given
6271    * extra space for its allocation.
6272    *
6273    * Since: 1.10
6274    */
6275   obj_props[PROP_Y_ALIGN] =
6276     g_param_spec_enum ("y-align",
6277                        P_("Y Alignment"),
6278                        P_("The alignment of the actor on the Y axis within its allocation"),
6279                        CLUTTER_TYPE_ACTOR_ALIGN,
6280                        CLUTTER_ACTOR_ALIGN_FILL,
6281                        CLUTTER_PARAM_READWRITE);
6282
6283   /**
6284    * ClutterActor:margin-top:
6285    *
6286    * The margin (in pixels) from the top of the actor.
6287    *
6288    * This property adds a margin to the actor's preferred size; the margin
6289    * will be automatically taken into account when allocating the actor.
6290    *
6291    * Since: 1.10
6292    */
6293   obj_props[PROP_MARGIN_TOP] =
6294     g_param_spec_float ("margin-top",
6295                         P_("Margin Top"),
6296                         P_("Extra space at the top"),
6297                         0.0, G_MAXFLOAT,
6298                         0.0,
6299                         CLUTTER_PARAM_READWRITE);
6300
6301   /**
6302    * ClutterActor:margin-bottom:
6303    *
6304    * The margin (in pixels) from the bottom of the actor.
6305    *
6306    * This property adds a margin to the actor's preferred size; the margin
6307    * will be automatically taken into account when allocating the actor.
6308    *
6309    * Since: 1.10
6310    */
6311   obj_props[PROP_MARGIN_BOTTOM] =
6312     g_param_spec_float ("margin-bottom",
6313                         P_("Margin Bottom"),
6314                         P_("Extra space at the bottom"),
6315                         0.0, G_MAXFLOAT,
6316                         0.0,
6317                         CLUTTER_PARAM_READWRITE);
6318
6319   /**
6320    * ClutterActor:margin-left:
6321    *
6322    * The margin (in pixels) from the left of the actor.
6323    *
6324    * This property adds a margin to the actor's preferred size; the margin
6325    * will be automatically taken into account when allocating the actor.
6326    *
6327    * Since: 1.10
6328    */
6329   obj_props[PROP_MARGIN_LEFT] =
6330     g_param_spec_float ("margin-left",
6331                         P_("Margin Left"),
6332                         P_("Extra space at the left"),
6333                         0.0, G_MAXFLOAT,
6334                         0.0,
6335                         CLUTTER_PARAM_READWRITE);
6336
6337   /**
6338    * ClutterActor:margin-right:
6339    *
6340    * The margin (in pixels) from the right of the actor.
6341    *
6342    * This property adds a margin to the actor's preferred size; the margin
6343    * will be automatically taken into account when allocating the actor.
6344    *
6345    * Since: 1.10
6346    */
6347   obj_props[PROP_MARGIN_RIGHT] =
6348     g_param_spec_float ("margin-right",
6349                         P_("Margin Right"),
6350                         P_("Extra space at the right"),
6351                         0.0, G_MAXFLOAT,
6352                         0.0,
6353                         CLUTTER_PARAM_READWRITE);
6354
6355   /**
6356    * ClutterActor:background-color-set:
6357    *
6358    * Whether the #ClutterActor:background-color property has been set.
6359    *
6360    * Since: 1.10
6361    */
6362   obj_props[PROP_BACKGROUND_COLOR_SET] =
6363     g_param_spec_boolean ("background-color-set",
6364                           P_("Background Color Set"),
6365                           P_("Whether the background color is set"),
6366                           FALSE,
6367                           CLUTTER_PARAM_READABLE);
6368
6369   /**
6370    * ClutterActor:background-color:
6371    *
6372    * Paints a solid fill of the actor's allocation using the specified
6373    * color.
6374    *
6375    * The #ClutterActor:background-color property is animatable.
6376    *
6377    * Since: 1.10
6378    */
6379   obj_props[PROP_BACKGROUND_COLOR] =
6380     clutter_param_spec_color ("background-color",
6381                               P_("Background color"),
6382                               P_("The actor's background color"),
6383                               CLUTTER_COLOR_Transparent,
6384                               G_PARAM_READWRITE |
6385                               G_PARAM_STATIC_STRINGS |
6386                               CLUTTER_PARAM_ANIMATABLE);
6387
6388   /**
6389    * ClutterActor:first-child:
6390    *
6391    * The actor's first child.
6392    *
6393    * Since: 1.10
6394    */
6395   obj_props[PROP_FIRST_CHILD] =
6396     g_param_spec_object ("first-child",
6397                          P_("First Child"),
6398                          P_("The actor's first child"),
6399                          CLUTTER_TYPE_ACTOR,
6400                          CLUTTER_PARAM_READABLE);
6401
6402   /**
6403    * ClutterActor:last-child:
6404    *
6405    * The actor's last child.
6406    *
6407    * Since: 1.10
6408    */
6409   obj_props[PROP_LAST_CHILD] =
6410     g_param_spec_object ("last-child",
6411                          P_("Last Child"),
6412                          P_("The actor's last child"),
6413                          CLUTTER_TYPE_ACTOR,
6414                          CLUTTER_PARAM_READABLE);
6415
6416   /**
6417    * ClutterActor:content:
6418    *
6419    * The #ClutterContent implementation that controls the content
6420    * of the actor.
6421    *
6422    * Since: 1.10
6423    */
6424   obj_props[PROP_CONTENT] =
6425     g_param_spec_object ("content",
6426                          P_("Content"),
6427                          P_("Delegate object for painting the actor's content"),
6428                          CLUTTER_TYPE_CONTENT,
6429                          CLUTTER_PARAM_READWRITE);
6430
6431   /**
6432    * ClutterActor:content-gravity:
6433    *
6434    * The alignment that should be honoured by the #ClutterContent
6435    * set with the #ClutterActor:content property.
6436    *
6437    * Changing the value of this property will change the bounding box of
6438    * the content; you can use the #ClutterActor:content-box property to
6439    * get the position and size of the content within the actor's
6440    * allocation.
6441    *
6442    * This property is meaningful only for #ClutterContent implementations
6443    * that have a preferred size, and if the preferred size is smaller than
6444    * the actor's allocation.
6445    *
6446    * Since: 1.10
6447    */
6448   obj_props[PROP_CONTENT_GRAVITY] =
6449     g_param_spec_enum ("content-gravity",
6450                        P_("Content Gravity"),
6451                        P_("Alignment of the actor's content"),
6452                        CLUTTER_TYPE_CONTENT_GRAVITY,
6453                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6454                        CLUTTER_PARAM_READWRITE);
6455
6456   /**
6457    * ClutterActor:content-box:
6458    *
6459    * The bounding box for the #ClutterContent used by the actor.
6460    *
6461    * The value of this property is controlled by the #ClutterActor:allocation
6462    * and #ClutterActor:content-gravity properties of #ClutterActor.
6463    *
6464    * The bounding box for the content is guaranteed to never exceed the
6465    * allocation's of the actor.
6466    *
6467    * Since: 1.10
6468    */
6469   obj_props[PROP_CONTENT_BOX] =
6470     g_param_spec_boxed ("content-box",
6471                         P_("Content Box"),
6472                         P_("The bounding box of the actor's content"),
6473                         CLUTTER_TYPE_ACTOR_BOX,
6474                         CLUTTER_PARAM_READABLE);
6475
6476   obj_props[PROP_MINIFICATION_FILTER] =
6477     g_param_spec_enum ("minification-filter",
6478                        P_("Minification Filter"),
6479                        P_("The filter used when reducing the size of the content"),
6480                        CLUTTER_TYPE_SCALING_FILTER,
6481                        CLUTTER_SCALING_FILTER_LINEAR,
6482                        CLUTTER_PARAM_READWRITE);
6483
6484   obj_props[PROP_MAGNIFICATION_FILTER] =
6485     g_param_spec_enum ("magnification-filter",
6486                        P_("Magnification Filter"),
6487                        P_("The filter used when increasing the size of the content"),
6488                        CLUTTER_TYPE_SCALING_FILTER,
6489                        CLUTTER_SCALING_FILTER_LINEAR,
6490                        CLUTTER_PARAM_READWRITE);
6491
6492   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6493
6494   /**
6495    * ClutterActor::destroy:
6496    * @actor: the #ClutterActor which emitted the signal
6497    *
6498    * The ::destroy signal notifies that all references held on the
6499    * actor which emitted it should be released.
6500    *
6501    * The ::destroy signal should be used by all holders of a reference
6502    * on @actor.
6503    *
6504    * This signal might result in the finalization of the #ClutterActor
6505    * if all references are released.
6506    *
6507    * Composite actors and actors implementing the #ClutterContainer
6508    * interface should override the default implementation of the
6509    * class handler of this signal and call clutter_actor_destroy() on
6510    * their children. When overriding the default class handler, it is
6511    * required to chain up to the parent's implementation.
6512    *
6513    * Since: 0.2
6514    */
6515   actor_signals[DESTROY] =
6516     g_signal_new (I_("destroy"),
6517                   G_TYPE_FROM_CLASS (object_class),
6518                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6519                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6520                   NULL, NULL,
6521                   _clutter_marshal_VOID__VOID,
6522                   G_TYPE_NONE, 0);
6523   /**
6524    * ClutterActor::show:
6525    * @actor: the object which received the signal
6526    *
6527    * The ::show signal is emitted when an actor is visible and
6528    * rendered on the stage.
6529    *
6530    * Since: 0.2
6531    */
6532   actor_signals[SHOW] =
6533     g_signal_new (I_("show"),
6534                   G_TYPE_FROM_CLASS (object_class),
6535                   G_SIGNAL_RUN_FIRST,
6536                   G_STRUCT_OFFSET (ClutterActorClass, show),
6537                   NULL, NULL,
6538                   _clutter_marshal_VOID__VOID,
6539                   G_TYPE_NONE, 0);
6540   /**
6541    * ClutterActor::hide:
6542    * @actor: the object which received the signal
6543    *
6544    * The ::hide signal is emitted when an actor is no longer rendered
6545    * on the stage.
6546    *
6547    * Since: 0.2
6548    */
6549   actor_signals[HIDE] =
6550     g_signal_new (I_("hide"),
6551                   G_TYPE_FROM_CLASS (object_class),
6552                   G_SIGNAL_RUN_FIRST,
6553                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6554                   NULL, NULL,
6555                   _clutter_marshal_VOID__VOID,
6556                   G_TYPE_NONE, 0);
6557   /**
6558    * ClutterActor::parent-set:
6559    * @actor: the object which received the signal
6560    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6561    *
6562    * This signal is emitted when the parent of the actor changes.
6563    *
6564    * Since: 0.2
6565    */
6566   actor_signals[PARENT_SET] =
6567     g_signal_new (I_("parent-set"),
6568                   G_TYPE_FROM_CLASS (object_class),
6569                   G_SIGNAL_RUN_LAST,
6570                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6571                   NULL, NULL,
6572                   _clutter_marshal_VOID__OBJECT,
6573                   G_TYPE_NONE, 1,
6574                   CLUTTER_TYPE_ACTOR);
6575
6576   /**
6577    * ClutterActor::queue-redraw:
6578    * @actor: the actor we're bubbling the redraw request through
6579    * @origin: the actor which initiated the redraw request
6580    *
6581    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6582    * is called on @origin.
6583    *
6584    * The default implementation for #ClutterActor chains up to the
6585    * parent actor and queues a redraw on the parent, thus "bubbling"
6586    * the redraw queue up through the actor graph. The default
6587    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6588    * in a main loop idle handler.
6589    *
6590    * Note that the @origin actor may be the stage, or a container; it
6591    * does not have to be a leaf node in the actor graph.
6592    *
6593    * Toolkits embedding a #ClutterStage which require a redraw and
6594    * relayout cycle can stop the emission of this signal using the
6595    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6596    * themselves, like:
6597    *
6598    * |[
6599    *   static void
6600    *   on_redraw_complete (gpointer data)
6601    *   {
6602    *     ClutterStage *stage = data;
6603    *
6604    *     /&ast; execute the Clutter drawing pipeline &ast;/
6605    *     clutter_stage_ensure_redraw (stage);
6606    *   }
6607    *
6608    *   static void
6609    *   on_stage_queue_redraw (ClutterStage *stage)
6610    *   {
6611    *     /&ast; this prevents the default handler to run &ast;/
6612    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6613    *
6614    *     /&ast; queue a redraw with the host toolkit and call
6615    *      &ast; a function when the redraw has been completed
6616    *      &ast;/
6617    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6618    *   }
6619    * ]|
6620    *
6621    * <note><para>This signal is emitted before the Clutter paint
6622    * pipeline is executed. If you want to know when the pipeline has
6623    * been completed you should connect to the ::paint signal on the
6624    * Stage with g_signal_connect_after().</para></note>
6625    *
6626    * Since: 1.0
6627    */
6628   actor_signals[QUEUE_REDRAW] =
6629     g_signal_new (I_("queue-redraw"),
6630                   G_TYPE_FROM_CLASS (object_class),
6631                   G_SIGNAL_RUN_LAST |
6632                   G_SIGNAL_NO_HOOKS,
6633                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6634                   NULL, NULL,
6635                   _clutter_marshal_VOID__OBJECT,
6636                   G_TYPE_NONE, 1,
6637                   CLUTTER_TYPE_ACTOR);
6638
6639   /**
6640    * ClutterActor::queue-relayout
6641    * @actor: the actor being queued for relayout
6642    *
6643    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6644    * is called on an actor.
6645    *
6646    * The default implementation for #ClutterActor chains up to the
6647    * parent actor and queues a relayout on the parent, thus "bubbling"
6648    * the relayout queue up through the actor graph.
6649    *
6650    * The main purpose of this signal is to allow relayout to be propagated
6651    * properly in the procense of #ClutterClone actors. Applications will
6652    * not normally need to connect to this signal.
6653    *
6654    * Since: 1.2
6655    */
6656   actor_signals[QUEUE_RELAYOUT] =
6657     g_signal_new (I_("queue-relayout"),
6658                   G_TYPE_FROM_CLASS (object_class),
6659                   G_SIGNAL_RUN_LAST |
6660                   G_SIGNAL_NO_HOOKS,
6661                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6662                   NULL, NULL,
6663                   _clutter_marshal_VOID__VOID,
6664                   G_TYPE_NONE, 0);
6665
6666   /**
6667    * ClutterActor::event:
6668    * @actor: the actor which received the event
6669    * @event: a #ClutterEvent
6670    *
6671    * The ::event signal is emitted each time an event is received
6672    * by the @actor. This signal will be emitted on every actor,
6673    * following the hierarchy chain, until it reaches the top-level
6674    * container (the #ClutterStage).
6675    *
6676    * Return value: %TRUE if the event has been handled by the actor,
6677    *   or %FALSE to continue the emission.
6678    *
6679    * Since: 0.6
6680    */
6681   actor_signals[EVENT] =
6682     g_signal_new (I_("event"),
6683                   G_TYPE_FROM_CLASS (object_class),
6684                   G_SIGNAL_RUN_LAST,
6685                   G_STRUCT_OFFSET (ClutterActorClass, event),
6686                   _clutter_boolean_handled_accumulator, NULL,
6687                   _clutter_marshal_BOOLEAN__BOXED,
6688                   G_TYPE_BOOLEAN, 1,
6689                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6690   /**
6691    * ClutterActor::button-press-event:
6692    * @actor: the actor which received the event
6693    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6694    *
6695    * The ::button-press-event signal is emitted each time a mouse button
6696    * is pressed on @actor.
6697    *
6698    * Return value: %TRUE if the event has been handled by the actor,
6699    *   or %FALSE to continue the emission.
6700    *
6701    * Since: 0.6
6702    */
6703   actor_signals[BUTTON_PRESS_EVENT] =
6704     g_signal_new (I_("button-press-event"),
6705                   G_TYPE_FROM_CLASS (object_class),
6706                   G_SIGNAL_RUN_LAST,
6707                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6708                   _clutter_boolean_handled_accumulator, NULL,
6709                   _clutter_marshal_BOOLEAN__BOXED,
6710                   G_TYPE_BOOLEAN, 1,
6711                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6712   /**
6713    * ClutterActor::button-release-event:
6714    * @actor: the actor which received the event
6715    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6716    *
6717    * The ::button-release-event signal is emitted each time a mouse button
6718    * is released on @actor.
6719    *
6720    * Return value: %TRUE if the event has been handled by the actor,
6721    *   or %FALSE to continue the emission.
6722    *
6723    * Since: 0.6
6724    */
6725   actor_signals[BUTTON_RELEASE_EVENT] =
6726     g_signal_new (I_("button-release-event"),
6727                   G_TYPE_FROM_CLASS (object_class),
6728                   G_SIGNAL_RUN_LAST,
6729                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6730                   _clutter_boolean_handled_accumulator, NULL,
6731                   _clutter_marshal_BOOLEAN__BOXED,
6732                   G_TYPE_BOOLEAN, 1,
6733                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6734   /**
6735    * ClutterActor::scroll-event:
6736    * @actor: the actor which received the event
6737    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6738    *
6739    * The ::scroll-event signal is emitted each time the mouse is
6740    * scrolled on @actor
6741    *
6742    * Return value: %TRUE if the event has been handled by the actor,
6743    *   or %FALSE to continue the emission.
6744    *
6745    * Since: 0.6
6746    */
6747   actor_signals[SCROLL_EVENT] =
6748     g_signal_new (I_("scroll-event"),
6749                   G_TYPE_FROM_CLASS (object_class),
6750                   G_SIGNAL_RUN_LAST,
6751                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6752                   _clutter_boolean_handled_accumulator, NULL,
6753                   _clutter_marshal_BOOLEAN__BOXED,
6754                   G_TYPE_BOOLEAN, 1,
6755                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6756   /**
6757    * ClutterActor::key-press-event:
6758    * @actor: the actor which received the event
6759    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6760    *
6761    * The ::key-press-event signal is emitted each time a keyboard button
6762    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6763    *
6764    * Return value: %TRUE if the event has been handled by the actor,
6765    *   or %FALSE to continue the emission.
6766    *
6767    * Since: 0.6
6768    */
6769   actor_signals[KEY_PRESS_EVENT] =
6770     g_signal_new (I_("key-press-event"),
6771                   G_TYPE_FROM_CLASS (object_class),
6772                   G_SIGNAL_RUN_LAST,
6773                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6774                   _clutter_boolean_handled_accumulator, NULL,
6775                   _clutter_marshal_BOOLEAN__BOXED,
6776                   G_TYPE_BOOLEAN, 1,
6777                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6778   /**
6779    * ClutterActor::key-release-event:
6780    * @actor: the actor which received the event
6781    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6782    *
6783    * The ::key-release-event signal is emitted each time a keyboard button
6784    * is released while @actor has key focus (see
6785    * clutter_stage_set_key_focus()).
6786    *
6787    * Return value: %TRUE if the event has been handled by the actor,
6788    *   or %FALSE to continue the emission.
6789    *
6790    * Since: 0.6
6791    */
6792   actor_signals[KEY_RELEASE_EVENT] =
6793     g_signal_new (I_("key-release-event"),
6794                   G_TYPE_FROM_CLASS (object_class),
6795                   G_SIGNAL_RUN_LAST,
6796                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6797                   _clutter_boolean_handled_accumulator, NULL,
6798                   _clutter_marshal_BOOLEAN__BOXED,
6799                   G_TYPE_BOOLEAN, 1,
6800                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6801   /**
6802    * ClutterActor::motion-event:
6803    * @actor: the actor which received the event
6804    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6805    *
6806    * The ::motion-event signal is emitted each time the mouse pointer is
6807    * moved over @actor.
6808    *
6809    * Return value: %TRUE if the event has been handled by the actor,
6810    *   or %FALSE to continue the emission.
6811    *
6812    * Since: 0.6
6813    */
6814   actor_signals[MOTION_EVENT] =
6815     g_signal_new (I_("motion-event"),
6816                   G_TYPE_FROM_CLASS (object_class),
6817                   G_SIGNAL_RUN_LAST,
6818                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6819                   _clutter_boolean_handled_accumulator, NULL,
6820                   _clutter_marshal_BOOLEAN__BOXED,
6821                   G_TYPE_BOOLEAN, 1,
6822                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6823
6824   /**
6825    * ClutterActor::key-focus-in:
6826    * @actor: the actor which now has key focus
6827    *
6828    * The ::key-focus-in signal is emitted when @actor receives key focus.
6829    *
6830    * Since: 0.6
6831    */
6832   actor_signals[KEY_FOCUS_IN] =
6833     g_signal_new (I_("key-focus-in"),
6834                   G_TYPE_FROM_CLASS (object_class),
6835                   G_SIGNAL_RUN_LAST,
6836                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6837                   NULL, NULL,
6838                   _clutter_marshal_VOID__VOID,
6839                   G_TYPE_NONE, 0);
6840
6841   /**
6842    * ClutterActor::key-focus-out:
6843    * @actor: the actor which now has key focus
6844    *
6845    * The ::key-focus-out signal is emitted when @actor loses key focus.
6846    *
6847    * Since: 0.6
6848    */
6849   actor_signals[KEY_FOCUS_OUT] =
6850     g_signal_new (I_("key-focus-out"),
6851                   G_TYPE_FROM_CLASS (object_class),
6852                   G_SIGNAL_RUN_LAST,
6853                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6854                   NULL, NULL,
6855                   _clutter_marshal_VOID__VOID,
6856                   G_TYPE_NONE, 0);
6857
6858   /**
6859    * ClutterActor::enter-event:
6860    * @actor: the actor which the pointer has entered.
6861    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6862    *
6863    * The ::enter-event signal is emitted when the pointer enters the @actor
6864    *
6865    * Return value: %TRUE if the event has been handled by the actor,
6866    *   or %FALSE to continue the emission.
6867    *
6868    * Since: 0.6
6869    */
6870   actor_signals[ENTER_EVENT] =
6871     g_signal_new (I_("enter-event"),
6872                   G_TYPE_FROM_CLASS (object_class),
6873                   G_SIGNAL_RUN_LAST,
6874                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6875                   _clutter_boolean_handled_accumulator, NULL,
6876                   _clutter_marshal_BOOLEAN__BOXED,
6877                   G_TYPE_BOOLEAN, 1,
6878                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6879
6880   /**
6881    * ClutterActor::leave-event:
6882    * @actor: the actor which the pointer has left
6883    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6884    *
6885    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6886    *
6887    * Return value: %TRUE if the event has been handled by the actor,
6888    *   or %FALSE to continue the emission.
6889    *
6890    * Since: 0.6
6891    */
6892   actor_signals[LEAVE_EVENT] =
6893     g_signal_new (I_("leave-event"),
6894                   G_TYPE_FROM_CLASS (object_class),
6895                   G_SIGNAL_RUN_LAST,
6896                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6897                   _clutter_boolean_handled_accumulator, NULL,
6898                   _clutter_marshal_BOOLEAN__BOXED,
6899                   G_TYPE_BOOLEAN, 1,
6900                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6901
6902   /**
6903    * ClutterActor::captured-event:
6904    * @actor: the actor which received the signal
6905    * @event: a #ClutterEvent
6906    *
6907    * The ::captured-event signal is emitted when an event is captured
6908    * by Clutter. This signal will be emitted starting from the top-level
6909    * container (the #ClutterStage) to the actor which received the event
6910    * going down the hierarchy. This signal can be used to intercept every
6911    * event before the specialized events (like
6912    * ClutterActor::button-press-event or ::key-released-event) are
6913    * emitted.
6914    *
6915    * Return value: %TRUE if the event has been handled by the actor,
6916    *   or %FALSE to continue the emission.
6917    *
6918    * Since: 0.6
6919    */
6920   actor_signals[CAPTURED_EVENT] =
6921     g_signal_new (I_("captured-event"),
6922                   G_TYPE_FROM_CLASS (object_class),
6923                   G_SIGNAL_RUN_LAST,
6924                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6925                   _clutter_boolean_handled_accumulator, NULL,
6926                   _clutter_marshal_BOOLEAN__BOXED,
6927                   G_TYPE_BOOLEAN, 1,
6928                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6929
6930   /**
6931    * ClutterActor::paint:
6932    * @actor: the #ClutterActor that received the signal
6933    *
6934    * The ::paint signal is emitted each time an actor is being painted.
6935    *
6936    * Subclasses of #ClutterActor should override the class signal handler
6937    * and paint themselves in that function.
6938    *
6939    * It is possible to connect a handler to the ::paint signal in order
6940    * to set up some custom aspect of a paint.
6941    *
6942    * Since: 0.8
6943    */
6944   actor_signals[PAINT] =
6945     g_signal_new (I_("paint"),
6946                   G_TYPE_FROM_CLASS (object_class),
6947                   G_SIGNAL_RUN_LAST |
6948                   G_SIGNAL_NO_HOOKS,
6949                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6950                   NULL, NULL,
6951                   _clutter_marshal_VOID__VOID,
6952                   G_TYPE_NONE, 0);
6953   /**
6954    * ClutterActor::realize:
6955    * @actor: the #ClutterActor that received the signal
6956    *
6957    * The ::realize signal is emitted each time an actor is being
6958    * realized.
6959    *
6960    * Since: 0.8
6961    */
6962   actor_signals[REALIZE] =
6963     g_signal_new (I_("realize"),
6964                   G_TYPE_FROM_CLASS (object_class),
6965                   G_SIGNAL_RUN_LAST,
6966                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6967                   NULL, NULL,
6968                   _clutter_marshal_VOID__VOID,
6969                   G_TYPE_NONE, 0);
6970   /**
6971    * ClutterActor::unrealize:
6972    * @actor: the #ClutterActor that received the signal
6973    *
6974    * The ::unrealize signal is emitted each time an actor is being
6975    * unrealized.
6976    *
6977    * Since: 0.8
6978    */
6979   actor_signals[UNREALIZE] =
6980     g_signal_new (I_("unrealize"),
6981                   G_TYPE_FROM_CLASS (object_class),
6982                   G_SIGNAL_RUN_LAST,
6983                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6984                   NULL, NULL,
6985                   _clutter_marshal_VOID__VOID,
6986                   G_TYPE_NONE, 0);
6987
6988   /**
6989    * ClutterActor::pick:
6990    * @actor: the #ClutterActor that received the signal
6991    * @color: the #ClutterColor to be used when picking
6992    *
6993    * The ::pick signal is emitted each time an actor is being painted
6994    * in "pick mode". The pick mode is used to identify the actor during
6995    * the event handling phase, or by clutter_stage_get_actor_at_pos().
6996    * The actor should paint its shape using the passed @pick_color.
6997    *
6998    * Subclasses of #ClutterActor should override the class signal handler
6999    * and paint themselves in that function.
7000    *
7001    * It is possible to connect a handler to the ::pick signal in order
7002    * to set up some custom aspect of a paint in pick mode.
7003    *
7004    * Since: 1.0
7005    */
7006   actor_signals[PICK] =
7007     g_signal_new (I_("pick"),
7008                   G_TYPE_FROM_CLASS (object_class),
7009                   G_SIGNAL_RUN_LAST,
7010                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7011                   NULL, NULL,
7012                   _clutter_marshal_VOID__BOXED,
7013                   G_TYPE_NONE, 1,
7014                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7015
7016   /**
7017    * ClutterActor::allocation-changed:
7018    * @actor: the #ClutterActor that emitted the signal
7019    * @box: a #ClutterActorBox with the new allocation
7020    * @flags: #ClutterAllocationFlags for the allocation
7021    *
7022    * The ::allocation-changed signal is emitted when the
7023    * #ClutterActor:allocation property changes. Usually, application
7024    * code should just use the notifications for the :allocation property
7025    * but if you want to track the allocation flags as well, for instance
7026    * to know whether the absolute origin of @actor changed, then you might
7027    * want use this signal instead.
7028    *
7029    * Since: 1.0
7030    */
7031   actor_signals[ALLOCATION_CHANGED] =
7032     g_signal_new (I_("allocation-changed"),
7033                   G_TYPE_FROM_CLASS (object_class),
7034                   G_SIGNAL_RUN_LAST,
7035                   0,
7036                   NULL, NULL,
7037                   _clutter_marshal_VOID__BOXED_FLAGS,
7038                   G_TYPE_NONE, 2,
7039                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7040                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7041
7042   /**
7043    * ClutterActor::transitions-completed:
7044    * @actor: a #ClutterActor
7045    *
7046    * The ::transitions-completed signal is emitted once all transitions
7047    * involving @actor are complete.
7048    *
7049    * Since: 1.10
7050    */
7051   actor_signals[TRANSITIONS_COMPLETED] =
7052     g_signal_new (I_("transitions-completed"),
7053                   G_TYPE_FROM_CLASS (object_class),
7054                   G_SIGNAL_RUN_LAST,
7055                   0,
7056                   NULL, NULL,
7057                   _clutter_marshal_VOID__VOID,
7058                   G_TYPE_NONE, 0);
7059 }
7060
7061 static void
7062 clutter_actor_init (ClutterActor *self)
7063 {
7064   ClutterActorPrivate *priv;
7065
7066   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7067
7068   priv->id = _clutter_context_acquire_id (self);
7069   priv->pick_id = -1;
7070
7071   priv->opacity = 0xff;
7072   priv->show_on_set_parent = TRUE;
7073
7074   priv->needs_width_request = TRUE;
7075   priv->needs_height_request = TRUE;
7076   priv->needs_allocation = TRUE;
7077
7078   priv->cached_width_age = 1;
7079   priv->cached_height_age = 1;
7080
7081   priv->opacity_override = -1;
7082   priv->enable_model_view_transform = TRUE;
7083
7084   /* Initialize an empty paint volume to start with */
7085   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7086   priv->last_paint_volume_valid = TRUE;
7087
7088   priv->transform_valid = FALSE;
7089
7090   /* the default is to stretch the content, to match the
7091    * current behaviour of basically all actors. also, it's
7092    * the easiest thing to compute.
7093    */
7094   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7095   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7096   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7097 }
7098
7099 /**
7100  * clutter_actor_new:
7101  *
7102  * Creates a new #ClutterActor.
7103  *
7104  * A newly created actor has a floating reference, which will be sunk
7105  * when it is added to another actor.
7106  *
7107  * Return value: (transfer full): the newly created #ClutterActor
7108  *
7109  * Since: 1.10
7110  */
7111 ClutterActor *
7112 clutter_actor_new (void)
7113 {
7114   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7115 }
7116
7117 /**
7118  * clutter_actor_destroy:
7119  * @self: a #ClutterActor
7120  *
7121  * Destroys an actor.  When an actor is destroyed, it will break any
7122  * references it holds to other objects.  If the actor is inside a
7123  * container, the actor will be removed.
7124  *
7125  * When you destroy a container, its children will be destroyed as well.
7126  *
7127  * Note: you cannot destroy the #ClutterStage returned by
7128  * clutter_stage_get_default().
7129  */
7130 void
7131 clutter_actor_destroy (ClutterActor *self)
7132 {
7133   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7134
7135   g_object_ref (self);
7136
7137   /* avoid recursion while destroying */
7138   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7139     {
7140       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7141
7142       g_object_run_dispose (G_OBJECT (self));
7143
7144       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7145     }
7146
7147   g_object_unref (self);
7148 }
7149
7150 void
7151 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7152                                     ClutterPaintVolume *clip)
7153 {
7154   ClutterActorPrivate *priv = self->priv;
7155   ClutterPaintVolume *pv;
7156   gboolean clipped;
7157
7158   /* Remove queue entry early in the process, otherwise a new
7159      queue_redraw() during signal handling could put back this
7160      object in the stage redraw list (but the entry is freed as
7161      soon as we return from this function, causing a segfault
7162      later)
7163   */
7164   priv->queue_redraw_entry = NULL;
7165
7166   /* If we've been explicitly passed a clip volume then there's
7167    * nothing more to calculate, but otherwise the only thing we know
7168    * is that the change is constrained to the given actor.
7169    *
7170    * The idea is that if we know the paint volume for where the actor
7171    * was last drawn (in eye coordinates) and we also have the paint
7172    * volume for where it will be drawn next (in actor coordinates)
7173    * then if we queue a redraw for both these volumes that will cover
7174    * everything that needs to be redrawn to clear the old view and
7175    * show the latest view of the actor.
7176    *
7177    * Don't clip this redraw if we don't know what position we had for
7178    * the previous redraw since we don't know where to set the clip so
7179    * it will clear the actor as it is currently.
7180    */
7181   if (clip)
7182     {
7183       _clutter_actor_set_queue_redraw_clip (self, clip);
7184       clipped = TRUE;
7185     }
7186   else if (G_LIKELY (priv->last_paint_volume_valid))
7187     {
7188       pv = _clutter_actor_get_paint_volume_mutable (self);
7189       if (pv)
7190         {
7191           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7192
7193           /* make sure we redraw the actors old position... */
7194           _clutter_actor_set_queue_redraw_clip (stage,
7195                                                 &priv->last_paint_volume);
7196           _clutter_actor_signal_queue_redraw (stage, stage);
7197           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7198
7199           /* XXX: Ideally the redraw signal would take a clip volume
7200            * argument, but that would be an ABI break. Until we can
7201            * break the ABI we pass the argument out-of-band
7202            */
7203
7204           /* setup the clip for the actors new position... */
7205           _clutter_actor_set_queue_redraw_clip (self, pv);
7206           clipped = TRUE;
7207         }
7208       else
7209         clipped = FALSE;
7210     }
7211   else
7212     clipped = FALSE;
7213
7214   _clutter_actor_signal_queue_redraw (self, self);
7215
7216   /* Just in case anyone is manually firing redraw signals without
7217    * using the public queue_redraw() API we are careful to ensure that
7218    * our out-of-band clip member is cleared before returning...
7219    *
7220    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7221    */
7222   if (G_LIKELY (clipped))
7223     _clutter_actor_set_queue_redraw_clip (self, NULL);
7224 }
7225
7226 static void
7227 _clutter_actor_get_allocation_clip (ClutterActor *self,
7228                                     ClutterActorBox *clip)
7229 {
7230   ClutterActorBox allocation;
7231
7232   /* XXX: we don't care if we get an out of date allocation here
7233    * because clutter_actor_queue_redraw_with_clip knows to ignore
7234    * the clip if the actor's allocation is invalid.
7235    *
7236    * This is noted because clutter_actor_get_allocation_box does some
7237    * unnecessary work to support buggy code with a comment suggesting
7238    * that it could be changed later which would be good for this use
7239    * case!
7240    */
7241   clutter_actor_get_allocation_box (self, &allocation);
7242
7243   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7244    * actor's own coordinate space but the allocation is in parent
7245    * coordinates */
7246   clip->x1 = 0;
7247   clip->y1 = 0;
7248   clip->x2 = allocation.x2 - allocation.x1;
7249   clip->y2 = allocation.y2 - allocation.y1;
7250 }
7251
7252 void
7253 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7254                                   ClutterRedrawFlags  flags,
7255                                   ClutterPaintVolume *volume,
7256                                   ClutterEffect      *effect)
7257 {
7258   ClutterActorPrivate *priv = self->priv;
7259   ClutterPaintVolume allocation_pv;
7260   ClutterPaintVolume *pv;
7261   gboolean should_free_pv;
7262   ClutterActor *stage;
7263
7264   /* Here's an outline of the actor queue redraw mechanism:
7265    *
7266    * The process starts in one of the following two functions which
7267    * are wrappers for this function:
7268    * clutter_actor_queue_redraw
7269    * _clutter_actor_queue_redraw_with_clip
7270    *
7271    * additionally, an effect can queue a redraw by wrapping this
7272    * function in clutter_effect_queue_rerun
7273    *
7274    * This functions queues an entry in a list associated with the
7275    * stage which is a list of actors that queued a redraw while
7276    * updating the timelines, performing layouting and processing other
7277    * mainloop sources before the next paint starts.
7278    *
7279    * We aim to minimize the processing done at this point because
7280    * there is a good chance other events will happen while updating
7281    * the scenegraph that would invalidate any expensive work we might
7282    * otherwise try to do here. For example we don't try and resolve
7283    * the screen space bounding box of an actor at this stage so as to
7284    * minimize how much of the screen redraw because it's possible
7285    * something else will happen which will force a full redraw anyway.
7286    *
7287    * When all updates are complete and we come to paint the stage then
7288    * we iterate this list and actually emit the "queue-redraw" signals
7289    * for each of the listed actors which will bubble up to the stage
7290    * for each actor and at that point we will transform the actors
7291    * paint volume into screen coordinates to determine the clip region
7292    * for what needs to be redrawn in the next paint.
7293    *
7294    * Besides minimizing redundant work another reason for this
7295    * deferred design is that it's more likely we will be able to
7296    * determine the paint volume of an actor once we've finished
7297    * updating the scenegraph because its allocation should be up to
7298    * date. NB: If we can't determine an actors paint volume then we
7299    * can't automatically queue a clipped redraw which can make a big
7300    * difference to performance.
7301    *
7302    * So the control flow goes like this:
7303    * One of clutter_actor_queue_redraw,
7304    *        _clutter_actor_queue_redraw_with_clip
7305    *     or clutter_effect_queue_rerun
7306    *
7307    * then control moves to:
7308    *   _clutter_stage_queue_actor_redraw
7309    *
7310    * later during _clutter_stage_do_update, once relayouting is done
7311    * and the scenegraph has been updated we will call:
7312    * _clutter_stage_finish_queue_redraws
7313    *
7314    * _clutter_stage_finish_queue_redraws will call
7315    * _clutter_actor_finish_queue_redraw for each listed actor.
7316    * Note: actors *are* allowed to queue further redraws during this
7317    * process (considering clone actors or texture_new_from_actor which
7318    * respond to their source queueing a redraw by queuing a redraw
7319    * themselves). We repeat the process until the list is empty.
7320    *
7321    * This will result in the "queue-redraw" signal being fired for
7322    * each actor which will pass control to the default signal handler:
7323    * clutter_actor_real_queue_redraw
7324    *
7325    * This will bubble up to the stages handler:
7326    * clutter_stage_real_queue_redraw
7327    *
7328    * clutter_stage_real_queue_redraw will transform the actors paint
7329    * volume into screen space and add it as a clip region for the next
7330    * paint.
7331    */
7332
7333   /* ignore queueing a redraw for actors being destroyed */
7334   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7335     return;
7336
7337   stage = _clutter_actor_get_stage_internal (self);
7338
7339   /* Ignore queueing a redraw for actors not descended from a stage */
7340   if (stage == NULL)
7341     return;
7342
7343   /* ignore queueing a redraw on stages that are being destroyed */
7344   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7345     return;
7346
7347   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7348     {
7349       ClutterActorBox allocation_clip;
7350       ClutterVertex origin;
7351
7352       /* If the actor doesn't have a valid allocation then we will
7353        * queue a full stage redraw. */
7354       if (priv->needs_allocation)
7355         {
7356           /* NB: NULL denotes an undefined clip which will result in a
7357            * full redraw... */
7358           _clutter_actor_set_queue_redraw_clip (self, NULL);
7359           _clutter_actor_signal_queue_redraw (self, self);
7360           return;
7361         }
7362
7363       _clutter_paint_volume_init_static (&allocation_pv, self);
7364       pv = &allocation_pv;
7365
7366       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7367
7368       origin.x = allocation_clip.x1;
7369       origin.y = allocation_clip.y1;
7370       origin.z = 0;
7371       clutter_paint_volume_set_origin (pv, &origin);
7372       clutter_paint_volume_set_width (pv,
7373                                       allocation_clip.x2 - allocation_clip.x1);
7374       clutter_paint_volume_set_height (pv,
7375                                        allocation_clip.y2 -
7376                                        allocation_clip.y1);
7377       should_free_pv = TRUE;
7378     }
7379   else
7380     {
7381       pv = volume;
7382       should_free_pv = FALSE;
7383     }
7384
7385   self->priv->queue_redraw_entry =
7386     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7387                                        priv->queue_redraw_entry,
7388                                        self,
7389                                        pv);
7390
7391   if (should_free_pv)
7392     clutter_paint_volume_free (pv);
7393
7394   /* If this is the first redraw queued then we can directly use the
7395      effect parameter */
7396   if (!priv->is_dirty)
7397     priv->effect_to_redraw = effect;
7398   /* Otherwise we need to merge it with the existing effect parameter */
7399   else if (effect != NULL)
7400     {
7401       /* If there's already an effect then we need to use whichever is
7402          later in the chain of actors. Otherwise a full redraw has
7403          already been queued on the actor so we need to ignore the
7404          effect parameter */
7405       if (priv->effect_to_redraw != NULL)
7406         {
7407           if (priv->effects == NULL)
7408             g_warning ("Redraw queued with an effect that is "
7409                        "not applied to the actor");
7410           else
7411             {
7412               const GList *l;
7413
7414               for (l = _clutter_meta_group_peek_metas (priv->effects);
7415                    l != NULL;
7416                    l = l->next)
7417                 {
7418                   if (l->data == priv->effect_to_redraw ||
7419                       l->data == effect)
7420                     priv->effect_to_redraw = l->data;
7421                 }
7422             }
7423         }
7424     }
7425   else
7426     {
7427       /* If no effect is specified then we need to redraw the whole
7428          actor */
7429       priv->effect_to_redraw = NULL;
7430     }
7431
7432   priv->is_dirty = TRUE;
7433 }
7434
7435 /**
7436  * clutter_actor_queue_redraw:
7437  * @self: A #ClutterActor
7438  *
7439  * Queues up a redraw of an actor and any children. The redraw occurs
7440  * once the main loop becomes idle (after the current batch of events
7441  * has been processed, roughly).
7442  *
7443  * Applications rarely need to call this, as redraws are handled
7444  * automatically by modification functions.
7445  *
7446  * This function will not do anything if @self is not visible, or
7447  * if the actor is inside an invisible part of the scenegraph.
7448  *
7449  * Also be aware that painting is a NOP for actors with an opacity of
7450  * 0
7451  *
7452  * When you are implementing a custom actor you must queue a redraw
7453  * whenever some private state changes that will affect painting or
7454  * picking of your actor.
7455  */
7456 void
7457 clutter_actor_queue_redraw (ClutterActor *self)
7458 {
7459   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7460
7461   _clutter_actor_queue_redraw_full (self,
7462                                     0, /* flags */
7463                                     NULL, /* clip volume */
7464                                     NULL /* effect */);
7465 }
7466
7467 /*< private >
7468  * _clutter_actor_queue_redraw_with_clip:
7469  * @self: A #ClutterActor
7470  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7471  *   this queue redraw.
7472  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7473  *   redrawn or %NULL if you are just using a @flag to state your
7474  *   desired clipping.
7475  *
7476  * Queues up a clipped redraw of an actor and any children. The redraw
7477  * occurs once the main loop becomes idle (after the current batch of
7478  * events has been processed, roughly).
7479  *
7480  * If no flags are given the clip volume is defined by @volume
7481  * specified in actor coordinates and tells Clutter that only content
7482  * within this volume has been changed so Clutter can optionally
7483  * optimize the redraw.
7484  *
7485  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7486  * should be %NULL and this tells Clutter to use the actor's current
7487  * allocation as a clip box. This flag can only be used for 2D actors,
7488  * because any actor with depth may be projected outside its
7489  * allocation.
7490  *
7491  * Applications rarely need to call this, as redraws are handled
7492  * automatically by modification functions.
7493  *
7494  * This function will not do anything if @self is not visible, or if
7495  * the actor is inside an invisible part of the scenegraph.
7496  *
7497  * Also be aware that painting is a NOP for actors with an opacity of
7498  * 0
7499  *
7500  * When you are implementing a custom actor you must queue a redraw
7501  * whenever some private state changes that will affect painting or
7502  * picking of your actor.
7503  */
7504 void
7505 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7506                                        ClutterRedrawFlags  flags,
7507                                        ClutterPaintVolume *volume)
7508 {
7509   _clutter_actor_queue_redraw_full (self,
7510                                     flags, /* flags */
7511                                     volume, /* clip volume */
7512                                     NULL /* effect */);
7513 }
7514
7515 static void
7516 _clutter_actor_queue_only_relayout (ClutterActor *self)
7517 {
7518   ClutterActorPrivate *priv = self->priv;
7519
7520   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7521     return;
7522
7523   if (priv->needs_width_request &&
7524       priv->needs_height_request &&
7525       priv->needs_allocation)
7526     return; /* save some cpu cycles */
7527
7528 #if CLUTTER_ENABLE_DEBUG
7529   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7530     {
7531       g_warning ("The actor '%s' is currently inside an allocation "
7532                  "cycle; calling clutter_actor_queue_relayout() is "
7533                  "not recommended",
7534                  _clutter_actor_get_debug_name (self));
7535     }
7536 #endif /* CLUTTER_ENABLE_DEBUG */
7537
7538   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7539 }
7540
7541 /**
7542  * clutter_actor_queue_redraw_with_clip:
7543  * @self: a #ClutterActor
7544  * @clip: (allow-none): a rectangular clip region, or %NULL
7545  *
7546  * Queues a redraw on @self limited to a specific, actor-relative
7547  * rectangular area.
7548  *
7549  * If @clip is %NULL this function is equivalent to
7550  * clutter_actor_queue_redraw().
7551  *
7552  * Since: 1.10
7553  */
7554 void
7555 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7556                                       const cairo_rectangle_int_t *clip)
7557 {
7558   ClutterPaintVolume volume;
7559   ClutterVertex origin;
7560
7561   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7562
7563   if (clip == NULL)
7564     {
7565       clutter_actor_queue_redraw (self);
7566       return;
7567     }
7568
7569   _clutter_paint_volume_init_static (&volume, self);
7570
7571   origin.x = clip->x;
7572   origin.y = clip->y;
7573   origin.z = 0.0f;
7574
7575   clutter_paint_volume_set_origin (&volume, &origin);
7576   clutter_paint_volume_set_width (&volume, clip->width);
7577   clutter_paint_volume_set_height (&volume, clip->height);
7578
7579   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7580
7581   clutter_paint_volume_free (&volume);
7582 }
7583
7584 /**
7585  * clutter_actor_queue_relayout:
7586  * @self: A #ClutterActor
7587  *
7588  * Indicates that the actor's size request or other layout-affecting
7589  * properties may have changed. This function is used inside #ClutterActor
7590  * subclass implementations, not by applications directly.
7591  *
7592  * Queueing a new layout automatically queues a redraw as well.
7593  *
7594  * Since: 0.8
7595  */
7596 void
7597 clutter_actor_queue_relayout (ClutterActor *self)
7598 {
7599   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7600
7601   _clutter_actor_queue_only_relayout (self);
7602   clutter_actor_queue_redraw (self);
7603 }
7604
7605 /**
7606  * clutter_actor_get_preferred_size:
7607  * @self: a #ClutterActor
7608  * @min_width_p: (out) (allow-none): return location for the minimum
7609  *   width, or %NULL
7610  * @min_height_p: (out) (allow-none): return location for the minimum
7611  *   height, or %NULL
7612  * @natural_width_p: (out) (allow-none): return location for the natural
7613  *   width, or %NULL
7614  * @natural_height_p: (out) (allow-none): return location for the natural
7615  *   height, or %NULL
7616  *
7617  * Computes the preferred minimum and natural size of an actor, taking into
7618  * account the actor's geometry management (either height-for-width
7619  * or width-for-height).
7620  *
7621  * The width and height used to compute the preferred height and preferred
7622  * width are the actor's natural ones.
7623  *
7624  * If you need to control the height for the preferred width, or the width for
7625  * the preferred height, you should use clutter_actor_get_preferred_width()
7626  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7627  * geometry management using the #ClutterActor:request-mode property.
7628  *
7629  * Since: 0.8
7630  */
7631 void
7632 clutter_actor_get_preferred_size (ClutterActor *self,
7633                                   gfloat       *min_width_p,
7634                                   gfloat       *min_height_p,
7635                                   gfloat       *natural_width_p,
7636                                   gfloat       *natural_height_p)
7637 {
7638   ClutterActorPrivate *priv;
7639   gfloat min_width, min_height;
7640   gfloat natural_width, natural_height;
7641
7642   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7643
7644   priv = self->priv;
7645
7646   min_width = min_height = 0;
7647   natural_width = natural_height = 0;
7648
7649   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7650     {
7651       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7652       clutter_actor_get_preferred_width (self, -1,
7653                                          &min_width,
7654                                          &natural_width);
7655       clutter_actor_get_preferred_height (self, natural_width,
7656                                           &min_height,
7657                                           &natural_height);
7658     }
7659   else
7660     {
7661       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7662       clutter_actor_get_preferred_height (self, -1,
7663                                           &min_height,
7664                                           &natural_height);
7665       clutter_actor_get_preferred_width (self, natural_height,
7666                                          &min_width,
7667                                          &natural_width);
7668     }
7669
7670   if (min_width_p)
7671     *min_width_p = min_width;
7672
7673   if (min_height_p)
7674     *min_height_p = min_height;
7675
7676   if (natural_width_p)
7677     *natural_width_p = natural_width;
7678
7679   if (natural_height_p)
7680     *natural_height_p = natural_height;
7681 }
7682
7683 /*< private >
7684  * effective_align:
7685  * @align: a #ClutterActorAlign
7686  * @direction: a #ClutterTextDirection
7687  *
7688  * Retrieves the correct alignment depending on the text direction
7689  *
7690  * Return value: the effective alignment
7691  */
7692 static ClutterActorAlign
7693 effective_align (ClutterActorAlign    align,
7694                  ClutterTextDirection direction)
7695 {
7696   ClutterActorAlign res;
7697
7698   switch (align)
7699     {
7700     case CLUTTER_ACTOR_ALIGN_START:
7701       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7702           ? CLUTTER_ACTOR_ALIGN_END
7703           : CLUTTER_ACTOR_ALIGN_START;
7704       break;
7705
7706     case CLUTTER_ACTOR_ALIGN_END:
7707       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7708           ? CLUTTER_ACTOR_ALIGN_START
7709           : CLUTTER_ACTOR_ALIGN_END;
7710       break;
7711
7712     default:
7713       res = align;
7714       break;
7715     }
7716
7717   return res;
7718 }
7719
7720 static inline void
7721 adjust_for_margin (float  margin_start,
7722                    float  margin_end,
7723                    float *minimum_size,
7724                    float *natural_size,
7725                    float *allocated_start,
7726                    float *allocated_end)
7727 {
7728   *minimum_size -= (margin_start + margin_end);
7729   *natural_size -= (margin_start + margin_end);
7730   *allocated_start += margin_start;
7731   *allocated_end -= margin_end;
7732 }
7733
7734 static inline void
7735 adjust_for_alignment (ClutterActorAlign  alignment,
7736                       float              natural_size,
7737                       float             *allocated_start,
7738                       float             *allocated_end)
7739 {
7740   float allocated_size = *allocated_end - *allocated_start;
7741
7742   switch (alignment)
7743     {
7744     case CLUTTER_ACTOR_ALIGN_FILL:
7745       /* do nothing */
7746       break;
7747
7748     case CLUTTER_ACTOR_ALIGN_START:
7749       /* keep start */
7750       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7751       break;
7752
7753     case CLUTTER_ACTOR_ALIGN_END:
7754       if (allocated_size > natural_size)
7755         {
7756           *allocated_start += (allocated_size - natural_size);
7757           *allocated_end = *allocated_start + natural_size;
7758         }
7759       break;
7760
7761     case CLUTTER_ACTOR_ALIGN_CENTER:
7762       if (allocated_size > natural_size)
7763         {
7764           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7765           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7766         }
7767       break;
7768     }
7769 }
7770
7771 /*< private >
7772  * clutter_actor_adjust_width:
7773  * @self: a #ClutterActor
7774  * @minimum_width: (inout): the actor's preferred minimum width, which
7775  *   will be adjusted depending on the margin
7776  * @natural_width: (inout): the actor's preferred natural width, which
7777  *   will be adjusted depending on the margin
7778  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7779  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7780  *
7781  * Adjusts the preferred and allocated position and size of an actor,
7782  * depending on the margin and alignment properties.
7783  */
7784 static void
7785 clutter_actor_adjust_width (ClutterActor *self,
7786                             gfloat       *minimum_width,
7787                             gfloat       *natural_width,
7788                             gfloat       *adjusted_x1,
7789                             gfloat       *adjusted_x2)
7790 {
7791   ClutterTextDirection text_dir;
7792   const ClutterLayoutInfo *info;
7793
7794   info = _clutter_actor_get_layout_info_or_defaults (self);
7795   text_dir = clutter_actor_get_text_direction (self);
7796
7797   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7798
7799   /* this will tweak natural_width to remove the margin, so that
7800    * adjust_for_alignment() will use the correct size
7801    */
7802   adjust_for_margin (info->margin.left, info->margin.right,
7803                      minimum_width, natural_width,
7804                      adjusted_x1, adjusted_x2);
7805
7806   adjust_for_alignment (effective_align (info->x_align, text_dir),
7807                         *natural_width,
7808                         adjusted_x1, adjusted_x2);
7809 }
7810
7811 /*< private >
7812  * clutter_actor_adjust_height:
7813  * @self: a #ClutterActor
7814  * @minimum_height: (inout): the actor's preferred minimum height, which
7815  *   will be adjusted depending on the margin
7816  * @natural_height: (inout): the actor's preferred natural height, which
7817  *   will be adjusted depending on the margin
7818  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7819  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7820  *
7821  * Adjusts the preferred and allocated position and size of an actor,
7822  * depending on the margin and alignment properties.
7823  */
7824 static void
7825 clutter_actor_adjust_height (ClutterActor *self,
7826                              gfloat       *minimum_height,
7827                              gfloat       *natural_height,
7828                              gfloat       *adjusted_y1,
7829                              gfloat       *adjusted_y2)
7830 {
7831   const ClutterLayoutInfo *info;
7832
7833   info = _clutter_actor_get_layout_info_or_defaults (self);
7834
7835   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7836
7837   /* this will tweak natural_height to remove the margin, so that
7838    * adjust_for_alignment() will use the correct size
7839    */
7840   adjust_for_margin (info->margin.top, info->margin.bottom,
7841                      minimum_height, natural_height,
7842                      adjusted_y1,
7843                      adjusted_y2);
7844
7845   /* we don't use effective_align() here, because text direction
7846    * only affects the horizontal axis
7847    */
7848   adjust_for_alignment (info->y_align,
7849                         *natural_height,
7850                         adjusted_y1,
7851                         adjusted_y2);
7852
7853 }
7854
7855 /* looks for a cached size request for this for_size. If not
7856  * found, returns the oldest entry so it can be overwritten */
7857 static gboolean
7858 _clutter_actor_get_cached_size_request (gfloat         for_size,
7859                                         SizeRequest   *cached_size_requests,
7860                                         SizeRequest  **result)
7861 {
7862   guint i;
7863
7864   *result = &cached_size_requests[0];
7865
7866   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7867     {
7868       SizeRequest *sr;
7869
7870       sr = &cached_size_requests[i];
7871
7872       if (sr->age > 0 &&
7873           sr->for_size == for_size)
7874         {
7875           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7876           *result = sr;
7877           return TRUE;
7878         }
7879       else if (sr->age < (*result)->age)
7880         {
7881           *result = sr;
7882         }
7883     }
7884
7885   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7886
7887   return FALSE;
7888 }
7889
7890 /**
7891  * clutter_actor_get_preferred_width:
7892  * @self: A #ClutterActor
7893  * @for_height: available height when computing the preferred width,
7894  *   or a negative value to indicate that no height is defined
7895  * @min_width_p: (out) (allow-none): return location for minimum width,
7896  *   or %NULL
7897  * @natural_width_p: (out) (allow-none): return location for the natural
7898  *   width, or %NULL
7899  *
7900  * Computes the requested minimum and natural widths for an actor,
7901  * optionally depending on the specified height, or if they are
7902  * already computed, returns the cached values.
7903  *
7904  * An actor may not get its request - depending on the layout
7905  * manager that's in effect.
7906  *
7907  * A request should not incorporate the actor's scale or anchor point;
7908  * those transformations do not affect layout, only rendering.
7909  *
7910  * Since: 0.8
7911  */
7912 void
7913 clutter_actor_get_preferred_width (ClutterActor *self,
7914                                    gfloat        for_height,
7915                                    gfloat       *min_width_p,
7916                                    gfloat       *natural_width_p)
7917 {
7918   float request_min_width, request_natural_width;
7919   SizeRequest *cached_size_request;
7920   const ClutterLayoutInfo *info;
7921   ClutterActorPrivate *priv;
7922   gboolean found_in_cache;
7923
7924   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7925
7926   priv = self->priv;
7927
7928   info = _clutter_actor_get_layout_info_or_defaults (self);
7929
7930   /* we shortcircuit the case of a fixed size set using set_width() */
7931   if (priv->min_width_set && priv->natural_width_set)
7932     {
7933       if (min_width_p != NULL)
7934         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7935
7936       if (natural_width_p != NULL)
7937         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7938
7939       return;
7940     }
7941
7942   /* the remaining cases are:
7943    *
7944    *   - either min_width or natural_width have been set
7945    *   - neither min_width or natural_width have been set
7946    *
7947    * in both cases, we go through the cache (and through the actor in case
7948    * of cache misses) and determine the authoritative value depending on
7949    * the *_set flags.
7950    */
7951
7952   if (!priv->needs_width_request)
7953     {
7954       found_in_cache =
7955         _clutter_actor_get_cached_size_request (for_height,
7956                                                 priv->width_requests,
7957                                                 &cached_size_request);
7958     }
7959   else
7960     {
7961       /* if the actor needs a width request we use the first slot */
7962       found_in_cache = FALSE;
7963       cached_size_request = &priv->width_requests[0];
7964     }
7965
7966   if (!found_in_cache)
7967     {
7968       gfloat minimum_width, natural_width;
7969       ClutterActorClass *klass;
7970
7971       minimum_width = natural_width = 0;
7972
7973       /* adjust for the margin */
7974       if (for_height >= 0)
7975         {
7976           for_height -= (info->margin.top + info->margin.bottom);
7977           if (for_height < 0)
7978             for_height = 0;
7979         }
7980
7981       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7982
7983       klass = CLUTTER_ACTOR_GET_CLASS (self);
7984       klass->get_preferred_width (self, for_height,
7985                                   &minimum_width,
7986                                   &natural_width);
7987
7988       /* adjust for the margin */
7989       minimum_width += (info->margin.left + info->margin.right);
7990       natural_width += (info->margin.left + info->margin.right);
7991
7992       /* Due to accumulated float errors, it's better not to warn
7993        * on this, but just fix it.
7994        */
7995       if (natural_width < minimum_width)
7996         natural_width = minimum_width;
7997
7998       cached_size_request->min_size = minimum_width;
7999       cached_size_request->natural_size = natural_width;
8000       cached_size_request->for_size = for_height;
8001       cached_size_request->age = priv->cached_width_age;
8002
8003       priv->cached_width_age += 1;
8004       priv->needs_width_request = FALSE;
8005     }
8006
8007   if (!priv->min_width_set)
8008     request_min_width = cached_size_request->min_size;
8009   else
8010     request_min_width = info->min_width;
8011
8012   if (!priv->natural_width_set)
8013     request_natural_width = cached_size_request->natural_size;
8014   else
8015     request_natural_width = info->natural_width;
8016
8017   if (min_width_p)
8018     *min_width_p = request_min_width;
8019
8020   if (natural_width_p)
8021     *natural_width_p = request_natural_width;
8022 }
8023
8024 /**
8025  * clutter_actor_get_preferred_height:
8026  * @self: A #ClutterActor
8027  * @for_width: available width to assume in computing desired height,
8028  *   or a negative value to indicate that no width is defined
8029  * @min_height_p: (out) (allow-none): return location for minimum height,
8030  *   or %NULL
8031  * @natural_height_p: (out) (allow-none): return location for natural
8032  *   height, or %NULL
8033  *
8034  * Computes the requested minimum and natural heights for an actor,
8035  * or if they are already computed, returns the cached values.
8036  *
8037  * An actor may not get its request - depending on the layout
8038  * manager that's in effect.
8039  *
8040  * A request should not incorporate the actor's scale or anchor point;
8041  * those transformations do not affect layout, only rendering.
8042  *
8043  * Since: 0.8
8044  */
8045 void
8046 clutter_actor_get_preferred_height (ClutterActor *self,
8047                                     gfloat        for_width,
8048                                     gfloat       *min_height_p,
8049                                     gfloat       *natural_height_p)
8050 {
8051   float request_min_height, request_natural_height;
8052   SizeRequest *cached_size_request;
8053   const ClutterLayoutInfo *info;
8054   ClutterActorPrivate *priv;
8055   gboolean found_in_cache;
8056
8057   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8058
8059   priv = self->priv;
8060
8061   info = _clutter_actor_get_layout_info_or_defaults (self);
8062
8063   /* we shortcircuit the case of a fixed size set using set_height() */
8064   if (priv->min_height_set && priv->natural_height_set)
8065     {
8066       if (min_height_p != NULL)
8067         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
8068
8069       if (natural_height_p != NULL)
8070         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
8071
8072       return;
8073     }
8074
8075   /* the remaining cases are:
8076    *
8077    *   - either min_height or natural_height have been set
8078    *   - neither min_height or natural_height have been set
8079    *
8080    * in both cases, we go through the cache (and through the actor in case
8081    * of cache misses) and determine the authoritative value depending on
8082    * the *_set flags.
8083    */
8084
8085   if (!priv->needs_height_request)
8086     {
8087       found_in_cache =
8088         _clutter_actor_get_cached_size_request (for_width,
8089                                                 priv->height_requests,
8090                                                 &cached_size_request);
8091     }
8092   else
8093     {
8094       found_in_cache = FALSE;
8095       cached_size_request = &priv->height_requests[0];
8096     }
8097
8098   if (!found_in_cache)
8099     {
8100       gfloat minimum_height, natural_height;
8101       ClutterActorClass *klass;
8102
8103       minimum_height = natural_height = 0;
8104
8105       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8106
8107       /* adjust for margin */
8108       if (for_width >= 0)
8109         {
8110           for_width -= (info->margin.left + info->margin.right);
8111           if (for_width < 0)
8112             for_width = 0;
8113         }
8114
8115       klass = CLUTTER_ACTOR_GET_CLASS (self);
8116       klass->get_preferred_height (self, for_width,
8117                                    &minimum_height,
8118                                    &natural_height);
8119
8120       /* adjust for margin */
8121       minimum_height += (info->margin.top + info->margin.bottom);
8122       natural_height += (info->margin.top + info->margin.bottom);
8123
8124       /* Due to accumulated float errors, it's better not to warn
8125        * on this, but just fix it.
8126        */
8127       if (natural_height < minimum_height)
8128         natural_height = minimum_height;
8129
8130       cached_size_request->min_size = minimum_height;
8131       cached_size_request->natural_size = natural_height;
8132       cached_size_request->for_size = for_width;
8133       cached_size_request->age = priv->cached_height_age;
8134
8135       priv->cached_height_age += 1;
8136       priv->needs_height_request = FALSE;
8137     }
8138
8139   if (!priv->min_height_set)
8140     request_min_height = cached_size_request->min_size;
8141   else
8142     request_min_height = info->min_height;
8143
8144   if (!priv->natural_height_set)
8145     request_natural_height = cached_size_request->natural_size;
8146   else
8147     request_natural_height = info->natural_height;
8148
8149   if (min_height_p)
8150     *min_height_p = request_min_height;
8151
8152   if (natural_height_p)
8153     *natural_height_p = request_natural_height;
8154 }
8155
8156 /**
8157  * clutter_actor_get_allocation_box:
8158  * @self: A #ClutterActor
8159  * @box: (out): the function fills this in with the actor's allocation
8160  *
8161  * Gets the layout box an actor has been assigned. The allocation can
8162  * only be assumed valid inside a paint() method; anywhere else, it
8163  * may be out-of-date.
8164  *
8165  * An allocation does not incorporate the actor's scale or anchor point;
8166  * those transformations do not affect layout, only rendering.
8167  *
8168  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8169  * of functions inside the implementation of the get_preferred_width()
8170  * or get_preferred_height() virtual functions.</note>
8171  *
8172  * Since: 0.8
8173  */
8174 void
8175 clutter_actor_get_allocation_box (ClutterActor    *self,
8176                                   ClutterActorBox *box)
8177 {
8178   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8179
8180   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8181    * which limits calling get_allocation to inside paint() basically; or
8182    * we can 2) force a layout, which could be expensive if someone calls
8183    * get_allocation somewhere silly; or we can 3) just return the latest
8184    * value, allowing it to be out-of-date, and assume people know what
8185    * they are doing.
8186    *
8187    * The least-surprises approach that keeps existing code working is
8188    * likely to be 2). People can end up doing some inefficient things,
8189    * though, and in general code that requires 2) is probably broken.
8190    */
8191
8192   /* this implements 2) */
8193   if (G_UNLIKELY (self->priv->needs_allocation))
8194     {
8195       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8196
8197       /* do not queue a relayout on an unparented actor */
8198       if (stage)
8199         _clutter_stage_maybe_relayout (stage);
8200     }
8201
8202   /* commenting out the code above and just keeping this assigment
8203    * implements 3)
8204    */
8205   *box = self->priv->allocation;
8206 }
8207
8208 /**
8209  * clutter_actor_get_allocation_geometry:
8210  * @self: A #ClutterActor
8211  * @geom: (out): allocation geometry in pixels
8212  *
8213  * Gets the layout box an actor has been assigned.  The allocation can
8214  * only be assumed valid inside a paint() method; anywhere else, it
8215  * may be out-of-date.
8216  *
8217  * An allocation does not incorporate the actor's scale or anchor point;
8218  * those transformations do not affect layout, only rendering.
8219  *
8220  * The returned rectangle is in pixels.
8221  *
8222  * Since: 0.8
8223  */
8224 void
8225 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8226                                        ClutterGeometry *geom)
8227 {
8228   ClutterActorBox box;
8229
8230   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8231   g_return_if_fail (geom != NULL);
8232
8233   clutter_actor_get_allocation_box (self, &box);
8234
8235   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8236   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8237   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8238   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8239 }
8240
8241 static void
8242 clutter_actor_update_constraints (ClutterActor    *self,
8243                                   ClutterActorBox *allocation)
8244 {
8245   ClutterActorPrivate *priv = self->priv;
8246   const GList *constraints, *l;
8247
8248   if (priv->constraints == NULL)
8249     return;
8250
8251   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8252   for (l = constraints; l != NULL; l = l->next)
8253     {
8254       ClutterConstraint *constraint = l->data;
8255       ClutterActorMeta *meta = l->data;
8256
8257       if (clutter_actor_meta_get_enabled (meta))
8258         {
8259           _clutter_constraint_update_allocation (constraint,
8260                                                  self,
8261                                                  allocation);
8262
8263           CLUTTER_NOTE (LAYOUT,
8264                         "Allocation of '%s' after constraint '%s': "
8265                         "{ %.2f, %.2f, %.2f, %.2f }",
8266                         _clutter_actor_get_debug_name (self),
8267                         _clutter_actor_meta_get_debug_name (meta),
8268                         allocation->x1,
8269                         allocation->y1,
8270                         allocation->x2,
8271                         allocation->y2);
8272         }
8273     }
8274 }
8275
8276 /*< private >
8277  * clutter_actor_adjust_allocation:
8278  * @self: a #ClutterActor
8279  * @allocation: (inout): the allocation to adjust
8280  *
8281  * Adjusts the passed allocation box taking into account the actor's
8282  * layout information, like alignment, expansion, and margin.
8283  */
8284 static void
8285 clutter_actor_adjust_allocation (ClutterActor    *self,
8286                                  ClutterActorBox *allocation)
8287 {
8288   ClutterActorBox adj_allocation;
8289   float alloc_width, alloc_height;
8290   float min_width, min_height;
8291   float nat_width, nat_height;
8292   ClutterRequestMode req_mode;
8293
8294   adj_allocation = *allocation;
8295
8296   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8297
8298   /* we want to hit the cache, so we use the public API */
8299   req_mode = clutter_actor_get_request_mode (self);
8300
8301   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8302     {
8303       clutter_actor_get_preferred_width (self, -1,
8304                                          &min_width,
8305                                          &nat_width);
8306       clutter_actor_get_preferred_height (self, alloc_width,
8307                                           &min_height,
8308                                           &nat_height);
8309     }
8310   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8311     {
8312       clutter_actor_get_preferred_height (self, -1,
8313                                           &min_height,
8314                                           &nat_height);
8315       clutter_actor_get_preferred_height (self, alloc_height,
8316                                           &min_width,
8317                                           &nat_width);
8318     }
8319
8320 #ifdef CLUTTER_ENABLE_DEBUG
8321   /* warn about underallocations */
8322   if (_clutter_diagnostic_enabled () &&
8323       (floorf (min_width - alloc_width) > 0 ||
8324        floorf (min_height - alloc_height) > 0))
8325     {
8326       ClutterActor *parent = clutter_actor_get_parent (self);
8327
8328       /* the only actors that are allowed to be underallocated are the Stage,
8329        * as it doesn't have an implicit size, and Actors that specifically
8330        * told us that they want to opt-out from layout control mechanisms
8331        * through the NO_LAYOUT escape hatch.
8332        */
8333       if (parent != NULL &&
8334           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8335         {
8336           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8337                      "of %.2f x %.2f from its parent actor '%s', but its "
8338                      "requested minimum size is of %.2f x %.2f",
8339                      _clutter_actor_get_debug_name (self),
8340                      alloc_width, alloc_height,
8341                      _clutter_actor_get_debug_name (parent),
8342                      min_width, min_height);
8343         }
8344     }
8345 #endif
8346
8347   clutter_actor_adjust_width (self,
8348                               &min_width,
8349                               &nat_width,
8350                               &adj_allocation.x1,
8351                               &adj_allocation.x2);
8352
8353   clutter_actor_adjust_height (self,
8354                                &min_height,
8355                                &nat_height,
8356                                &adj_allocation.y1,
8357                                &adj_allocation.y2);
8358
8359   /* we maintain the invariant that an allocation cannot be adjusted
8360    * to be outside the parent-given box
8361    */
8362   if (adj_allocation.x1 < allocation->x1 ||
8363       adj_allocation.y1 < allocation->y1 ||
8364       adj_allocation.x2 > allocation->x2 ||
8365       adj_allocation.y2 > allocation->y2)
8366     {
8367       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8368                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8369                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8370                  _clutter_actor_get_debug_name (self),
8371                  adj_allocation.x1, adj_allocation.y1,
8372                  adj_allocation.x2 - adj_allocation.x1,
8373                  adj_allocation.y2 - adj_allocation.y1,
8374                  allocation->x1, allocation->y1,
8375                  allocation->x2 - allocation->x1,
8376                  allocation->y2 - allocation->y1);
8377       return;
8378     }
8379
8380   *allocation = adj_allocation;
8381 }
8382
8383 /**
8384  * clutter_actor_allocate:
8385  * @self: A #ClutterActor
8386  * @box: new allocation of the actor, in parent-relative coordinates
8387  * @flags: flags that control the allocation
8388  *
8389  * Called by the parent of an actor to assign the actor its size.
8390  * Should never be called by applications (except when implementing
8391  * a container or layout manager).
8392  *
8393  * Actors can know from their allocation box whether they have moved
8394  * with respect to their parent actor. The @flags parameter describes
8395  * additional information about the allocation, for instance whether
8396  * the parent has moved with respect to the stage, for example because
8397  * a grandparent's origin has moved.
8398  *
8399  * Since: 0.8
8400  */
8401 void
8402 clutter_actor_allocate (ClutterActor           *self,
8403                         const ClutterActorBox  *box,
8404                         ClutterAllocationFlags  flags)
8405 {
8406   ClutterActorPrivate *priv;
8407   ClutterActorClass *klass;
8408   ClutterActorBox old_allocation, real_allocation;
8409   gboolean origin_changed, child_moved, size_changed;
8410   gboolean stage_allocation_changed;
8411
8412   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8413   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8414     {
8415       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8416                  "which isn't a descendent of the stage!\n",
8417                  self, _clutter_actor_get_debug_name (self));
8418       return;
8419     }
8420
8421   priv = self->priv;
8422
8423   old_allocation = priv->allocation;
8424   real_allocation = *box;
8425
8426   /* constraints are allowed to modify the allocation only here; we do
8427    * this prior to all the other checks so that we can bail out if the
8428    * allocation did not change
8429    */
8430   clutter_actor_update_constraints (self, &real_allocation);
8431
8432   /* adjust the allocation depending on the align/margin properties */
8433   clutter_actor_adjust_allocation (self, &real_allocation);
8434
8435   if (real_allocation.x2 < real_allocation.x1 ||
8436       real_allocation.y2 < real_allocation.y1)
8437     {
8438       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8439                  _clutter_actor_get_debug_name (self),
8440                  real_allocation.x2 - real_allocation.x1,
8441                  real_allocation.y2 - real_allocation.y1);
8442     }
8443
8444   /* we allow 0-sized actors, but not negative-sized ones */
8445   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8446   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8447
8448   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8449
8450   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8451                  real_allocation.y1 != old_allocation.y1);
8452
8453   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8454                   real_allocation.y2 != old_allocation.y2);
8455
8456   if (origin_changed || child_moved || size_changed)
8457     stage_allocation_changed = TRUE;
8458   else
8459     stage_allocation_changed = FALSE;
8460
8461   /* If we get an allocation "out of the blue"
8462    * (we did not queue relayout), then we want to
8463    * ignore it. But if we have needs_allocation set,
8464    * we want to guarantee that allocate() virtual
8465    * method is always called, i.e. that queue_relayout()
8466    * always results in an allocate() invocation on
8467    * an actor.
8468    *
8469    * The optimization here is to avoid re-allocating
8470    * actors that did not queue relayout and were
8471    * not moved.
8472    */
8473   if (!priv->needs_allocation && !stage_allocation_changed)
8474     {
8475       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8476       return;
8477     }
8478
8479   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8480    * clutter_actor_allocate(), it indicates whether the parent has its
8481    * absolute origin moved; when passed in to ClutterActor::allocate()
8482    * virtual method though, it indicates whether the child has its
8483    * absolute origin moved.  So we set it when child_moved is TRUE
8484    */
8485   if (child_moved)
8486     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8487
8488   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8489
8490   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8491                 _clutter_actor_get_debug_name (self));
8492
8493   klass = CLUTTER_ACTOR_GET_CLASS (self);
8494   klass->allocate (self, &real_allocation, flags);
8495
8496   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8497
8498   if (stage_allocation_changed)
8499     clutter_actor_queue_redraw (self);
8500 }
8501
8502 /**
8503  * clutter_actor_set_allocation:
8504  * @self: a #ClutterActor
8505  * @box: a #ClutterActorBox
8506  * @flags: allocation flags
8507  *
8508  * Stores the allocation of @self as defined by @box.
8509  *
8510  * This function can only be called from within the implementation of
8511  * the #ClutterActorClass.allocate() virtual function.
8512  *
8513  * The allocation should have been adjusted to take into account constraints,
8514  * alignment, and margin properties. If you are implementing a #ClutterActor
8515  * subclass that provides its own layout management policy for its children
8516  * instead of using a #ClutterLayoutManager delegate, you should not call
8517  * this function on the children of @self; instead, you should call
8518  * clutter_actor_allocate(), which will adjust the allocation box for
8519  * you.
8520  *
8521  * This function should only be used by subclasses of #ClutterActor
8522  * that wish to store their allocation but cannot chain up to the
8523  * parent's implementation; the default implementation of the
8524  * #ClutterActorClass.allocate() virtual function will call this
8525  * function.
8526  *
8527  * It is important to note that, while chaining up was the recommended
8528  * behaviour for #ClutterActor subclasses prior to the introduction of
8529  * this function, it is recommended to call clutter_actor_set_allocation()
8530  * instead.
8531  *
8532  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8533  * to handle the allocation of its children, this function will call
8534  * the clutter_layout_manager_allocate() function only if the
8535  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8536  * expected that the subclass will call clutter_layout_manager_allocate()
8537  * by itself. For instance, the following code:
8538  *
8539  * |[
8540  * static void
8541  * my_actor_allocate (ClutterActor *actor,
8542  *                    const ClutterActorBox *allocation,
8543  *                    ClutterAllocationFlags flags)
8544  * {
8545  *   ClutterActorBox new_alloc;
8546  *   ClutterAllocationFlags new_flags;
8547  *
8548  *   adjust_allocation (allocation, &amp;new_alloc);
8549  *
8550  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8551  *
8552  *   /&ast; this will use the layout manager set on the actor &ast;/
8553  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8554  * }
8555  * ]|
8556  *
8557  * is equivalent to this:
8558  *
8559  * |[
8560  * static void
8561  * my_actor_allocate (ClutterActor *actor,
8562  *                    const ClutterActorBox *allocation,
8563  *                    ClutterAllocationFlags flags)
8564  * {
8565  *   ClutterLayoutManager *layout;
8566  *   ClutterActorBox new_alloc;
8567  *
8568  *   adjust_allocation (allocation, &amp;new_alloc);
8569  *
8570  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8571  *
8572  *   layout = clutter_actor_get_layout_manager (actor);
8573  *   clutter_layout_manager_allocate (layout,
8574  *                                    CLUTTER_CONTAINER (actor),
8575  *                                    &amp;new_alloc,
8576  *                                    flags);
8577  * }
8578  * ]|
8579  *
8580  * Since: 1.10
8581  */
8582 void
8583 clutter_actor_set_allocation (ClutterActor           *self,
8584                               const ClutterActorBox  *box,
8585                               ClutterAllocationFlags  flags)
8586 {
8587   ClutterActorPrivate *priv;
8588   gboolean changed;
8589
8590   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8591   g_return_if_fail (box != NULL);
8592
8593   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8594     {
8595       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8596                   "can only be called from within the implementation of "
8597                   "the ClutterActor::allocate() virtual function.");
8598       return;
8599     }
8600
8601   priv = self->priv;
8602
8603   g_object_freeze_notify (G_OBJECT (self));
8604
8605   changed = clutter_actor_set_allocation_internal (self, box, flags);
8606
8607   /* we allocate our children before we notify changes in our geometry,
8608    * so that people connecting to properties will be able to get valid
8609    * data out of the sub-tree of the scene graph that has this actor at
8610    * the root.
8611    */
8612   clutter_actor_maybe_layout_children (self, box, flags);
8613
8614   if (changed)
8615     {
8616       ClutterActorBox signal_box = priv->allocation;
8617       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8618
8619       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8620                      &signal_box,
8621                      signal_flags);
8622     }
8623
8624   g_object_thaw_notify (G_OBJECT (self));
8625 }
8626
8627 /**
8628  * clutter_actor_set_geometry:
8629  * @self: A #ClutterActor
8630  * @geometry: A #ClutterGeometry
8631  *
8632  * Sets the actor's fixed position and forces its minimum and natural
8633  * size, in pixels. This means the untransformed actor will have the
8634  * given geometry. This is the same as calling clutter_actor_set_position()
8635  * and clutter_actor_set_size().
8636  *
8637  * Deprecated: 1.10: Use clutter_actor_set_position() and
8638  *   clutter_actor_set_size() instead.
8639  */
8640 void
8641 clutter_actor_set_geometry (ClutterActor          *self,
8642                             const ClutterGeometry *geometry)
8643 {
8644   g_object_freeze_notify (G_OBJECT (self));
8645
8646   clutter_actor_set_position (self, geometry->x, geometry->y);
8647   clutter_actor_set_size (self, geometry->width, geometry->height);
8648
8649   g_object_thaw_notify (G_OBJECT (self));
8650 }
8651
8652 /**
8653  * clutter_actor_get_geometry:
8654  * @self: A #ClutterActor
8655  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8656  *
8657  * Gets the size and position of an actor relative to its parent
8658  * actor. This is the same as calling clutter_actor_get_position() and
8659  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8660  * requested size and position if the actor's allocation is invalid.
8661  *
8662  * Deprecated: 1.10: Use clutter_actor_get_position() and
8663  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8664  *   instead.
8665  */
8666 void
8667 clutter_actor_get_geometry (ClutterActor    *self,
8668                             ClutterGeometry *geometry)
8669 {
8670   gfloat x, y, width, height;
8671
8672   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8673   g_return_if_fail (geometry != NULL);
8674
8675   clutter_actor_get_position (self, &x, &y);
8676   clutter_actor_get_size (self, &width, &height);
8677
8678   geometry->x = (int) x;
8679   geometry->y = (int) y;
8680   geometry->width = (int) width;
8681   geometry->height = (int) height;
8682 }
8683
8684 /**
8685  * clutter_actor_set_position:
8686  * @self: A #ClutterActor
8687  * @x: New left position of actor in pixels.
8688  * @y: New top position of actor in pixels.
8689  *
8690  * Sets the actor's fixed position in pixels relative to any parent
8691  * actor.
8692  *
8693  * If a layout manager is in use, this position will override the
8694  * layout manager and force a fixed position.
8695  */
8696 void
8697 clutter_actor_set_position (ClutterActor *self,
8698                             gfloat        x,
8699                             gfloat        y)
8700 {
8701   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8702
8703   g_object_freeze_notify (G_OBJECT (self));
8704
8705   clutter_actor_set_x (self, x);
8706   clutter_actor_set_y (self, y);
8707
8708   g_object_thaw_notify (G_OBJECT (self));
8709 }
8710
8711 /**
8712  * clutter_actor_get_fixed_position_set:
8713  * @self: A #ClutterActor
8714  *
8715  * Checks whether an actor has a fixed position set (and will thus be
8716  * unaffected by any layout manager).
8717  *
8718  * Return value: %TRUE if the fixed position is set on the actor
8719  *
8720  * Since: 0.8
8721  */
8722 gboolean
8723 clutter_actor_get_fixed_position_set (ClutterActor *self)
8724 {
8725   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8726
8727   return self->priv->position_set;
8728 }
8729
8730 /**
8731  * clutter_actor_set_fixed_position_set:
8732  * @self: A #ClutterActor
8733  * @is_set: whether to use fixed position
8734  *
8735  * Sets whether an actor has a fixed position set (and will thus be
8736  * unaffected by any layout manager).
8737  *
8738  * Since: 0.8
8739  */
8740 void
8741 clutter_actor_set_fixed_position_set (ClutterActor *self,
8742                                       gboolean      is_set)
8743 {
8744   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8745
8746   if (self->priv->position_set == (is_set != FALSE))
8747     return;
8748
8749   self->priv->position_set = is_set != FALSE;
8750   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8751
8752   clutter_actor_queue_relayout (self);
8753 }
8754
8755 /**
8756  * clutter_actor_move_by:
8757  * @self: A #ClutterActor
8758  * @dx: Distance to move Actor on X axis.
8759  * @dy: Distance to move Actor on Y axis.
8760  *
8761  * Moves an actor by the specified distance relative to its current
8762  * position in pixels.
8763  *
8764  * This function modifies the fixed position of an actor and thus removes
8765  * it from any layout management. Another way to move an actor is with an
8766  * anchor point, see clutter_actor_set_anchor_point().
8767  *
8768  * Since: 0.2
8769  */
8770 void
8771 clutter_actor_move_by (ClutterActor *self,
8772                        gfloat        dx,
8773                        gfloat        dy)
8774 {
8775   const ClutterLayoutInfo *info;
8776   gfloat x, y;
8777
8778   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8779
8780   info = _clutter_actor_get_layout_info_or_defaults (self);
8781   x = info->fixed_x;
8782   y = info->fixed_y;
8783
8784   clutter_actor_set_position (self, x + dx, y + dy);
8785 }
8786
8787 static void
8788 clutter_actor_set_min_width (ClutterActor *self,
8789                              gfloat        min_width)
8790 {
8791   ClutterActorPrivate *priv = self->priv;
8792   ClutterActorBox old = { 0, };
8793   ClutterLayoutInfo *info;
8794
8795   /* if we are setting the size on a top-level actor and the
8796    * backend only supports static top-levels (e.g. framebuffers)
8797    * then we ignore the passed value and we override it with
8798    * the stage implementation's preferred size.
8799    */
8800   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8801       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8802     return;
8803
8804   info = _clutter_actor_get_layout_info (self);
8805
8806   if (priv->min_width_set && min_width == info->min_width)
8807     return;
8808
8809   g_object_freeze_notify (G_OBJECT (self));
8810
8811   clutter_actor_store_old_geometry (self, &old);
8812
8813   info->min_width = min_width;
8814   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8815   clutter_actor_set_min_width_set (self, TRUE);
8816
8817   clutter_actor_notify_if_geometry_changed (self, &old);
8818
8819   g_object_thaw_notify (G_OBJECT (self));
8820
8821   clutter_actor_queue_relayout (self);
8822 }
8823
8824 static void
8825 clutter_actor_set_min_height (ClutterActor *self,
8826                               gfloat        min_height)
8827
8828 {
8829   ClutterActorPrivate *priv = self->priv;
8830   ClutterActorBox old = { 0, };
8831   ClutterLayoutInfo *info;
8832
8833   /* if we are setting the size on a top-level actor and the
8834    * backend only supports static top-levels (e.g. framebuffers)
8835    * then we ignore the passed value and we override it with
8836    * the stage implementation's preferred size.
8837    */
8838   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8839       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8840     return;
8841
8842   info = _clutter_actor_get_layout_info (self);
8843
8844   if (priv->min_height_set && min_height == info->min_height)
8845     return;
8846
8847   g_object_freeze_notify (G_OBJECT (self));
8848
8849   clutter_actor_store_old_geometry (self, &old);
8850
8851   info->min_height = min_height;
8852   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8853   clutter_actor_set_min_height_set (self, TRUE);
8854
8855   clutter_actor_notify_if_geometry_changed (self, &old);
8856
8857   g_object_thaw_notify (G_OBJECT (self));
8858
8859   clutter_actor_queue_relayout (self);
8860 }
8861
8862 static void
8863 clutter_actor_set_natural_width (ClutterActor *self,
8864                                  gfloat        natural_width)
8865 {
8866   ClutterActorPrivate *priv = self->priv;
8867   ClutterActorBox old = { 0, };
8868   ClutterLayoutInfo *info;
8869
8870   /* if we are setting the size on a top-level actor and the
8871    * backend only supports static top-levels (e.g. framebuffers)
8872    * then we ignore the passed value and we override it with
8873    * the stage implementation's preferred size.
8874    */
8875   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8876       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8877     return;
8878
8879   info = _clutter_actor_get_layout_info (self);
8880
8881   if (priv->natural_width_set && natural_width == info->natural_width)
8882     return;
8883
8884   g_object_freeze_notify (G_OBJECT (self));
8885
8886   clutter_actor_store_old_geometry (self, &old);
8887
8888   info->natural_width = natural_width;
8889   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8890   clutter_actor_set_natural_width_set (self, TRUE);
8891
8892   clutter_actor_notify_if_geometry_changed (self, &old);
8893
8894   g_object_thaw_notify (G_OBJECT (self));
8895
8896   clutter_actor_queue_relayout (self);
8897 }
8898
8899 static void
8900 clutter_actor_set_natural_height (ClutterActor *self,
8901                                   gfloat        natural_height)
8902 {
8903   ClutterActorPrivate *priv = self->priv;
8904   ClutterActorBox old = { 0, };
8905   ClutterLayoutInfo *info;
8906
8907   /* if we are setting the size on a top-level actor and the
8908    * backend only supports static top-levels (e.g. framebuffers)
8909    * then we ignore the passed value and we override it with
8910    * the stage implementation's preferred size.
8911    */
8912   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8913       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8914     return;
8915
8916   info = _clutter_actor_get_layout_info (self);
8917
8918   if (priv->natural_height_set && natural_height == info->natural_height)
8919     return;
8920
8921   g_object_freeze_notify (G_OBJECT (self));
8922
8923   clutter_actor_store_old_geometry (self, &old);
8924
8925   info->natural_height = natural_height;
8926   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8927   clutter_actor_set_natural_height_set (self, TRUE);
8928
8929   clutter_actor_notify_if_geometry_changed (self, &old);
8930
8931   g_object_thaw_notify (G_OBJECT (self));
8932
8933   clutter_actor_queue_relayout (self);
8934 }
8935
8936 static void
8937 clutter_actor_set_min_width_set (ClutterActor *self,
8938                                  gboolean      use_min_width)
8939 {
8940   ClutterActorPrivate *priv = self->priv;
8941   ClutterActorBox old = { 0, };
8942
8943   if (priv->min_width_set == (use_min_width != FALSE))
8944     return;
8945
8946   clutter_actor_store_old_geometry (self, &old);
8947
8948   priv->min_width_set = use_min_width != FALSE;
8949   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8950
8951   clutter_actor_notify_if_geometry_changed (self, &old);
8952
8953   clutter_actor_queue_relayout (self);
8954 }
8955
8956 static void
8957 clutter_actor_set_min_height_set (ClutterActor *self,
8958                                   gboolean      use_min_height)
8959 {
8960   ClutterActorPrivate *priv = self->priv;
8961   ClutterActorBox old = { 0, };
8962
8963   if (priv->min_height_set == (use_min_height != FALSE))
8964     return;
8965
8966   clutter_actor_store_old_geometry (self, &old);
8967
8968   priv->min_height_set = use_min_height != FALSE;
8969   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8970
8971   clutter_actor_notify_if_geometry_changed (self, &old);
8972
8973   clutter_actor_queue_relayout (self);
8974 }
8975
8976 static void
8977 clutter_actor_set_natural_width_set (ClutterActor *self,
8978                                      gboolean      use_natural_width)
8979 {
8980   ClutterActorPrivate *priv = self->priv;
8981   ClutterActorBox old = { 0, };
8982
8983   if (priv->natural_width_set == (use_natural_width != FALSE))
8984     return;
8985
8986   clutter_actor_store_old_geometry (self, &old);
8987
8988   priv->natural_width_set = use_natural_width != FALSE;
8989   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8990
8991   clutter_actor_notify_if_geometry_changed (self, &old);
8992
8993   clutter_actor_queue_relayout (self);
8994 }
8995
8996 static void
8997 clutter_actor_set_natural_height_set (ClutterActor *self,
8998                                       gboolean      use_natural_height)
8999 {
9000   ClutterActorPrivate *priv = self->priv;
9001   ClutterActorBox old = { 0, };
9002
9003   if (priv->natural_height_set == (use_natural_height != FALSE))
9004     return;
9005
9006   clutter_actor_store_old_geometry (self, &old);
9007
9008   priv->natural_height_set = use_natural_height != FALSE;
9009   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9010
9011   clutter_actor_notify_if_geometry_changed (self, &old);
9012
9013   clutter_actor_queue_relayout (self);
9014 }
9015
9016 /**
9017  * clutter_actor_set_request_mode:
9018  * @self: a #ClutterActor
9019  * @mode: the request mode
9020  *
9021  * Sets the geometry request mode of @self.
9022  *
9023  * The @mode determines the order for invoking
9024  * clutter_actor_get_preferred_width() and
9025  * clutter_actor_get_preferred_height()
9026  *
9027  * Since: 1.2
9028  */
9029 void
9030 clutter_actor_set_request_mode (ClutterActor       *self,
9031                                 ClutterRequestMode  mode)
9032 {
9033   ClutterActorPrivate *priv;
9034
9035   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9036
9037   priv = self->priv;
9038
9039   if (priv->request_mode == mode)
9040     return;
9041
9042   priv->request_mode = mode;
9043
9044   priv->needs_width_request = TRUE;
9045   priv->needs_height_request = TRUE;
9046
9047   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9048
9049   clutter_actor_queue_relayout (self);
9050 }
9051
9052 /**
9053  * clutter_actor_get_request_mode:
9054  * @self: a #ClutterActor
9055  *
9056  * Retrieves the geometry request mode of @self
9057  *
9058  * Return value: the request mode for the actor
9059  *
9060  * Since: 1.2
9061  */
9062 ClutterRequestMode
9063 clutter_actor_get_request_mode (ClutterActor *self)
9064 {
9065   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9066                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9067
9068   return self->priv->request_mode;
9069 }
9070
9071 /* variant of set_width() without checks and without notification
9072  * freeze+thaw, for internal usage only
9073  */
9074 static inline void
9075 clutter_actor_set_width_internal (ClutterActor *self,
9076                                   gfloat        width)
9077 {
9078   if (width >= 0)
9079     {
9080       /* the Stage will use the :min-width to control the minimum
9081        * width to be resized to, so we should not be setting it
9082        * along with the :natural-width
9083        */
9084       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9085         clutter_actor_set_min_width (self, width);
9086
9087       clutter_actor_set_natural_width (self, width);
9088     }
9089   else
9090     {
9091       /* we only unset the :natural-width for the Stage */
9092       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9093         clutter_actor_set_min_width_set (self, FALSE);
9094
9095       clutter_actor_set_natural_width_set (self, FALSE);
9096     }
9097 }
9098
9099 /* variant of set_height() without checks and without notification
9100  * freeze+thaw, for internal usage only
9101  */
9102 static inline void
9103 clutter_actor_set_height_internal (ClutterActor *self,
9104                                    gfloat        height)
9105 {
9106   if (height >= 0)
9107     {
9108       /* see the comment above in set_width_internal() */
9109       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9110         clutter_actor_set_min_height (self, height);
9111
9112       clutter_actor_set_natural_height (self, height);
9113     }
9114   else
9115     {
9116       /* see the comment above in set_width_internal() */
9117       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9118         clutter_actor_set_min_height_set (self, FALSE);
9119
9120       clutter_actor_set_natural_height_set (self, FALSE);
9121     }
9122 }
9123
9124 /**
9125  * clutter_actor_set_size:
9126  * @self: A #ClutterActor
9127  * @width: New width of actor in pixels, or -1
9128  * @height: New height of actor in pixels, or -1
9129  *
9130  * Sets the actor's size request in pixels. This overrides any
9131  * "normal" size request the actor would have. For example
9132  * a text actor might normally request the size of the text;
9133  * this function would force a specific size instead.
9134  *
9135  * If @width and/or @height are -1 the actor will use its
9136  * "normal" size request instead of overriding it, i.e.
9137  * you can "unset" the size with -1.
9138  *
9139  * This function sets or unsets both the minimum and natural size.
9140  */
9141 void
9142 clutter_actor_set_size (ClutterActor *self,
9143                         gfloat        width,
9144                         gfloat        height)
9145 {
9146   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9147
9148   g_object_freeze_notify (G_OBJECT (self));
9149
9150   clutter_actor_set_width (self, width);
9151   clutter_actor_set_height (self, height);
9152
9153   g_object_thaw_notify (G_OBJECT (self));
9154 }
9155
9156 /**
9157  * clutter_actor_get_size:
9158  * @self: A #ClutterActor
9159  * @width: (out) (allow-none): return location for the width, or %NULL.
9160  * @height: (out) (allow-none): return location for the height, or %NULL.
9161  *
9162  * This function tries to "do what you mean" and return
9163  * the size an actor will have. If the actor has a valid
9164  * allocation, the allocation will be returned; otherwise,
9165  * the actors natural size request will be returned.
9166  *
9167  * If you care whether you get the request vs. the allocation, you
9168  * should probably call a different function like
9169  * clutter_actor_get_allocation_box() or
9170  * clutter_actor_get_preferred_width().
9171  *
9172  * Since: 0.2
9173  */
9174 void
9175 clutter_actor_get_size (ClutterActor *self,
9176                         gfloat       *width,
9177                         gfloat       *height)
9178 {
9179   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9180
9181   if (width)
9182     *width = clutter_actor_get_width (self);
9183
9184   if (height)
9185     *height = clutter_actor_get_height (self);
9186 }
9187
9188 /**
9189  * clutter_actor_get_position:
9190  * @self: a #ClutterActor
9191  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9192  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9193  *
9194  * This function tries to "do what you mean" and tell you where the
9195  * actor is, prior to any transformations. Retrieves the fixed
9196  * position of an actor in pixels, if one has been set; otherwise, if
9197  * the allocation is valid, returns the actor's allocated position;
9198  * otherwise, returns 0,0.
9199  *
9200  * The returned position is in pixels.
9201  *
9202  * Since: 0.6
9203  */
9204 void
9205 clutter_actor_get_position (ClutterActor *self,
9206                             gfloat       *x,
9207                             gfloat       *y)
9208 {
9209   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9210
9211   if (x)
9212     *x = clutter_actor_get_x (self);
9213
9214   if (y)
9215     *y = clutter_actor_get_y (self);
9216 }
9217
9218 /**
9219  * clutter_actor_get_transformed_position:
9220  * @self: A #ClutterActor
9221  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9222  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9223  *
9224  * Gets the absolute position of an actor, in pixels relative to the stage.
9225  *
9226  * Since: 0.8
9227  */
9228 void
9229 clutter_actor_get_transformed_position (ClutterActor *self,
9230                                         gfloat       *x,
9231                                         gfloat       *y)
9232 {
9233   ClutterVertex v1;
9234   ClutterVertex v2;
9235
9236   v1.x = v1.y = v1.z = 0;
9237   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9238
9239   if (x)
9240     *x = v2.x;
9241
9242   if (y)
9243     *y = v2.y;
9244 }
9245
9246 /**
9247  * clutter_actor_get_transformed_size:
9248  * @self: A #ClutterActor
9249  * @width: (out) (allow-none): return location for the width, or %NULL
9250  * @height: (out) (allow-none): return location for the height, or %NULL
9251  *
9252  * Gets the absolute size of an actor in pixels, taking into account the
9253  * scaling factors.
9254  *
9255  * If the actor has a valid allocation, the allocated size will be used.
9256  * If the actor has not a valid allocation then the preferred size will
9257  * be transformed and returned.
9258  *
9259  * If you want the transformed allocation, see
9260  * clutter_actor_get_abs_allocation_vertices() instead.
9261  *
9262  * <note>When the actor (or one of its ancestors) is rotated around the
9263  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9264  * as a generic quadrangle; in that case this function returns the size
9265  * of the smallest rectangle that encapsulates the entire quad. Please
9266  * note that in this case no assumptions can be made about the relative
9267  * position of this envelope to the absolute position of the actor, as
9268  * returned by clutter_actor_get_transformed_position(); if you need this
9269  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9270  * to get the coords of the actual quadrangle.</note>
9271  *
9272  * Since: 0.8
9273  */
9274 void
9275 clutter_actor_get_transformed_size (ClutterActor *self,
9276                                     gfloat       *width,
9277                                     gfloat       *height)
9278 {
9279   ClutterActorPrivate *priv;
9280   ClutterVertex v[4];
9281   gfloat x_min, x_max, y_min, y_max;
9282   gint i;
9283
9284   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9285
9286   priv = self->priv;
9287
9288   /* if the actor hasn't been allocated yet, get the preferred
9289    * size and transform that
9290    */
9291   if (priv->needs_allocation)
9292     {
9293       gfloat natural_width, natural_height;
9294       ClutterActorBox box;
9295
9296       /* Make a fake allocation to transform.
9297        *
9298        * NB: _clutter_actor_transform_and_project_box expects a box in
9299        * the actor's coordinate space... */
9300
9301       box.x1 = 0;
9302       box.y1 = 0;
9303
9304       natural_width = natural_height = 0;
9305       clutter_actor_get_preferred_size (self, NULL, NULL,
9306                                         &natural_width,
9307                                         &natural_height);
9308
9309       box.x2 = natural_width;
9310       box.y2 = natural_height;
9311
9312       _clutter_actor_transform_and_project_box (self, &box, v);
9313     }
9314   else
9315     clutter_actor_get_abs_allocation_vertices (self, v);
9316
9317   x_min = x_max = v[0].x;
9318   y_min = y_max = v[0].y;
9319
9320   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9321     {
9322       if (v[i].x < x_min)
9323         x_min = v[i].x;
9324
9325       if (v[i].x > x_max)
9326         x_max = v[i].x;
9327
9328       if (v[i].y < y_min)
9329         y_min = v[i].y;
9330
9331       if (v[i].y > y_max)
9332         y_max = v[i].y;
9333     }
9334
9335   if (width)
9336     *width  = x_max - x_min;
9337
9338   if (height)
9339     *height = y_max - y_min;
9340 }
9341
9342 /**
9343  * clutter_actor_get_width:
9344  * @self: A #ClutterActor
9345  *
9346  * Retrieves the width of a #ClutterActor.
9347  *
9348  * If the actor has a valid allocation, this function will return the
9349  * width of the allocated area given to the actor.
9350  *
9351  * If the actor does not have a valid allocation, this function will
9352  * return the actor's natural width, that is the preferred width of
9353  * the actor.
9354  *
9355  * If you care whether you get the preferred width or the width that
9356  * has been assigned to the actor, you should probably call a different
9357  * function like clutter_actor_get_allocation_box() to retrieve the
9358  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9359  * preferred width.
9360  *
9361  * If an actor has a fixed width, for instance a width that has been
9362  * assigned using clutter_actor_set_width(), the width returned will
9363  * be the same value.
9364  *
9365  * Return value: the width of the actor, in pixels
9366  */
9367 gfloat
9368 clutter_actor_get_width (ClutterActor *self)
9369 {
9370   ClutterActorPrivate *priv;
9371
9372   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9373
9374   priv = self->priv;
9375
9376   if (priv->needs_allocation)
9377     {
9378       gfloat natural_width = 0;
9379
9380       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9381         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9382       else
9383         {
9384           gfloat natural_height = 0;
9385
9386           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9387           clutter_actor_get_preferred_width (self, natural_height,
9388                                              NULL,
9389                                              &natural_width);
9390         }
9391
9392       return natural_width;
9393     }
9394   else
9395     return priv->allocation.x2 - priv->allocation.x1;
9396 }
9397
9398 /**
9399  * clutter_actor_get_height:
9400  * @self: A #ClutterActor
9401  *
9402  * Retrieves the height of a #ClutterActor.
9403  *
9404  * If the actor has a valid allocation, this function will return the
9405  * height of the allocated area given to the actor.
9406  *
9407  * If the actor does not have a valid allocation, this function will
9408  * return the actor's natural height, that is the preferred height of
9409  * the actor.
9410  *
9411  * If you care whether you get the preferred height or the height that
9412  * has been assigned to the actor, you should probably call a different
9413  * function like clutter_actor_get_allocation_box() to retrieve the
9414  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9415  * preferred height.
9416  *
9417  * If an actor has a fixed height, for instance a height that has been
9418  * assigned using clutter_actor_set_height(), the height returned will
9419  * be the same value.
9420  *
9421  * Return value: the height of the actor, in pixels
9422  */
9423 gfloat
9424 clutter_actor_get_height (ClutterActor *self)
9425 {
9426   ClutterActorPrivate *priv;
9427
9428   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9429
9430   priv = self->priv;
9431
9432   if (priv->needs_allocation)
9433     {
9434       gfloat natural_height = 0;
9435
9436       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9437         {
9438           gfloat natural_width = 0;
9439
9440           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9441           clutter_actor_get_preferred_height (self, natural_width,
9442                                               NULL, &natural_height);
9443         }
9444       else
9445         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9446
9447       return natural_height;
9448     }
9449   else
9450     return priv->allocation.y2 - priv->allocation.y1;
9451 }
9452
9453 /**
9454  * clutter_actor_set_width:
9455  * @self: A #ClutterActor
9456  * @width: Requested new width for the actor, in pixels, or -1
9457  *
9458  * Forces a width on an actor, causing the actor's preferred width
9459  * and height (if any) to be ignored.
9460  *
9461  * If @width is -1 the actor will use its preferred width request
9462  * instead of overriding it, i.e. you can "unset" the width with -1.
9463  *
9464  * This function sets both the minimum and natural size of the actor.
9465  *
9466  * since: 0.2
9467  */
9468 void
9469 clutter_actor_set_width (ClutterActor *self,
9470                          gfloat        width)
9471 {
9472   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9473
9474   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9475     {
9476       float cur_size = clutter_actor_get_width (self);
9477
9478       _clutter_actor_create_transition (self,
9479                                         obj_props[PROP_WIDTH],
9480                                         cur_size,
9481                                         width);
9482     }
9483   else
9484     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9485
9486   clutter_actor_queue_relayout (self);
9487 }
9488
9489 /**
9490  * clutter_actor_set_height:
9491  * @self: A #ClutterActor
9492  * @height: Requested new height for the actor, in pixels, or -1
9493  *
9494  * Forces a height on an actor, causing the actor's preferred width
9495  * and height (if any) to be ignored.
9496  *
9497  * If @height is -1 the actor will use its preferred height instead of
9498  * overriding it, i.e. you can "unset" the height with -1.
9499  *
9500  * This function sets both the minimum and natural size of the actor.
9501  *
9502  * since: 0.2
9503  */
9504 void
9505 clutter_actor_set_height (ClutterActor *self,
9506                           gfloat        height)
9507 {
9508   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9509
9510   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9511     {
9512       float cur_size = clutter_actor_get_height (self);
9513
9514       _clutter_actor_create_transition (self,
9515                                         obj_props[PROP_HEIGHT],
9516                                         cur_size,
9517                                         height);
9518     }
9519   else
9520     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9521
9522   clutter_actor_queue_relayout (self);
9523 }
9524
9525 static inline void
9526 clutter_actor_set_x_internal (ClutterActor *self,
9527                               float         x)
9528 {
9529   ClutterActorPrivate *priv = self->priv;
9530   ClutterLayoutInfo *linfo;
9531   ClutterActorBox old = { 0, };
9532
9533   linfo = _clutter_actor_get_layout_info (self);
9534
9535   if (priv->position_set && linfo->fixed_x == x)
9536     return;
9537
9538   clutter_actor_store_old_geometry (self, &old);
9539
9540   linfo->fixed_x = x;
9541   clutter_actor_set_fixed_position_set (self, TRUE);
9542
9543   clutter_actor_notify_if_geometry_changed (self, &old);
9544
9545   clutter_actor_queue_relayout (self);
9546 }
9547
9548 static inline void
9549 clutter_actor_set_y_internal (ClutterActor *self,
9550                               float         y)
9551 {
9552   ClutterActorPrivate *priv = self->priv;
9553   ClutterLayoutInfo *linfo;
9554   ClutterActorBox old = { 0, };
9555
9556   linfo = _clutter_actor_get_layout_info (self);
9557
9558   if (priv->position_set && linfo->fixed_y == y)
9559     return;
9560
9561   clutter_actor_store_old_geometry (self, &old);
9562
9563   linfo->fixed_y = y;
9564   clutter_actor_set_fixed_position_set (self, TRUE);
9565
9566   clutter_actor_notify_if_geometry_changed (self, &old);
9567
9568   clutter_actor_queue_relayout (self);
9569 }
9570
9571 /**
9572  * clutter_actor_set_x:
9573  * @self: a #ClutterActor
9574  * @x: the actor's position on the X axis
9575  *
9576  * Sets the actor's X coordinate, relative to its parent, in pixels.
9577  *
9578  * Overrides any layout manager and forces a fixed position for
9579  * the actor.
9580  *
9581  * The #ClutterActor:x property is animatable.
9582  *
9583  * Since: 0.6
9584  */
9585 void
9586 clutter_actor_set_x (ClutterActor *self,
9587                      gfloat        x)
9588 {
9589   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9590
9591   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9592     {
9593       float cur_position = clutter_actor_get_x (self);
9594
9595       _clutter_actor_create_transition (self, obj_props[PROP_X],
9596                                         cur_position,
9597                                         x);
9598     }
9599   else
9600     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9601
9602   clutter_actor_queue_relayout (self);
9603 }
9604
9605 /**
9606  * clutter_actor_set_y:
9607  * @self: a #ClutterActor
9608  * @y: the actor's position on the Y axis
9609  *
9610  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9611  *
9612  * Overrides any layout manager and forces a fixed position for
9613  * the actor.
9614  *
9615  * The #ClutterActor:y property is animatable.
9616  *
9617  * Since: 0.6
9618  */
9619 void
9620 clutter_actor_set_y (ClutterActor *self,
9621                      gfloat        y)
9622 {
9623   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9624
9625   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9626     {
9627       float cur_position = clutter_actor_get_y (self);
9628
9629       _clutter_actor_create_transition (self, obj_props[PROP_Y],
9630                                         cur_position,
9631                                         y);
9632     }
9633   else
9634     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9635
9636   clutter_actor_queue_relayout (self);
9637 }
9638
9639 /**
9640  * clutter_actor_get_x:
9641  * @self: A #ClutterActor
9642  *
9643  * Retrieves the X coordinate of a #ClutterActor.
9644  *
9645  * This function tries to "do what you mean", by returning the
9646  * correct value depending on the actor's state.
9647  *
9648  * If the actor has a valid allocation, this function will return
9649  * the X coordinate of the origin of the allocation box.
9650  *
9651  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9652  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9653  * function will return that coordinate.
9654  *
9655  * If both the allocation and a fixed position are missing, this function
9656  * will return 0.
9657  *
9658  * Return value: the X coordinate, in pixels, ignoring any
9659  *   transformation (i.e. scaling, rotation)
9660  */
9661 gfloat
9662 clutter_actor_get_x (ClutterActor *self)
9663 {
9664   ClutterActorPrivate *priv;
9665
9666   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9667
9668   priv = self->priv;
9669
9670   if (priv->needs_allocation)
9671     {
9672       if (priv->position_set)
9673         {
9674           const ClutterLayoutInfo *info;
9675
9676           info = _clutter_actor_get_layout_info_or_defaults (self);
9677
9678           return info->fixed_x;
9679         }
9680       else
9681         return 0;
9682     }
9683   else
9684     return priv->allocation.x1;
9685 }
9686
9687 /**
9688  * clutter_actor_get_y:
9689  * @self: A #ClutterActor
9690  *
9691  * Retrieves the Y coordinate of a #ClutterActor.
9692  *
9693  * This function tries to "do what you mean", by returning the
9694  * correct value depending on the actor's state.
9695  *
9696  * If the actor has a valid allocation, this function will return
9697  * the Y coordinate of the origin of the allocation box.
9698  *
9699  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9700  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9701  * function will return that coordinate.
9702  *
9703  * If both the allocation and a fixed position are missing, this function
9704  * will return 0.
9705  *
9706  * Return value: the Y coordinate, in pixels, ignoring any
9707  *   transformation (i.e. scaling, rotation)
9708  */
9709 gfloat
9710 clutter_actor_get_y (ClutterActor *self)
9711 {
9712   ClutterActorPrivate *priv;
9713
9714   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9715
9716   priv = self->priv;
9717
9718   if (priv->needs_allocation)
9719     {
9720       if (priv->position_set)
9721         {
9722           const ClutterLayoutInfo *info;
9723
9724           info = _clutter_actor_get_layout_info_or_defaults (self);
9725
9726           return info->fixed_y;
9727         }
9728       else
9729         return 0;
9730     }
9731   else
9732     return priv->allocation.y1;
9733 }
9734
9735 /**
9736  * clutter_actor_set_scale:
9737  * @self: A #ClutterActor
9738  * @scale_x: double factor to scale actor by horizontally.
9739  * @scale_y: double factor to scale actor by vertically.
9740  *
9741  * Scales an actor with the given factors. The scaling is relative to
9742  * the scale center and the anchor point. The scale center is
9743  * unchanged by this function and defaults to 0,0.
9744  *
9745  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9746  * animatable.
9747  *
9748  * Since: 0.2
9749  */
9750 void
9751 clutter_actor_set_scale (ClutterActor *self,
9752                          gdouble       scale_x,
9753                          gdouble       scale_y)
9754 {
9755   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9756
9757   g_object_freeze_notify (G_OBJECT (self));
9758
9759   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9760   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9761
9762   g_object_thaw_notify (G_OBJECT (self));
9763 }
9764
9765 /**
9766  * clutter_actor_set_scale_full:
9767  * @self: A #ClutterActor
9768  * @scale_x: double factor to scale actor by horizontally.
9769  * @scale_y: double factor to scale actor by vertically.
9770  * @center_x: X coordinate of the center of the scale.
9771  * @center_y: Y coordinate of the center of the scale
9772  *
9773  * Scales an actor with the given factors around the given center
9774  * point. The center point is specified in pixels relative to the
9775  * anchor point (usually the top left corner of the actor).
9776  *
9777  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9778  * are animatable.
9779  *
9780  * Since: 1.0
9781  */
9782 void
9783 clutter_actor_set_scale_full (ClutterActor *self,
9784                               gdouble       scale_x,
9785                               gdouble       scale_y,
9786                               gfloat        center_x,
9787                               gfloat        center_y)
9788 {
9789   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9790
9791   g_object_freeze_notify (G_OBJECT (self));
9792
9793   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9794   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9795   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9796   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9797
9798   g_object_thaw_notify (G_OBJECT (self));
9799 }
9800
9801 /**
9802  * clutter_actor_set_scale_with_gravity:
9803  * @self: A #ClutterActor
9804  * @scale_x: double factor to scale actor by horizontally.
9805  * @scale_y: double factor to scale actor by vertically.
9806  * @gravity: the location of the scale center expressed as a compass
9807  * direction.
9808  *
9809  * Scales an actor with the given factors around the given
9810  * center point. The center point is specified as one of the compass
9811  * directions in #ClutterGravity. For example, setting it to north
9812  * will cause the top of the actor to remain unchanged and the rest of
9813  * the actor to expand left, right and downwards.
9814  *
9815  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9816  * animatable.
9817  *
9818  * Since: 1.0
9819  */
9820 void
9821 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9822                                       gdouble         scale_x,
9823                                       gdouble         scale_y,
9824                                       ClutterGravity  gravity)
9825 {
9826   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9827
9828   g_object_freeze_notify (G_OBJECT (self));
9829
9830   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9831   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9832   clutter_actor_set_scale_gravity (self, gravity);
9833
9834   g_object_thaw_notify (G_OBJECT (self));
9835 }
9836
9837 /**
9838  * clutter_actor_get_scale:
9839  * @self: A #ClutterActor
9840  * @scale_x: (out) (allow-none): Location to store horizonal
9841  *   scale factor, or %NULL.
9842  * @scale_y: (out) (allow-none): Location to store vertical
9843  *   scale factor, or %NULL.
9844  *
9845  * Retrieves an actors scale factors.
9846  *
9847  * Since: 0.2
9848  */
9849 void
9850 clutter_actor_get_scale (ClutterActor *self,
9851                          gdouble      *scale_x,
9852                          gdouble      *scale_y)
9853 {
9854   const ClutterTransformInfo *info;
9855
9856   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9857
9858   info = _clutter_actor_get_transform_info_or_defaults (self);
9859
9860   if (scale_x)
9861     *scale_x = info->scale_x;
9862
9863   if (scale_y)
9864     *scale_y = info->scale_y;
9865 }
9866
9867 /**
9868  * clutter_actor_get_scale_center:
9869  * @self: A #ClutterActor
9870  * @center_x: (out) (allow-none): Location to store the X position
9871  *   of the scale center, or %NULL.
9872  * @center_y: (out) (allow-none): Location to store the Y position
9873  *   of the scale center, or %NULL.
9874  *
9875  * Retrieves the scale center coordinate in pixels relative to the top
9876  * left corner of the actor. If the scale center was specified using a
9877  * #ClutterGravity this will calculate the pixel offset using the
9878  * current size of the actor.
9879  *
9880  * Since: 1.0
9881  */
9882 void
9883 clutter_actor_get_scale_center (ClutterActor *self,
9884                                 gfloat       *center_x,
9885                                 gfloat       *center_y)
9886 {
9887   const ClutterTransformInfo *info;
9888
9889   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9890
9891   info = _clutter_actor_get_transform_info_or_defaults (self);
9892
9893   clutter_anchor_coord_get_units (self, &info->scale_center,
9894                                   center_x,
9895                                   center_y,
9896                                   NULL);
9897 }
9898
9899 /**
9900  * clutter_actor_get_scale_gravity:
9901  * @self: A #ClutterActor
9902  *
9903  * Retrieves the scale center as a compass direction. If the scale
9904  * center was specified in pixels or units this will return
9905  * %CLUTTER_GRAVITY_NONE.
9906  *
9907  * Return value: the scale gravity
9908  *
9909  * Since: 1.0
9910  */
9911 ClutterGravity
9912 clutter_actor_get_scale_gravity (ClutterActor *self)
9913 {
9914   const ClutterTransformInfo *info;
9915
9916   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9917
9918   info = _clutter_actor_get_transform_info_or_defaults (self);
9919
9920   return clutter_anchor_coord_get_gravity (&info->scale_center);
9921 }
9922
9923 static inline void
9924 clutter_actor_set_opacity_internal (ClutterActor *self,
9925                                     guint8        opacity)
9926 {
9927   ClutterActorPrivate *priv = self->priv;
9928
9929   if (priv->opacity != opacity)
9930     {
9931       priv->opacity = opacity;
9932
9933       /* Queue a redraw from the flatten effect so that it can use
9934          its cached image if available instead of having to redraw the
9935          actual actor. If it doesn't end up using the FBO then the
9936          effect is still able to continue the paint anyway. If there
9937          is no flatten effect yet then this is equivalent to queueing
9938          a full redraw */
9939       _clutter_actor_queue_redraw_full (self,
9940                                         0, /* flags */
9941                                         NULL, /* clip */
9942                                         priv->flatten_effect);
9943
9944       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9945     }
9946 }
9947
9948 /**
9949  * clutter_actor_set_opacity:
9950  * @self: A #ClutterActor
9951  * @opacity: New opacity value for the actor.
9952  *
9953  * Sets the actor's opacity, with zero being completely transparent and
9954  * 255 (0xff) being fully opaque.
9955  *
9956  * The #ClutterActor:opacity property is animatable.
9957  */
9958 void
9959 clutter_actor_set_opacity (ClutterActor *self,
9960                            guint8        opacity)
9961 {
9962   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9963
9964   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
9965     {
9966       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
9967                                         self->priv->opacity,
9968                                         opacity);
9969     }
9970   else
9971     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9972
9973   clutter_actor_queue_redraw (self);
9974 }
9975
9976 /*
9977  * clutter_actor_get_paint_opacity_internal:
9978  * @self: a #ClutterActor
9979  *
9980  * Retrieves the absolute opacity of the actor, as it appears on the stage
9981  *
9982  * This function does not do type checks
9983  *
9984  * Return value: the absolute opacity of the actor
9985  */
9986 static guint8
9987 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9988 {
9989   ClutterActorPrivate *priv = self->priv;
9990   ClutterActor *parent;
9991
9992   /* override the top-level opacity to always be 255; even in
9993    * case of ClutterStage:use-alpha being TRUE we want the rest
9994    * of the scene to be painted
9995    */
9996   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9997     return 255;
9998
9999   if (priv->opacity_override >= 0)
10000     return priv->opacity_override;
10001
10002   parent = priv->parent;
10003
10004   /* Factor in the actual actors opacity with parents */
10005   if (parent != NULL)
10006     {
10007       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10008
10009       if (opacity != 0xff)
10010         return (opacity * priv->opacity) / 0xff;
10011     }
10012
10013   return priv->opacity;
10014
10015 }
10016
10017 /**
10018  * clutter_actor_get_paint_opacity:
10019  * @self: A #ClutterActor
10020  *
10021  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10022  *
10023  * This function traverses the hierarchy chain and composites the opacity of
10024  * the actor with that of its parents.
10025  *
10026  * This function is intended for subclasses to use in the paint virtual
10027  * function, to paint themselves with the correct opacity.
10028  *
10029  * Return value: The actor opacity value.
10030  *
10031  * Since: 0.8
10032  */
10033 guint8
10034 clutter_actor_get_paint_opacity (ClutterActor *self)
10035 {
10036   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10037
10038   return clutter_actor_get_paint_opacity_internal (self);
10039 }
10040
10041 /**
10042  * clutter_actor_get_opacity:
10043  * @self: a #ClutterActor
10044  *
10045  * Retrieves the opacity value of an actor, as set by
10046  * clutter_actor_set_opacity().
10047  *
10048  * For retrieving the absolute opacity of the actor inside a paint
10049  * virtual function, see clutter_actor_get_paint_opacity().
10050  *
10051  * Return value: the opacity of the actor
10052  */
10053 guint8
10054 clutter_actor_get_opacity (ClutterActor *self)
10055 {
10056   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10057
10058   return self->priv->opacity;
10059 }
10060
10061 /**
10062  * clutter_actor_set_offscreen_redirect:
10063  * @self: A #ClutterActor
10064  * @redirect: New offscreen redirect flags for the actor.
10065  *
10066  * Defines the circumstances where the actor should be redirected into
10067  * an offscreen image. The offscreen image is used to flatten the
10068  * actor into a single image while painting for two main reasons.
10069  * Firstly, when the actor is painted a second time without any of its
10070  * contents changing it can simply repaint the cached image without
10071  * descending further down the actor hierarchy. Secondly, it will make
10072  * the opacity look correct even if there are overlapping primitives
10073  * in the actor.
10074  *
10075  * Caching the actor could in some cases be a performance win and in
10076  * some cases be a performance lose so it is important to determine
10077  * which value is right for an actor before modifying this value. For
10078  * example, there is never any reason to flatten an actor that is just
10079  * a single texture (such as a #ClutterTexture) because it is
10080  * effectively already cached in an image so the offscreen would be
10081  * redundant. Also if the actor contains primitives that are far apart
10082  * with a large transparent area in the middle (such as a large
10083  * CluterGroup with a small actor in the top left and a small actor in
10084  * the bottom right) then the cached image will contain the entire
10085  * image of the large area and the paint will waste time blending all
10086  * of the transparent pixels in the middle.
10087  *
10088  * The default method of implementing opacity on a container simply
10089  * forwards on the opacity to all of the children. If the children are
10090  * overlapping then it will appear as if they are two separate glassy
10091  * objects and there will be a break in the color where they
10092  * overlap. By redirecting to an offscreen buffer it will be as if the
10093  * two opaque objects are combined into one and then made transparent
10094  * which is usually what is expected.
10095  *
10096  * The image below demonstrates the difference between redirecting and
10097  * not. The image shows two Clutter groups, each containing a red and
10098  * a green rectangle which overlap. The opacity on the group is set to
10099  * 128 (which is 50%). When the offscreen redirect is not used, the
10100  * red rectangle can be seen through the blue rectangle as if the two
10101  * rectangles were separately transparent. When the redirect is used
10102  * the group as a whole is transparent instead so the red rectangle is
10103  * not visible where they overlap.
10104  *
10105  * <figure id="offscreen-redirect">
10106  *   <title>Sample of using an offscreen redirect for transparency</title>
10107  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10108  * </figure>
10109  *
10110  * The default value for this property is 0, so we effectively will
10111  * never redirect an actor offscreen by default. This means that there
10112  * are times that transparent actors may look glassy as described
10113  * above. The reason this is the default is because there is a
10114  * performance trade off between quality and performance here. In many
10115  * cases the default form of glassy opacity looks good enough, but if
10116  * it's not you will need to set the
10117  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10118  * redirection for opacity.
10119  *
10120  * Custom actors that don't contain any overlapping primitives are
10121  * recommended to override the has_overlaps() virtual to return %FALSE
10122  * for maximum efficiency.
10123  *
10124  * Since: 1.8
10125  */
10126 void
10127 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10128                                       ClutterOffscreenRedirect redirect)
10129 {
10130   ClutterActorPrivate *priv;
10131
10132   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10133
10134   priv = self->priv;
10135
10136   if (priv->offscreen_redirect != redirect)
10137     {
10138       priv->offscreen_redirect = redirect;
10139
10140       /* Queue a redraw from the effect so that it can use its cached
10141          image if available instead of having to redraw the actual
10142          actor. If it doesn't end up using the FBO then the effect is
10143          still able to continue the paint anyway. If there is no
10144          effect then this is equivalent to queuing a full redraw */
10145       _clutter_actor_queue_redraw_full (self,
10146                                         0, /* flags */
10147                                         NULL, /* clip */
10148                                         priv->flatten_effect);
10149
10150       g_object_notify_by_pspec (G_OBJECT (self),
10151                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10152     }
10153 }
10154
10155 /**
10156  * clutter_actor_get_offscreen_redirect:
10157  * @self: a #ClutterActor
10158  *
10159  * Retrieves whether to redirect the actor to an offscreen buffer, as
10160  * set by clutter_actor_set_offscreen_redirect().
10161  *
10162  * Return value: the value of the offscreen-redirect property of the actor
10163  *
10164  * Since: 1.8
10165  */
10166 ClutterOffscreenRedirect
10167 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10168 {
10169   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10170
10171   return self->priv->offscreen_redirect;
10172 }
10173
10174 /**
10175  * clutter_actor_set_name:
10176  * @self: A #ClutterActor
10177  * @name: Textual tag to apply to actor
10178  *
10179  * Sets the given name to @self. The name can be used to identify
10180  * a #ClutterActor.
10181  */
10182 void
10183 clutter_actor_set_name (ClutterActor *self,
10184                         const gchar  *name)
10185 {
10186   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10187
10188   g_free (self->priv->name);
10189   self->priv->name = g_strdup (name);
10190
10191   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10192 }
10193
10194 /**
10195  * clutter_actor_get_name:
10196  * @self: A #ClutterActor
10197  *
10198  * Retrieves the name of @self.
10199  *
10200  * Return value: the name of the actor, or %NULL. The returned string is
10201  *   owned by the actor and should not be modified or freed.
10202  */
10203 const gchar *
10204 clutter_actor_get_name (ClutterActor *self)
10205 {
10206   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10207
10208   return self->priv->name;
10209 }
10210
10211 /**
10212  * clutter_actor_get_gid:
10213  * @self: A #ClutterActor
10214  *
10215  * Retrieves the unique id for @self.
10216  *
10217  * Return value: Globally unique value for this object instance.
10218  *
10219  * Since: 0.6
10220  *
10221  * Deprecated: 1.8: The id is not used any longer.
10222  */
10223 guint32
10224 clutter_actor_get_gid (ClutterActor *self)
10225 {
10226   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10227
10228   return self->priv->id;
10229 }
10230
10231 static inline void
10232 clutter_actor_set_depth_internal (ClutterActor *self,
10233                                   float         depth)
10234 {
10235   ClutterTransformInfo *info;
10236
10237   info = _clutter_actor_get_transform_info (self);
10238
10239   if (info->depth != depth)
10240     {
10241       /* Sets Z value - XXX 2.0: should we invert? */
10242       info->depth = depth;
10243
10244       self->priv->transform_valid = FALSE;
10245
10246       /* FIXME - remove this crap; sadly, there are still containers
10247        * in Clutter that depend on this utter brain damage
10248        */
10249       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10250
10251       clutter_actor_queue_redraw (self);
10252
10253       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10254     }
10255 }
10256
10257 /**
10258  * clutter_actor_set_depth:
10259  * @self: a #ClutterActor
10260  * @depth: Z co-ord
10261  *
10262  * Sets the Z coordinate of @self to @depth.
10263  *
10264  * The unit used by @depth is dependant on the perspective setup. See
10265  * also clutter_stage_set_perspective().
10266  */
10267 void
10268 clutter_actor_set_depth (ClutterActor *self,
10269                          gfloat        depth)
10270 {
10271   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10272
10273   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10274     {
10275       const ClutterTransformInfo *info;
10276
10277       info = _clutter_actor_get_transform_info_or_defaults (self);
10278
10279       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10280                                         info->depth,
10281                                         depth);
10282     }
10283   else
10284     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10285
10286   clutter_actor_queue_redraw (self);
10287 }
10288
10289 /**
10290  * clutter_actor_get_depth:
10291  * @self: a #ClutterActor
10292  *
10293  * Retrieves the depth of @self.
10294  *
10295  * Return value: the depth of the actor
10296  */
10297 gfloat
10298 clutter_actor_get_depth (ClutterActor *self)
10299 {
10300   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10301
10302   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10303 }
10304
10305 /**
10306  * clutter_actor_set_rotation:
10307  * @self: a #ClutterActor
10308  * @axis: the axis of rotation
10309  * @angle: the angle of rotation
10310  * @x: X coordinate of the rotation center
10311  * @y: Y coordinate of the rotation center
10312  * @z: Z coordinate of the rotation center
10313  *
10314  * Sets the rotation angle of @self around the given axis.
10315  *
10316  * The rotation center coordinates used depend on the value of @axis:
10317  * <itemizedlist>
10318  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10319  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10320  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10321  * </itemizedlist>
10322  *
10323  * The rotation coordinates are relative to the anchor point of the
10324  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10325  * point is set, the upper left corner is assumed as the origin.
10326  *
10327  * Since: 0.8
10328  */
10329 void
10330 clutter_actor_set_rotation (ClutterActor      *self,
10331                             ClutterRotateAxis  axis,
10332                             gdouble            angle,
10333                             gfloat             x,
10334                             gfloat             y,
10335                             gfloat             z)
10336 {
10337   ClutterVertex v;
10338
10339   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10340
10341   v.x = x;
10342   v.y = y;
10343   v.z = z;
10344
10345   g_object_freeze_notify (G_OBJECT (self));
10346
10347   clutter_actor_set_rotation_angle (self, axis, angle);
10348   clutter_actor_set_rotation_center_internal (self, axis, &v);
10349
10350   g_object_thaw_notify (G_OBJECT (self));
10351 }
10352
10353 /**
10354  * clutter_actor_set_z_rotation_from_gravity:
10355  * @self: a #ClutterActor
10356  * @angle: the angle of rotation
10357  * @gravity: the center point of the rotation
10358  *
10359  * Sets the rotation angle of @self around the Z axis using the center
10360  * point specified as a compass point. For example to rotate such that
10361  * the center of the actor remains static you can use
10362  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10363  * will move accordingly.
10364  *
10365  * Since: 1.0
10366  */
10367 void
10368 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10369                                            gdouble         angle,
10370                                            ClutterGravity  gravity)
10371 {
10372   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10373
10374   if (gravity == CLUTTER_GRAVITY_NONE)
10375     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10376   else
10377     {
10378       GObject *obj = G_OBJECT (self);
10379       ClutterTransformInfo *info;
10380
10381       info = _clutter_actor_get_transform_info (self);
10382
10383       g_object_freeze_notify (obj);
10384
10385       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10386
10387       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10388       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10389       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10390
10391       g_object_thaw_notify (obj);
10392     }
10393 }
10394
10395 /**
10396  * clutter_actor_get_rotation:
10397  * @self: a #ClutterActor
10398  * @axis: the axis of rotation
10399  * @x: (out): return value for the X coordinate of the center of rotation
10400  * @y: (out): return value for the Y coordinate of the center of rotation
10401  * @z: (out): return value for the Z coordinate of the center of rotation
10402  *
10403  * Retrieves the angle and center of rotation on the given axis,
10404  * set using clutter_actor_set_rotation().
10405  *
10406  * Return value: the angle of rotation
10407  *
10408  * Since: 0.8
10409  */
10410 gdouble
10411 clutter_actor_get_rotation (ClutterActor      *self,
10412                             ClutterRotateAxis  axis,
10413                             gfloat            *x,
10414                             gfloat            *y,
10415                             gfloat            *z)
10416 {
10417   const ClutterTransformInfo *info;
10418   const AnchorCoord *anchor_coord;
10419   gdouble retval = 0;
10420
10421   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10422
10423   info = _clutter_actor_get_transform_info_or_defaults (self);
10424
10425   switch (axis)
10426     {
10427     case CLUTTER_X_AXIS:
10428       anchor_coord = &info->rx_center;
10429       retval = info->rx_angle;
10430       break;
10431
10432     case CLUTTER_Y_AXIS:
10433       anchor_coord = &info->ry_center;
10434       retval = info->ry_angle;
10435       break;
10436
10437     case CLUTTER_Z_AXIS:
10438       anchor_coord = &info->rz_center;
10439       retval = info->rz_angle;
10440       break;
10441
10442     default:
10443       anchor_coord = NULL;
10444       retval = 0.0;
10445       break;
10446     }
10447
10448   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10449
10450   return retval;
10451 }
10452
10453 /**
10454  * clutter_actor_get_z_rotation_gravity:
10455  * @self: A #ClutterActor
10456  *
10457  * Retrieves the center for the rotation around the Z axis as a
10458  * compass direction. If the center was specified in pixels or units
10459  * this will return %CLUTTER_GRAVITY_NONE.
10460  *
10461  * Return value: the Z rotation center
10462  *
10463  * Since: 1.0
10464  */
10465 ClutterGravity
10466 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10467 {
10468   const ClutterTransformInfo *info;
10469
10470   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10471
10472   info = _clutter_actor_get_transform_info_or_defaults (self);
10473
10474   return clutter_anchor_coord_get_gravity (&info->rz_center);
10475 }
10476
10477 /**
10478  * clutter_actor_set_clip:
10479  * @self: A #ClutterActor
10480  * @xoff: X offset of the clip rectangle
10481  * @yoff: Y offset of the clip rectangle
10482  * @width: Width of the clip rectangle
10483  * @height: Height of the clip rectangle
10484  *
10485  * Sets clip area for @self. The clip area is always computed from the
10486  * upper left corner of the actor, even if the anchor point is set
10487  * otherwise.
10488  *
10489  * Since: 0.6
10490  */
10491 void
10492 clutter_actor_set_clip (ClutterActor *self,
10493                         gfloat        xoff,
10494                         gfloat        yoff,
10495                         gfloat        width,
10496                         gfloat        height)
10497 {
10498   ClutterActorPrivate *priv;
10499
10500   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10501
10502   priv = self->priv;
10503
10504   if (priv->has_clip &&
10505       priv->clip.x == xoff &&
10506       priv->clip.y == yoff &&
10507       priv->clip.width == width &&
10508       priv->clip.height == height)
10509     return;
10510
10511   priv->clip.x = xoff;
10512   priv->clip.y = yoff;
10513   priv->clip.width = width;
10514   priv->clip.height = height;
10515
10516   priv->has_clip = TRUE;
10517
10518   clutter_actor_queue_redraw (self);
10519
10520   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10521   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10522 }
10523
10524 /**
10525  * clutter_actor_remove_clip:
10526  * @self: A #ClutterActor
10527  *
10528  * Removes clip area from @self.
10529  */
10530 void
10531 clutter_actor_remove_clip (ClutterActor *self)
10532 {
10533   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10534
10535   if (!self->priv->has_clip)
10536     return;
10537
10538   self->priv->has_clip = FALSE;
10539
10540   clutter_actor_queue_redraw (self);
10541
10542   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10543 }
10544
10545 /**
10546  * clutter_actor_has_clip:
10547  * @self: a #ClutterActor
10548  *
10549  * Determines whether the actor has a clip area set or not.
10550  *
10551  * Return value: %TRUE if the actor has a clip area set.
10552  *
10553  * Since: 0.1.1
10554  */
10555 gboolean
10556 clutter_actor_has_clip (ClutterActor *self)
10557 {
10558   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10559
10560   return self->priv->has_clip;
10561 }
10562
10563 /**
10564  * clutter_actor_get_clip:
10565  * @self: a #ClutterActor
10566  * @xoff: (out) (allow-none): return location for the X offset of
10567  *   the clip rectangle, or %NULL
10568  * @yoff: (out) (allow-none): return location for the Y offset of
10569  *   the clip rectangle, or %NULL
10570  * @width: (out) (allow-none): return location for the width of
10571  *   the clip rectangle, or %NULL
10572  * @height: (out) (allow-none): return location for the height of
10573  *   the clip rectangle, or %NULL
10574  *
10575  * Gets the clip area for @self, if any is set
10576  *
10577  * Since: 0.6
10578  */
10579 void
10580 clutter_actor_get_clip (ClutterActor *self,
10581                         gfloat       *xoff,
10582                         gfloat       *yoff,
10583                         gfloat       *width,
10584                         gfloat       *height)
10585 {
10586   ClutterActorPrivate *priv;
10587
10588   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10589
10590   priv = self->priv;
10591
10592   if (!priv->has_clip)
10593     return;
10594
10595   if (xoff != NULL)
10596     *xoff = priv->clip.x;
10597
10598   if (yoff != NULL)
10599     *yoff = priv->clip.y;
10600
10601   if (width != NULL)
10602     *width = priv->clip.width;
10603
10604   if (height != NULL)
10605     *height = priv->clip.height;
10606 }
10607
10608 /**
10609  * clutter_actor_get_children:
10610  * @self: a #ClutterActor
10611  *
10612  * Retrieves the list of children of @self.
10613  *
10614  * Return value: (transfer container) (element-type ClutterActor): A newly
10615  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10616  *   done.
10617  *
10618  * Since: 1.10
10619  */
10620 GList *
10621 clutter_actor_get_children (ClutterActor *self)
10622 {
10623   ClutterActor *iter;
10624   GList *res;
10625
10626   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10627
10628   /* we walk the list backward so that we can use prepend(),
10629    * which is O(1)
10630    */
10631   for (iter = self->priv->last_child, res = NULL;
10632        iter != NULL;
10633        iter = iter->priv->prev_sibling)
10634     {
10635       res = g_list_prepend (res, iter);
10636     }
10637
10638   return res;
10639 }
10640
10641 /*< private >
10642  * insert_child_at_depth:
10643  * @self: a #ClutterActor
10644  * @child: a #ClutterActor
10645  *
10646  * Inserts @child inside the list of children held by @self, using
10647  * the depth as the insertion criteria.
10648  *
10649  * This sadly makes the insertion not O(1), but we can keep the
10650  * list sorted so that the painters algorithm we use for painting
10651  * the children will work correctly.
10652  */
10653 static void
10654 insert_child_at_depth (ClutterActor *self,
10655                        ClutterActor *child,
10656                        gpointer      dummy G_GNUC_UNUSED)
10657 {
10658   ClutterActor *iter;
10659   float child_depth;
10660
10661   child->priv->parent = self;
10662
10663   child_depth =
10664     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10665
10666   /* special-case the first child */
10667   if (self->priv->n_children == 0)
10668     {
10669       self->priv->first_child = child;
10670       self->priv->last_child = child;
10671
10672       child->priv->next_sibling = NULL;
10673       child->priv->prev_sibling = NULL;
10674
10675       return;
10676     }
10677
10678   /* Find the right place to insert the child so that it will still be
10679      sorted and the child will be after all of the actors at the same
10680      dept */
10681   for (iter = self->priv->first_child;
10682        iter != NULL;
10683        iter = iter->priv->next_sibling)
10684     {
10685       float iter_depth;
10686
10687       iter_depth =
10688         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10689
10690       if (iter_depth > child_depth)
10691         break;
10692     }
10693
10694   if (iter != NULL)
10695     {
10696       ClutterActor *tmp = iter->priv->prev_sibling;
10697
10698       if (tmp != NULL)
10699         tmp->priv->next_sibling = child;
10700
10701       /* Insert the node before the found one */
10702       child->priv->prev_sibling = iter->priv->prev_sibling;
10703       child->priv->next_sibling = iter;
10704       iter->priv->prev_sibling = child;
10705     }
10706   else
10707     {
10708       ClutterActor *tmp = self->priv->last_child;
10709
10710       if (tmp != NULL)
10711         tmp->priv->next_sibling = child;
10712
10713       /* insert the node at the end of the list */
10714       child->priv->prev_sibling = self->priv->last_child;
10715       child->priv->next_sibling = NULL;
10716     }
10717
10718   if (child->priv->prev_sibling == NULL)
10719     self->priv->first_child = child;
10720
10721   if (child->priv->next_sibling == NULL)
10722     self->priv->last_child = child;
10723 }
10724
10725 static void
10726 insert_child_at_index (ClutterActor *self,
10727                        ClutterActor *child,
10728                        gpointer      data_)
10729 {
10730   gint index_ = GPOINTER_TO_INT (data_);
10731
10732   child->priv->parent = self;
10733
10734   if (index_ == 0)
10735     {
10736       ClutterActor *tmp = self->priv->first_child;
10737
10738       if (tmp != NULL)
10739         tmp->priv->prev_sibling = child;
10740
10741       child->priv->prev_sibling = NULL;
10742       child->priv->next_sibling = tmp;
10743     }
10744   else if (index_ < 0 || index_ >= self->priv->n_children)
10745     {
10746       ClutterActor *tmp = self->priv->last_child;
10747
10748       if (tmp != NULL)
10749         tmp->priv->next_sibling = child;
10750
10751       child->priv->prev_sibling = tmp;
10752       child->priv->next_sibling = NULL;
10753     }
10754   else
10755     {
10756       ClutterActor *iter;
10757       int i;
10758
10759       for (iter = self->priv->first_child, i = 0;
10760            iter != NULL;
10761            iter = iter->priv->next_sibling, i += 1)
10762         {
10763           if (index_ == i)
10764             {
10765               ClutterActor *tmp = iter->priv->prev_sibling;
10766
10767               child->priv->prev_sibling = tmp;
10768               child->priv->next_sibling = iter;
10769
10770               iter->priv->prev_sibling = child;
10771
10772               if (tmp != NULL)
10773                 tmp->priv->next_sibling = child;
10774
10775               break;
10776             }
10777         }
10778     }
10779
10780   if (child->priv->prev_sibling == NULL)
10781     self->priv->first_child = child;
10782
10783   if (child->priv->next_sibling == NULL)
10784     self->priv->last_child = child;
10785 }
10786
10787 static void
10788 insert_child_above (ClutterActor *self,
10789                     ClutterActor *child,
10790                     gpointer      data)
10791 {
10792   ClutterActor *sibling = data;
10793
10794   child->priv->parent = self;
10795
10796   if (sibling == NULL)
10797     sibling = self->priv->last_child;
10798
10799   child->priv->prev_sibling = sibling;
10800
10801   if (sibling != NULL)
10802     {
10803       ClutterActor *tmp = sibling->priv->next_sibling;
10804
10805       child->priv->next_sibling = tmp;
10806
10807       if (tmp != NULL)
10808         tmp->priv->prev_sibling = child;
10809
10810       sibling->priv->next_sibling = child;
10811     }
10812   else
10813     child->priv->next_sibling = NULL;
10814
10815   if (child->priv->prev_sibling == NULL)
10816     self->priv->first_child = child;
10817
10818   if (child->priv->next_sibling == NULL)
10819     self->priv->last_child = child;
10820 }
10821
10822 static void
10823 insert_child_below (ClutterActor *self,
10824                     ClutterActor *child,
10825                     gpointer      data)
10826 {
10827   ClutterActor *sibling = data;
10828
10829   child->priv->parent = self;
10830
10831   if (sibling == NULL)
10832     sibling = self->priv->first_child;
10833
10834   child->priv->next_sibling = sibling;
10835
10836   if (sibling != NULL)
10837     {
10838       ClutterActor *tmp = sibling->priv->prev_sibling;
10839
10840       child->priv->prev_sibling = tmp;
10841
10842       if (tmp != NULL)
10843         tmp->priv->next_sibling = child;
10844
10845       sibling->priv->prev_sibling = child;
10846     }
10847   else
10848     child->priv->prev_sibling = NULL;
10849
10850   if (child->priv->prev_sibling == NULL)
10851     self->priv->first_child = child;
10852
10853   if (child->priv->next_sibling == NULL)
10854     self->priv->last_child = child;
10855 }
10856
10857 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10858                                            ClutterActor *child,
10859                                            gpointer      data);
10860
10861 typedef enum {
10862   ADD_CHILD_CREATE_META       = 1 << 0,
10863   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10864   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10865   ADD_CHILD_CHECK_STATE       = 1 << 3,
10866   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10867
10868   /* default flags for public API */
10869   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10870                                ADD_CHILD_EMIT_PARENT_SET |
10871                                ADD_CHILD_EMIT_ACTOR_ADDED |
10872                                ADD_CHILD_CHECK_STATE |
10873                                ADD_CHILD_NOTIFY_FIRST_LAST,
10874
10875   /* flags for legacy/deprecated API */
10876   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10877                                ADD_CHILD_CHECK_STATE |
10878                                ADD_CHILD_NOTIFY_FIRST_LAST
10879 } ClutterActorAddChildFlags;
10880
10881 /*< private >
10882  * clutter_actor_add_child_internal:
10883  * @self: a #ClutterActor
10884  * @child: a #ClutterActor
10885  * @flags: control flags for actions
10886  * @add_func: delegate function
10887  * @data: (closure): data to pass to @add_func
10888  *
10889  * Adds @child to the list of children of @self.
10890  *
10891  * The actual insertion inside the list is delegated to @add_func: this
10892  * function will just set up the state, perform basic checks, and emit
10893  * signals.
10894  *
10895  * The @flags argument is used to perform additional operations.
10896  */
10897 static inline void
10898 clutter_actor_add_child_internal (ClutterActor              *self,
10899                                   ClutterActor              *child,
10900                                   ClutterActorAddChildFlags  flags,
10901                                   ClutterActorAddChildFunc   add_func,
10902                                   gpointer                   data)
10903 {
10904   ClutterTextDirection text_dir;
10905   gboolean create_meta;
10906   gboolean emit_parent_set, emit_actor_added;
10907   gboolean check_state;
10908   gboolean notify_first_last;
10909   ClutterActor *old_first_child, *old_last_child;
10910
10911   if (child->priv->parent != NULL)
10912     {
10913       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10914                  "use clutter_actor_remove_child() first.",
10915                  _clutter_actor_get_debug_name (child),
10916                  _clutter_actor_get_debug_name (child->priv->parent));
10917       return;
10918     }
10919
10920   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10921     {
10922       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10923                  "a child of another actor.",
10924                  _clutter_actor_get_debug_name (child));
10925       return;
10926     }
10927
10928 #if 0
10929   /* XXX - this check disallows calling methods that change the stacking
10930    * order within the destruction sequence, by triggering a critical
10931    * warning first, and leaving the actor in an undefined state, which
10932    * then ends up being caught by an assertion.
10933    *
10934    * the reproducible sequence is:
10935    *
10936    *   - actor gets destroyed;
10937    *   - another actor, linked to the first, will try to change the
10938    *     stacking order of the first actor;
10939    *   - changing the stacking order is a composite operation composed
10940    *     by the following steps:
10941    *     1. ref() the child;
10942    *     2. remove_child_internal(), which removes the reference;
10943    *     3. add_child_internal(), which adds a reference;
10944    *   - the state of the actor is not changed between (2) and (3), as
10945    *     it could be an expensive recomputation;
10946    *   - if (3) bails out, then the actor is in an undefined state, but
10947    *     still alive;
10948    *   - the destruction sequence terminates, but the actor is unparented
10949    *     while its state indicates being parented instead.
10950    *   - assertion failure.
10951    *
10952    * the obvious fix would be to decompose each set_child_*_sibling()
10953    * method into proper remove_child()/add_child(), with state validation;
10954    * this may cause excessive work, though, and trigger a cascade of other
10955    * bugs in code that assumes that a change in the stacking order is an
10956    * atomic operation.
10957    *
10958    * another potential fix is to just remove this check here, and let
10959    * code doing stacking order changes inside the destruction sequence
10960    * of an actor continue doing the work.
10961    *
10962    * the third fix is to silently bail out early from every
10963    * set_child_*_sibling() and set_child_at_index() method, and avoid
10964    * doing work.
10965    *
10966    * I have a preference for the second solution, since it involves the
10967    * least amount of work, and the least amount of code duplication.
10968    *
10969    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10970    */
10971   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10972     {
10973       g_warning ("The actor '%s' is currently being destroyed, and "
10974                  "cannot be added as a child of another actor.",
10975                  _clutter_actor_get_debug_name (child));
10976       return;
10977     }
10978 #endif
10979
10980   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10981   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10982   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10983   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10984   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10985
10986   old_first_child = self->priv->first_child;
10987   old_last_child = self->priv->last_child;
10988
10989   g_object_freeze_notify (G_OBJECT (self));
10990
10991   if (create_meta)
10992     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10993
10994   g_object_ref_sink (child);
10995   child->priv->parent = NULL;
10996   child->priv->next_sibling = NULL;
10997   child->priv->prev_sibling = NULL;
10998
10999   /* delegate the actual insertion */
11000   add_func (self, child, data);
11001
11002   g_assert (child->priv->parent == self);
11003
11004   self->priv->n_children += 1;
11005
11006   self->priv->age += 1;
11007
11008   /* if push_internal() has been called then we automatically set
11009    * the flag on the actor
11010    */
11011   if (self->priv->internal_child)
11012     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11013
11014   /* clutter_actor_reparent() will emit ::parent-set for us */
11015   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11016     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11017
11018   if (check_state)
11019     {
11020       /* If parent is mapped or realized, we need to also be mapped or
11021        * realized once we're inside the parent.
11022        */
11023       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11024
11025       /* propagate the parent's text direction to the child */
11026       text_dir = clutter_actor_get_text_direction (self);
11027       clutter_actor_set_text_direction (child, text_dir);
11028     }
11029
11030   if (child->priv->show_on_set_parent)
11031     clutter_actor_show (child);
11032
11033   if (CLUTTER_ACTOR_IS_MAPPED (child))
11034     clutter_actor_queue_redraw (child);
11035
11036   /* maintain the invariant that if an actor needs layout,
11037    * its parents do as well
11038    */
11039   if (child->priv->needs_width_request ||
11040       child->priv->needs_height_request ||
11041       child->priv->needs_allocation)
11042     {
11043       /* we work around the short-circuiting we do
11044        * in clutter_actor_queue_relayout() since we
11045        * want to force a relayout
11046        */
11047       child->priv->needs_width_request = TRUE;
11048       child->priv->needs_height_request = TRUE;
11049       child->priv->needs_allocation = TRUE;
11050
11051       clutter_actor_queue_relayout (child->priv->parent);
11052     }
11053
11054   if (emit_actor_added)
11055     g_signal_emit_by_name (self, "actor-added", child);
11056
11057   if (notify_first_last)
11058     {
11059       if (old_first_child != self->priv->first_child)
11060         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11061
11062       if (old_last_child != self->priv->last_child)
11063         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11064     }
11065
11066   g_object_thaw_notify (G_OBJECT (self));
11067 }
11068
11069 /**
11070  * clutter_actor_add_child:
11071  * @self: a #ClutterActor
11072  * @child: a #ClutterActor
11073  *
11074  * Adds @child to the children of @self.
11075  *
11076  * This function will acquire a reference on @child that will only
11077  * be released when calling clutter_actor_remove_child().
11078  *
11079  * This function will take into consideration the #ClutterActor:depth
11080  * of @child, and will keep the list of children sorted.
11081  *
11082  * This function will emit the #ClutterContainer::actor-added signal
11083  * on @self.
11084  *
11085  * Since: 1.10
11086  */
11087 void
11088 clutter_actor_add_child (ClutterActor *self,
11089                          ClutterActor *child)
11090 {
11091   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11092   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11093   g_return_if_fail (self != child);
11094   g_return_if_fail (child->priv->parent == NULL);
11095
11096   clutter_actor_add_child_internal (self, child,
11097                                     ADD_CHILD_DEFAULT_FLAGS,
11098                                     insert_child_at_depth,
11099                                     NULL);
11100 }
11101
11102 /**
11103  * clutter_actor_insert_child_at_index:
11104  * @self: a #ClutterActor
11105  * @child: a #ClutterActor
11106  * @index_: the index
11107  *
11108  * Inserts @child into the list of children of @self, using the
11109  * given @index_. If @index_ is greater than the number of children
11110  * in @self, or is less than 0, then the new child is added at the end.
11111  *
11112  * This function will acquire a reference on @child that will only
11113  * be released when calling clutter_actor_remove_child().
11114  *
11115  * This function will not take into consideration the #ClutterActor:depth
11116  * of @child.
11117  *
11118  * This function will emit the #ClutterContainer::actor-added signal
11119  * on @self.
11120  *
11121  * Since: 1.10
11122  */
11123 void
11124 clutter_actor_insert_child_at_index (ClutterActor *self,
11125                                      ClutterActor *child,
11126                                      gint          index_)
11127 {
11128   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11129   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11130   g_return_if_fail (self != child);
11131   g_return_if_fail (child->priv->parent == NULL);
11132
11133   clutter_actor_add_child_internal (self, child,
11134                                     ADD_CHILD_DEFAULT_FLAGS,
11135                                     insert_child_at_index,
11136                                     GINT_TO_POINTER (index_));
11137 }
11138
11139 /**
11140  * clutter_actor_insert_child_above:
11141  * @self: a #ClutterActor
11142  * @child: a #ClutterActor
11143  * @sibling: (allow-none): a child of @self, or %NULL
11144  *
11145  * Inserts @child into the list of children of @self, above another
11146  * child of @self or, if @sibling is %NULL, above all the children
11147  * of @self.
11148  *
11149  * This function will acquire a reference on @child that will only
11150  * be released when calling clutter_actor_remove_child().
11151  *
11152  * This function will not take into consideration the #ClutterActor:depth
11153  * of @child.
11154  *
11155  * This function will emit the #ClutterContainer::actor-added signal
11156  * on @self.
11157  *
11158  * Since: 1.10
11159  */
11160 void
11161 clutter_actor_insert_child_above (ClutterActor *self,
11162                                   ClutterActor *child,
11163                                   ClutterActor *sibling)
11164 {
11165   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11166   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11167   g_return_if_fail (self != child);
11168   g_return_if_fail (child != sibling);
11169   g_return_if_fail (child->priv->parent == NULL);
11170   g_return_if_fail (sibling == NULL ||
11171                     (CLUTTER_IS_ACTOR (sibling) &&
11172                      sibling->priv->parent == self));
11173
11174   clutter_actor_add_child_internal (self, child,
11175                                     ADD_CHILD_DEFAULT_FLAGS,
11176                                     insert_child_above,
11177                                     sibling);
11178 }
11179
11180 /**
11181  * clutter_actor_insert_child_below:
11182  * @self: a #ClutterActor
11183  * @child: a #ClutterActor
11184  * @sibling: (allow-none): a child of @self, or %NULL
11185  *
11186  * Inserts @child into the list of children of @self, below another
11187  * child of @self or, if @sibling is %NULL, below all the children
11188  * of @self.
11189  *
11190  * This function will acquire a reference on @child that will only
11191  * be released when calling clutter_actor_remove_child().
11192  *
11193  * This function will not take into consideration the #ClutterActor:depth
11194  * of @child.
11195  *
11196  * This function will emit the #ClutterContainer::actor-added signal
11197  * on @self.
11198  *
11199  * Since: 1.10
11200  */
11201 void
11202 clutter_actor_insert_child_below (ClutterActor *self,
11203                                   ClutterActor *child,
11204                                   ClutterActor *sibling)
11205 {
11206   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11207   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11208   g_return_if_fail (self != child);
11209   g_return_if_fail (child != sibling);
11210   g_return_if_fail (child->priv->parent == NULL);
11211   g_return_if_fail (sibling == NULL ||
11212                     (CLUTTER_IS_ACTOR (sibling) &&
11213                      sibling->priv->parent == self));
11214
11215   clutter_actor_add_child_internal (self, child,
11216                                     ADD_CHILD_DEFAULT_FLAGS,
11217                                     insert_child_below,
11218                                     sibling);
11219 }
11220
11221 /**
11222  * clutter_actor_set_parent:
11223  * @self: A #ClutterActor
11224  * @parent: A new #ClutterActor parent
11225  *
11226  * Sets the parent of @self to @parent.
11227  *
11228  * This function will result in @parent acquiring a reference on @self,
11229  * eventually by sinking its floating reference first. The reference
11230  * will be released by clutter_actor_unparent().
11231  *
11232  * This function should only be called by legacy #ClutterActor<!-- -->s
11233  * implementing the #ClutterContainer interface.
11234  *
11235  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11236  */
11237 void
11238 clutter_actor_set_parent (ClutterActor *self,
11239                           ClutterActor *parent)
11240 {
11241   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11242   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11243   g_return_if_fail (self != parent);
11244   g_return_if_fail (self->priv->parent == NULL);
11245
11246   /* as this function will be called inside ClutterContainer::add
11247    * implementations or when building up a composite actor, we have
11248    * to preserve the old behaviour, and not create child meta or
11249    * emit the ::actor-added signal, to avoid recursion or double
11250    * emissions
11251    */
11252   clutter_actor_add_child_internal (parent, self,
11253                                     ADD_CHILD_LEGACY_FLAGS,
11254                                     insert_child_at_depth,
11255                                     NULL);
11256 }
11257
11258 /**
11259  * clutter_actor_get_parent:
11260  * @self: A #ClutterActor
11261  *
11262  * Retrieves the parent of @self.
11263  *
11264  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11265  *  if no parent is set
11266  */
11267 ClutterActor *
11268 clutter_actor_get_parent (ClutterActor *self)
11269 {
11270   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11271
11272   return self->priv->parent;
11273 }
11274
11275 /**
11276  * clutter_actor_get_paint_visibility:
11277  * @self: A #ClutterActor
11278  *
11279  * Retrieves the 'paint' visibility of an actor recursively checking for non
11280  * visible parents.
11281  *
11282  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11283  *
11284  * Return Value: %TRUE if the actor is visibile and will be painted.
11285  *
11286  * Since: 0.8.4
11287  */
11288 gboolean
11289 clutter_actor_get_paint_visibility (ClutterActor *actor)
11290 {
11291   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11292
11293   return CLUTTER_ACTOR_IS_MAPPED (actor);
11294 }
11295
11296 /**
11297  * clutter_actor_remove_child:
11298  * @self: a #ClutterActor
11299  * @child: a #ClutterActor
11300  *
11301  * Removes @child from the children of @self.
11302  *
11303  * This function will release the reference added by
11304  * clutter_actor_add_child(), so if you want to keep using @child
11305  * you will have to acquire a referenced on it before calling this
11306  * function.
11307  *
11308  * This function will emit the #ClutterContainer::actor-removed
11309  * signal on @self.
11310  *
11311  * Since: 1.10
11312  */
11313 void
11314 clutter_actor_remove_child (ClutterActor *self,
11315                             ClutterActor *child)
11316 {
11317   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11318   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11319   g_return_if_fail (self != child);
11320   g_return_if_fail (child->priv->parent != NULL);
11321   g_return_if_fail (child->priv->parent == self);
11322
11323   clutter_actor_remove_child_internal (self, child,
11324                                        REMOVE_CHILD_DEFAULT_FLAGS);
11325 }
11326
11327 /**
11328  * clutter_actor_remove_all_children:
11329  * @self: a #ClutterActor
11330  *
11331  * Removes all children of @self.
11332  *
11333  * This function releases the reference added by inserting a child actor
11334  * in the list of children of @self.
11335  *
11336  * If the reference count of a child drops to zero, the child will be
11337  * destroyed. If you want to ensure the destruction of all the children
11338  * of @self, use clutter_actor_destroy_all_children().
11339  *
11340  * Since: 1.10
11341  */
11342 void
11343 clutter_actor_remove_all_children (ClutterActor *self)
11344 {
11345   ClutterActorIter iter;
11346
11347   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11348
11349   if (self->priv->n_children == 0)
11350     return;
11351
11352   g_object_freeze_notify (G_OBJECT (self));
11353
11354   clutter_actor_iter_init (&iter, self);
11355   while (clutter_actor_iter_next (&iter, NULL))
11356     clutter_actor_iter_remove (&iter);
11357
11358   g_object_thaw_notify (G_OBJECT (self));
11359
11360   /* sanity check */
11361   g_assert (self->priv->first_child == NULL);
11362   g_assert (self->priv->last_child == NULL);
11363   g_assert (self->priv->n_children == 0);
11364 }
11365
11366 /**
11367  * clutter_actor_destroy_all_children:
11368  * @self: a #ClutterActor
11369  *
11370  * Destroys all children of @self.
11371  *
11372  * This function releases the reference added by inserting a child
11373  * actor in the list of children of @self, and ensures that the
11374  * #ClutterActor::destroy signal is emitted on each child of the
11375  * actor.
11376  *
11377  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11378  * when its reference count drops to 0; the default handler of the
11379  * #ClutterActor::destroy signal will destroy all the children of an
11380  * actor. This function ensures that all children are destroyed, instead
11381  * of just removed from @self, unlike clutter_actor_remove_all_children()
11382  * which will merely release the reference and remove each child.
11383  *
11384  * Unless you acquired an additional reference on each child of @self
11385  * prior to calling clutter_actor_remove_all_children() and want to reuse
11386  * the actors, you should use clutter_actor_destroy_all_children() in
11387  * order to make sure that children are destroyed and signal handlers
11388  * are disconnected even in cases where circular references prevent this
11389  * from automatically happening through reference counting alone.
11390  *
11391  * Since: 1.10
11392  */
11393 void
11394 clutter_actor_destroy_all_children (ClutterActor *self)
11395 {
11396   ClutterActorIter iter;
11397
11398   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11399
11400   if (self->priv->n_children == 0)
11401     return;
11402
11403   g_object_freeze_notify (G_OBJECT (self));
11404
11405   clutter_actor_iter_init (&iter, self);
11406   while (clutter_actor_iter_next (&iter, NULL))
11407     clutter_actor_iter_destroy (&iter);
11408
11409   g_object_thaw_notify (G_OBJECT (self));
11410
11411   /* sanity check */
11412   g_assert (self->priv->first_child == NULL);
11413   g_assert (self->priv->last_child == NULL);
11414   g_assert (self->priv->n_children == 0);
11415 }
11416
11417 typedef struct _InsertBetweenData {
11418   ClutterActor *prev_sibling;
11419   ClutterActor *next_sibling;
11420 } InsertBetweenData;
11421
11422 static void
11423 insert_child_between (ClutterActor *self,
11424                       ClutterActor *child,
11425                       gpointer      data_)
11426 {
11427   InsertBetweenData *data = data_;
11428   ClutterActor *prev_sibling = data->prev_sibling;
11429   ClutterActor *next_sibling = data->next_sibling;
11430
11431   child->priv->parent = self;
11432   child->priv->prev_sibling = prev_sibling;
11433   child->priv->next_sibling = next_sibling;
11434
11435   if (prev_sibling != NULL)
11436     prev_sibling->priv->next_sibling = child;
11437
11438   if (next_sibling != NULL)
11439     next_sibling->priv->prev_sibling = child;
11440
11441   if (child->priv->prev_sibling == NULL)
11442     self->priv->first_child = child;
11443
11444   if (child->priv->next_sibling == NULL)
11445     self->priv->last_child = child;
11446 }
11447
11448 /**
11449  * clutter_actor_replace_child:
11450  * @self: a #ClutterActor
11451  * @old_child: the child of @self to replace
11452  * @new_child: the #ClutterActor to replace @old_child
11453  *
11454  * Replaces @old_child with @new_child in the list of children of @self.
11455  *
11456  * Since: 1.10
11457  */
11458 void
11459 clutter_actor_replace_child (ClutterActor *self,
11460                              ClutterActor *old_child,
11461                              ClutterActor *new_child)
11462 {
11463   ClutterActor *prev_sibling, *next_sibling;
11464   InsertBetweenData clos;
11465
11466   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11467   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11468   g_return_if_fail (old_child->priv->parent == self);
11469   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11470   g_return_if_fail (old_child != new_child);
11471   g_return_if_fail (new_child != self);
11472   g_return_if_fail (new_child->priv->parent == NULL);
11473
11474   prev_sibling = old_child->priv->prev_sibling;
11475   next_sibling = old_child->priv->next_sibling;
11476   clutter_actor_remove_child_internal (self, old_child,
11477                                        REMOVE_CHILD_DEFAULT_FLAGS);
11478
11479   clos.prev_sibling = prev_sibling;
11480   clos.next_sibling = next_sibling;
11481   clutter_actor_add_child_internal (self, new_child,
11482                                     ADD_CHILD_DEFAULT_FLAGS,
11483                                     insert_child_between,
11484                                     &clos);
11485 }
11486
11487 /**
11488  * clutter_actor_unparent:
11489  * @self: a #ClutterActor
11490  *
11491  * Removes the parent of @self.
11492  *
11493  * This will cause the parent of @self to release the reference
11494  * acquired when calling clutter_actor_set_parent(), so if you
11495  * want to keep @self you will have to acquire a reference of
11496  * your own, through g_object_ref().
11497  *
11498  * This function should only be called by legacy #ClutterActor<!-- -->s
11499  * implementing the #ClutterContainer interface.
11500  *
11501  * Since: 0.1.1
11502  *
11503  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11504  */
11505 void
11506 clutter_actor_unparent (ClutterActor *self)
11507 {
11508   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11509
11510   if (self->priv->parent == NULL)
11511     return;
11512
11513   clutter_actor_remove_child_internal (self->priv->parent, self,
11514                                        REMOVE_CHILD_LEGACY_FLAGS);
11515 }
11516
11517 /**
11518  * clutter_actor_reparent:
11519  * @self: a #ClutterActor
11520  * @new_parent: the new #ClutterActor parent
11521  *
11522  * Resets the parent actor of @self.
11523  *
11524  * This function is logically equivalent to calling clutter_actor_unparent()
11525  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11526  * ensures the child is not finalized when unparented, and emits the
11527  * #ClutterActor::parent-set signal only once.
11528  *
11529  * In reality, calling this function is less useful than it sounds, as some
11530  * application code may rely on changes in the intermediate state between
11531  * removal and addition of the actor from its old parent to the @new_parent.
11532  * Thus, it is strongly encouraged to avoid using this function in application
11533  * code.
11534  *
11535  * Since: 0.2
11536  *
11537  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11538  *   clutter_actor_add_child() instead; remember to take a reference on
11539  *   the actor being removed before calling clutter_actor_remove_child()
11540  *   to avoid the reference count dropping to zero and the actor being
11541  *   destroyed.
11542  */
11543 void
11544 clutter_actor_reparent (ClutterActor *self,
11545                         ClutterActor *new_parent)
11546 {
11547   ClutterActorPrivate *priv;
11548
11549   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11550   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11551   g_return_if_fail (self != new_parent);
11552
11553   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11554     {
11555       g_warning ("Cannot set a parent on a toplevel actor");
11556       return;
11557     }
11558
11559   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11560     {
11561       g_warning ("Cannot set a parent currently being destroyed");
11562       return;
11563     }
11564
11565   priv = self->priv;
11566
11567   if (priv->parent != new_parent)
11568     {
11569       ClutterActor *old_parent;
11570
11571       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11572
11573       old_parent = priv->parent;
11574
11575       g_object_ref (self);
11576
11577       if (old_parent != NULL)
11578         {
11579          /* go through the Container implementation if this is a regular
11580           * child and not an internal one
11581           */
11582          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11583            {
11584              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11585
11586              /* this will have to call unparent() */
11587              clutter_container_remove_actor (parent, self);
11588            }
11589          else
11590            clutter_actor_remove_child_internal (old_parent, self,
11591                                                 REMOVE_CHILD_LEGACY_FLAGS);
11592         }
11593
11594       /* Note, will call set_parent() */
11595       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11596         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11597       else
11598         clutter_actor_add_child_internal (new_parent, self,
11599                                           ADD_CHILD_LEGACY_FLAGS,
11600                                           insert_child_at_depth,
11601                                           NULL);
11602
11603       /* we emit the ::parent-set signal once */
11604       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11605
11606       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11607
11608       /* the IN_REPARENT flag suspends state updates */
11609       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11610
11611       g_object_unref (self);
11612    }
11613 }
11614
11615 /**
11616  * clutter_actor_contains:
11617  * @self: A #ClutterActor
11618  * @descendant: A #ClutterActor, possibly contained in @self
11619  *
11620  * Determines if @descendant is contained inside @self (either as an
11621  * immediate child, or as a deeper descendant). If @self and
11622  * @descendant point to the same actor then it will also return %TRUE.
11623  *
11624  * Return value: whether @descendent is contained within @self
11625  *
11626  * Since: 1.4
11627  */
11628 gboolean
11629 clutter_actor_contains (ClutterActor *self,
11630                         ClutterActor *descendant)
11631 {
11632   ClutterActor *actor;
11633
11634   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11635   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11636
11637   for (actor = descendant; actor; actor = actor->priv->parent)
11638     if (actor == self)
11639       return TRUE;
11640
11641   return FALSE;
11642 }
11643
11644 /**
11645  * clutter_actor_set_child_above_sibling:
11646  * @self: a #ClutterActor
11647  * @child: a #ClutterActor child of @self
11648  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11649  *
11650  * Sets @child to be above @sibling in the list of children of @self.
11651  *
11652  * If @sibling is %NULL, @child will be the new last child of @self.
11653  *
11654  * This function is logically equivalent to removing @child and using
11655  * clutter_actor_insert_child_above(), but it will not emit signals
11656  * or change state on @child.
11657  *
11658  * Since: 1.10
11659  */
11660 void
11661 clutter_actor_set_child_above_sibling (ClutterActor *self,
11662                                        ClutterActor *child,
11663                                        ClutterActor *sibling)
11664 {
11665   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11666   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11667   g_return_if_fail (child->priv->parent == self);
11668   g_return_if_fail (child != sibling);
11669   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11670
11671   if (sibling != NULL)
11672     g_return_if_fail (sibling->priv->parent == self);
11673
11674   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11675       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11676       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11677     return;
11678
11679   /* we don't want to change the state of child, or emit signals, or
11680    * regenerate ChildMeta instances here, but we still want to follow
11681    * the correct sequence of steps encoded in remove_child() and
11682    * add_child(), so that correctness is ensured, and we only go
11683    * through one known code path.
11684    */
11685   g_object_ref (child);
11686   clutter_actor_remove_child_internal (self, child, 0);
11687   clutter_actor_add_child_internal (self, child,
11688                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11689                                     insert_child_above,
11690                                     sibling);
11691
11692   clutter_actor_queue_relayout (self);
11693 }
11694
11695 /**
11696  * clutter_actor_set_child_below_sibling:
11697  * @self: a #ClutterActor
11698  * @child: a #ClutterActor child of @self
11699  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11700  *
11701  * Sets @child to be below @sibling in the list of children of @self.
11702  *
11703  * If @sibling is %NULL, @child will be the new first child of @self.
11704  *
11705  * This function is logically equivalent to removing @self and using
11706  * clutter_actor_insert_child_below(), but it will not emit signals
11707  * or change state on @child.
11708  *
11709  * Since: 1.10
11710  */
11711 void
11712 clutter_actor_set_child_below_sibling (ClutterActor *self,
11713                                        ClutterActor *child,
11714                                        ClutterActor *sibling)
11715 {
11716   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11717   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11718   g_return_if_fail (child->priv->parent == self);
11719   g_return_if_fail (child != sibling);
11720   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11721
11722   if (sibling != NULL)
11723     g_return_if_fail (sibling->priv->parent == self);
11724
11725   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11726       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11727       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11728     return;
11729
11730   /* see the comment in set_child_above_sibling() */
11731   g_object_ref (child);
11732   clutter_actor_remove_child_internal (self, child, 0);
11733   clutter_actor_add_child_internal (self, child,
11734                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11735                                     insert_child_below,
11736                                     sibling);
11737
11738   clutter_actor_queue_relayout (self);
11739 }
11740
11741 /**
11742  * clutter_actor_set_child_at_index:
11743  * @self: a #ClutterActor
11744  * @child: a #ClutterActor child of @self
11745  * @index_: the new index for @child
11746  *
11747  * Changes the index of @child in the list of children of @self.
11748  *
11749  * This function is logically equivalent to removing @child and
11750  * calling clutter_actor_insert_child_at_index(), but it will not
11751  * emit signals or change state on @child.
11752  *
11753  * Since: 1.10
11754  */
11755 void
11756 clutter_actor_set_child_at_index (ClutterActor *self,
11757                                   ClutterActor *child,
11758                                   gint          index_)
11759 {
11760   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11761   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11762   g_return_if_fail (child->priv->parent == self);
11763   g_return_if_fail (index_ <= self->priv->n_children);
11764
11765   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11766       CLUTTER_ACTOR_IN_DESTRUCTION (child))
11767     return;
11768
11769   g_object_ref (child);
11770   clutter_actor_remove_child_internal (self, child, 0);
11771   clutter_actor_add_child_internal (self, child,
11772                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11773                                     insert_child_at_index,
11774                                     GINT_TO_POINTER (index_));
11775
11776   clutter_actor_queue_relayout (self);
11777 }
11778
11779 /**
11780  * clutter_actor_raise:
11781  * @self: A #ClutterActor
11782  * @below: (allow-none): A #ClutterActor to raise above.
11783  *
11784  * Puts @self above @below.
11785  *
11786  * Both actors must have the same parent, and the parent must implement
11787  * the #ClutterContainer interface
11788  *
11789  * This function calls clutter_container_raise_child() internally.
11790  *
11791  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11792  */
11793 void
11794 clutter_actor_raise (ClutterActor *self,
11795                      ClutterActor *below)
11796 {
11797   ClutterActor *parent;
11798
11799   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11800
11801   parent = clutter_actor_get_parent (self);
11802   if (parent == NULL)
11803     {
11804       g_warning ("%s: Actor '%s' is not inside a container",
11805                  G_STRFUNC,
11806                  _clutter_actor_get_debug_name (self));
11807       return;
11808     }
11809
11810   if (below != NULL)
11811     {
11812       if (parent != clutter_actor_get_parent (below))
11813         {
11814           g_warning ("%s Actor '%s' is not in the same container as "
11815                      "actor '%s'",
11816                      G_STRFUNC,
11817                      _clutter_actor_get_debug_name (self),
11818                      _clutter_actor_get_debug_name (below));
11819           return;
11820         }
11821     }
11822
11823   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11824 }
11825
11826 /**
11827  * clutter_actor_lower:
11828  * @self: A #ClutterActor
11829  * @above: (allow-none): A #ClutterActor to lower below
11830  *
11831  * Puts @self below @above.
11832  *
11833  * Both actors must have the same parent, and the parent must implement
11834  * the #ClutterContainer interface.
11835  *
11836  * This function calls clutter_container_lower_child() internally.
11837  *
11838  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11839  */
11840 void
11841 clutter_actor_lower (ClutterActor *self,
11842                      ClutterActor *above)
11843 {
11844   ClutterActor *parent;
11845
11846   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11847
11848   parent = clutter_actor_get_parent (self);
11849   if (parent == NULL)
11850     {
11851       g_warning ("%s: Actor of type %s is not inside a container",
11852                  G_STRFUNC,
11853                  _clutter_actor_get_debug_name (self));
11854       return;
11855     }
11856
11857   if (above)
11858     {
11859       if (parent != clutter_actor_get_parent (above))
11860         {
11861           g_warning ("%s: Actor '%s' is not in the same container as "
11862                      "actor '%s'",
11863                      G_STRFUNC,
11864                      _clutter_actor_get_debug_name (self),
11865                      _clutter_actor_get_debug_name (above));
11866           return;
11867         }
11868     }
11869
11870   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11871 }
11872
11873 /**
11874  * clutter_actor_raise_top:
11875  * @self: A #ClutterActor
11876  *
11877  * Raises @self to the top.
11878  *
11879  * This function calls clutter_actor_raise() internally.
11880  *
11881  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11882  *   a %NULL sibling, instead.
11883  */
11884 void
11885 clutter_actor_raise_top (ClutterActor *self)
11886 {
11887   clutter_actor_raise (self, NULL);
11888 }
11889
11890 /**
11891  * clutter_actor_lower_bottom:
11892  * @self: A #ClutterActor
11893  *
11894  * Lowers @self to the bottom.
11895  *
11896  * This function calls clutter_actor_lower() internally.
11897  *
11898  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11899  *   a %NULL sibling, instead.
11900  */
11901 void
11902 clutter_actor_lower_bottom (ClutterActor *self)
11903 {
11904   clutter_actor_lower (self, NULL);
11905 }
11906
11907 /*
11908  * Event handling
11909  */
11910
11911 /**
11912  * clutter_actor_event:
11913  * @actor: a #ClutterActor
11914  * @event: a #ClutterEvent
11915  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11916  *
11917  * This function is used to emit an event on the main stage.
11918  * You should rarely need to use this function, except for
11919  * synthetising events.
11920  *
11921  * Return value: the return value from the signal emission: %TRUE
11922  *   if the actor handled the event, or %FALSE if the event was
11923  *   not handled
11924  *
11925  * Since: 0.6
11926  */
11927 gboolean
11928 clutter_actor_event (ClutterActor *actor,
11929                      ClutterEvent *event,
11930                      gboolean      capture)
11931 {
11932   gboolean retval = FALSE;
11933   gint signal_num = -1;
11934
11935   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11936   g_return_val_if_fail (event != NULL, FALSE);
11937
11938   g_object_ref (actor);
11939
11940   if (capture)
11941     {
11942       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11943                      event,
11944                      &retval);
11945       goto out;
11946     }
11947
11948   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11949
11950   if (!retval)
11951     {
11952       switch (event->type)
11953         {
11954         case CLUTTER_NOTHING:
11955           break;
11956         case CLUTTER_BUTTON_PRESS:
11957           signal_num = BUTTON_PRESS_EVENT;
11958           break;
11959         case CLUTTER_BUTTON_RELEASE:
11960           signal_num = BUTTON_RELEASE_EVENT;
11961           break;
11962         case CLUTTER_SCROLL:
11963           signal_num = SCROLL_EVENT;
11964           break;
11965         case CLUTTER_KEY_PRESS:
11966           signal_num = KEY_PRESS_EVENT;
11967           break;
11968         case CLUTTER_KEY_RELEASE:
11969           signal_num = KEY_RELEASE_EVENT;
11970           break;
11971         case CLUTTER_MOTION:
11972           signal_num = MOTION_EVENT;
11973           break;
11974         case CLUTTER_ENTER:
11975           signal_num = ENTER_EVENT;
11976           break;
11977         case CLUTTER_LEAVE:
11978           signal_num = LEAVE_EVENT;
11979           break;
11980         case CLUTTER_DELETE:
11981         case CLUTTER_DESTROY_NOTIFY:
11982         case CLUTTER_CLIENT_MESSAGE:
11983         default:
11984           signal_num = -1;
11985           break;
11986         }
11987
11988       if (signal_num != -1)
11989         g_signal_emit (actor, actor_signals[signal_num], 0,
11990                        event, &retval);
11991     }
11992
11993 out:
11994   g_object_unref (actor);
11995
11996   return retval;
11997 }
11998
11999 /**
12000  * clutter_actor_set_reactive:
12001  * @actor: a #ClutterActor
12002  * @reactive: whether the actor should be reactive to events
12003  *
12004  * Sets @actor as reactive. Reactive actors will receive events.
12005  *
12006  * Since: 0.6
12007  */
12008 void
12009 clutter_actor_set_reactive (ClutterActor *actor,
12010                             gboolean      reactive)
12011 {
12012   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12013
12014   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12015     return;
12016
12017   if (reactive)
12018     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12019   else
12020     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12021
12022   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12023 }
12024
12025 /**
12026  * clutter_actor_get_reactive:
12027  * @actor: a #ClutterActor
12028  *
12029  * Checks whether @actor is marked as reactive.
12030  *
12031  * Return value: %TRUE if the actor is reactive
12032  *
12033  * Since: 0.6
12034  */
12035 gboolean
12036 clutter_actor_get_reactive (ClutterActor *actor)
12037 {
12038   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12039
12040   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12041 }
12042
12043 /**
12044  * clutter_actor_get_anchor_point:
12045  * @self: a #ClutterActor
12046  * @anchor_x: (out): return location for the X coordinate of the anchor point
12047  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12048  *
12049  * Gets the current anchor point of the @actor in pixels.
12050  *
12051  * Since: 0.6
12052  */
12053 void
12054 clutter_actor_get_anchor_point (ClutterActor *self,
12055                                 gfloat       *anchor_x,
12056                                 gfloat       *anchor_y)
12057 {
12058   const ClutterTransformInfo *info;
12059
12060   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12061
12062   info = _clutter_actor_get_transform_info_or_defaults (self);
12063   clutter_anchor_coord_get_units (self, &info->anchor,
12064                                   anchor_x,
12065                                   anchor_y,
12066                                   NULL);
12067 }
12068
12069 /**
12070  * clutter_actor_set_anchor_point:
12071  * @self: a #ClutterActor
12072  * @anchor_x: X coordinate of the anchor point
12073  * @anchor_y: Y coordinate of the anchor point
12074  *
12075  * Sets an anchor point for @self. The anchor point is a point in the
12076  * coordinate space of an actor to which the actor position within its
12077  * parent is relative; the default is (0, 0), i.e. the top-left corner
12078  * of the actor.
12079  *
12080  * Since: 0.6
12081  */
12082 void
12083 clutter_actor_set_anchor_point (ClutterActor *self,
12084                                 gfloat        anchor_x,
12085                                 gfloat        anchor_y)
12086 {
12087   ClutterTransformInfo *info;
12088   ClutterActorPrivate *priv;
12089   gboolean changed = FALSE;
12090   gfloat old_anchor_x, old_anchor_y;
12091   GObject *obj;
12092
12093   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12094
12095   obj = G_OBJECT (self);
12096   priv = self->priv;
12097   info = _clutter_actor_get_transform_info (self);
12098
12099   g_object_freeze_notify (obj);
12100
12101   clutter_anchor_coord_get_units (self, &info->anchor,
12102                                   &old_anchor_x,
12103                                   &old_anchor_y,
12104                                   NULL);
12105
12106   if (info->anchor.is_fractional)
12107     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12108
12109   if (old_anchor_x != anchor_x)
12110     {
12111       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12112       changed = TRUE;
12113     }
12114
12115   if (old_anchor_y != anchor_y)
12116     {
12117       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12118       changed = TRUE;
12119     }
12120
12121   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12122
12123   if (changed)
12124     {
12125       priv->transform_valid = FALSE;
12126       clutter_actor_queue_redraw (self);
12127     }
12128
12129   g_object_thaw_notify (obj);
12130 }
12131
12132 /**
12133  * clutter_actor_get_anchor_point_gravity:
12134  * @self: a #ClutterActor
12135  *
12136  * Retrieves the anchor position expressed as a #ClutterGravity. If
12137  * the anchor point was specified using pixels or units this will
12138  * return %CLUTTER_GRAVITY_NONE.
12139  *
12140  * Return value: the #ClutterGravity used by the anchor point
12141  *
12142  * Since: 1.0
12143  */
12144 ClutterGravity
12145 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12146 {
12147   const ClutterTransformInfo *info;
12148
12149   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12150
12151   info = _clutter_actor_get_transform_info_or_defaults (self);
12152
12153   return clutter_anchor_coord_get_gravity (&info->anchor);
12154 }
12155
12156 /**
12157  * clutter_actor_move_anchor_point:
12158  * @self: a #ClutterActor
12159  * @anchor_x: X coordinate of the anchor point
12160  * @anchor_y: Y coordinate of the anchor point
12161  *
12162  * Sets an anchor point for the actor, and adjusts the actor postion so that
12163  * the relative position of the actor toward its parent remains the same.
12164  *
12165  * Since: 0.6
12166  */
12167 void
12168 clutter_actor_move_anchor_point (ClutterActor *self,
12169                                  gfloat        anchor_x,
12170                                  gfloat        anchor_y)
12171 {
12172   gfloat old_anchor_x, old_anchor_y;
12173   const ClutterTransformInfo *info;
12174
12175   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12176
12177   info = _clutter_actor_get_transform_info (self);
12178   clutter_anchor_coord_get_units (self, &info->anchor,
12179                                   &old_anchor_x,
12180                                   &old_anchor_y,
12181                                   NULL);
12182
12183   g_object_freeze_notify (G_OBJECT (self));
12184
12185   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12186
12187   if (self->priv->position_set)
12188     clutter_actor_move_by (self,
12189                            anchor_x - old_anchor_x,
12190                            anchor_y - old_anchor_y);
12191
12192   g_object_thaw_notify (G_OBJECT (self));
12193 }
12194
12195 /**
12196  * clutter_actor_move_anchor_point_from_gravity:
12197  * @self: a #ClutterActor
12198  * @gravity: #ClutterGravity.
12199  *
12200  * Sets an anchor point on the actor based on the given gravity, adjusting the
12201  * actor postion so that its relative position within its parent remains
12202  * unchanged.
12203  *
12204  * Since version 1.0 the anchor point will be stored as a gravity so
12205  * that if the actor changes size then the anchor point will move. For
12206  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12207  * and later double the size of the actor, the anchor point will move
12208  * to the bottom right.
12209  *
12210  * Since: 0.6
12211  */
12212 void
12213 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12214                                               ClutterGravity  gravity)
12215 {
12216   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12217   const ClutterTransformInfo *info;
12218   ClutterActorPrivate *priv;
12219
12220   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12221
12222   priv = self->priv;
12223   info = _clutter_actor_get_transform_info (self);
12224
12225   g_object_freeze_notify (G_OBJECT (self));
12226
12227   clutter_anchor_coord_get_units (self, &info->anchor,
12228                                   &old_anchor_x,
12229                                   &old_anchor_y,
12230                                   NULL);
12231   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12232   clutter_anchor_coord_get_units (self, &info->anchor,
12233                                   &new_anchor_x,
12234                                   &new_anchor_y,
12235                                   NULL);
12236
12237   if (priv->position_set)
12238     clutter_actor_move_by (self,
12239                            new_anchor_x - old_anchor_x,
12240                            new_anchor_y - old_anchor_y);
12241
12242   g_object_thaw_notify (G_OBJECT (self));
12243 }
12244
12245 /**
12246  * clutter_actor_set_anchor_point_from_gravity:
12247  * @self: a #ClutterActor
12248  * @gravity: #ClutterGravity.
12249  *
12250  * Sets an anchor point on the actor, based on the given gravity (this is a
12251  * convenience function wrapping clutter_actor_set_anchor_point()).
12252  *
12253  * Since version 1.0 the anchor point will be stored as a gravity so
12254  * that if the actor changes size then the anchor point will move. For
12255  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12256  * and later double the size of the actor, the anchor point will move
12257  * to the bottom right.
12258  *
12259  * Since: 0.6
12260  */
12261 void
12262 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12263                                              ClutterGravity  gravity)
12264 {
12265   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12266
12267   if (gravity == CLUTTER_GRAVITY_NONE)
12268     clutter_actor_set_anchor_point (self, 0, 0);
12269   else
12270     {
12271       GObject *obj = G_OBJECT (self);
12272       ClutterTransformInfo *info;
12273
12274       g_object_freeze_notify (obj);
12275
12276       info = _clutter_actor_get_transform_info (self);
12277       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12278
12279       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12280       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12281       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12282
12283       self->priv->transform_valid = FALSE;
12284
12285       clutter_actor_queue_redraw (self);
12286
12287       g_object_thaw_notify (obj);
12288     }
12289 }
12290
12291 static void
12292 clutter_container_iface_init (ClutterContainerIface *iface)
12293 {
12294   /* we don't override anything, as ClutterContainer already has a default
12295    * implementation that we can use, and which calls into our own API.
12296    */
12297 }
12298
12299 typedef enum
12300 {
12301   PARSE_X,
12302   PARSE_Y,
12303   PARSE_WIDTH,
12304   PARSE_HEIGHT,
12305   PARSE_ANCHOR_X,
12306   PARSE_ANCHOR_Y
12307 } ParseDimension;
12308
12309 static gfloat
12310 parse_units (ClutterActor   *self,
12311              ParseDimension  dimension,
12312              JsonNode       *node)
12313 {
12314   GValue value = G_VALUE_INIT;
12315   gfloat retval = 0;
12316
12317   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12318     return 0;
12319
12320   json_node_get_value (node, &value);
12321
12322   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12323     {
12324       retval = (gfloat) g_value_get_int64 (&value);
12325     }
12326   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12327     {
12328       retval = g_value_get_double (&value);
12329     }
12330   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12331     {
12332       ClutterUnits units;
12333       gboolean res;
12334
12335       res = clutter_units_from_string (&units, g_value_get_string (&value));
12336       if (res)
12337         retval = clutter_units_to_pixels (&units);
12338       else
12339         {
12340           g_warning ("Invalid value '%s': integers, strings or floating point "
12341                      "values can be used for the x, y, width and height "
12342                      "properties. Valid modifiers for strings are 'px', 'mm', "
12343                      "'pt' and 'em'.",
12344                      g_value_get_string (&value));
12345           retval = 0;
12346         }
12347     }
12348   else
12349     {
12350       g_warning ("Invalid value of type '%s': integers, strings of floating "
12351                  "point values can be used for the x, y, width, height "
12352                  "anchor-x and anchor-y properties.",
12353                  g_type_name (G_VALUE_TYPE (&value)));
12354     }
12355
12356   g_value_unset (&value);
12357
12358   return retval;
12359 }
12360
12361 typedef struct {
12362   ClutterRotateAxis axis;
12363
12364   gdouble angle;
12365
12366   gfloat center_x;
12367   gfloat center_y;
12368   gfloat center_z;
12369 } RotationInfo;
12370
12371 static inline gboolean
12372 parse_rotation_array (ClutterActor *actor,
12373                       JsonArray    *array,
12374                       RotationInfo *info)
12375 {
12376   JsonNode *element;
12377
12378   if (json_array_get_length (array) != 2)
12379     return FALSE;
12380
12381   /* angle */
12382   element = json_array_get_element (array, 0);
12383   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12384     info->angle = json_node_get_double (element);
12385   else
12386     return FALSE;
12387
12388   /* center */
12389   element = json_array_get_element (array, 1);
12390   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12391     {
12392       JsonArray *center = json_node_get_array (element);
12393
12394       if (json_array_get_length (center) != 2)
12395         return FALSE;
12396
12397       switch (info->axis)
12398         {
12399         case CLUTTER_X_AXIS:
12400           info->center_y = parse_units (actor, PARSE_Y,
12401                                         json_array_get_element (center, 0));
12402           info->center_z = parse_units (actor, PARSE_Y,
12403                                         json_array_get_element (center, 1));
12404           return TRUE;
12405
12406         case CLUTTER_Y_AXIS:
12407           info->center_x = parse_units (actor, PARSE_X,
12408                                         json_array_get_element (center, 0));
12409           info->center_z = parse_units (actor, PARSE_X,
12410                                         json_array_get_element (center, 1));
12411           return TRUE;
12412
12413         case CLUTTER_Z_AXIS:
12414           info->center_x = parse_units (actor, PARSE_X,
12415                                         json_array_get_element (center, 0));
12416           info->center_y = parse_units (actor, PARSE_Y,
12417                                         json_array_get_element (center, 1));
12418           return TRUE;
12419         }
12420     }
12421
12422   return FALSE;
12423 }
12424
12425 static gboolean
12426 parse_rotation (ClutterActor *actor,
12427                 JsonNode     *node,
12428                 RotationInfo *info)
12429 {
12430   JsonArray *array;
12431   guint len, i;
12432   gboolean retval = FALSE;
12433
12434   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12435     {
12436       g_warning ("Invalid node of type '%s' found, expecting an array",
12437                  json_node_type_name (node));
12438       return FALSE;
12439     }
12440
12441   array = json_node_get_array (node);
12442   len = json_array_get_length (array);
12443
12444   for (i = 0; i < len; i++)
12445     {
12446       JsonNode *element = json_array_get_element (array, i);
12447       JsonObject *object;
12448       JsonNode *member;
12449
12450       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12451         {
12452           g_warning ("Invalid node of type '%s' found, expecting an object",
12453                      json_node_type_name (element));
12454           return FALSE;
12455         }
12456
12457       object = json_node_get_object (element);
12458
12459       if (json_object_has_member (object, "x-axis"))
12460         {
12461           member = json_object_get_member (object, "x-axis");
12462
12463           info->axis = CLUTTER_X_AXIS;
12464
12465           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12466             {
12467               info->angle = json_node_get_double (member);
12468               retval = TRUE;
12469             }
12470           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12471             retval = parse_rotation_array (actor,
12472                                            json_node_get_array (member),
12473                                            info);
12474           else
12475             retval = FALSE;
12476         }
12477       else if (json_object_has_member (object, "y-axis"))
12478         {
12479           member = json_object_get_member (object, "y-axis");
12480
12481           info->axis = CLUTTER_Y_AXIS;
12482
12483           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12484             {
12485               info->angle = json_node_get_double (member);
12486               retval = TRUE;
12487             }
12488           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12489             retval = parse_rotation_array (actor,
12490                                            json_node_get_array (member),
12491                                            info);
12492           else
12493             retval = FALSE;
12494         }
12495       else if (json_object_has_member (object, "z-axis"))
12496         {
12497           member = json_object_get_member (object, "z-axis");
12498
12499           info->axis = CLUTTER_Z_AXIS;
12500
12501           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12502             {
12503               info->angle = json_node_get_double (member);
12504               retval = TRUE;
12505             }
12506           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12507             retval = parse_rotation_array (actor,
12508                                            json_node_get_array (member),
12509                                            info);
12510           else
12511             retval = FALSE;
12512         }
12513     }
12514
12515   return retval;
12516 }
12517
12518 static GSList *
12519 parse_actor_metas (ClutterScript *script,
12520                    ClutterActor  *actor,
12521                    JsonNode      *node)
12522 {
12523   GList *elements, *l;
12524   GSList *retval = NULL;
12525
12526   if (!JSON_NODE_HOLDS_ARRAY (node))
12527     return NULL;
12528
12529   elements = json_array_get_elements (json_node_get_array (node));
12530
12531   for (l = elements; l != NULL; l = l->next)
12532     {
12533       JsonNode *element = l->data;
12534       const gchar *id_ = _clutter_script_get_id_from_node (element);
12535       GObject *meta;
12536
12537       if (id_ == NULL || *id_ == '\0')
12538         continue;
12539
12540       meta = clutter_script_get_object (script, id_);
12541       if (meta == NULL)
12542         continue;
12543
12544       retval = g_slist_prepend (retval, meta);
12545     }
12546
12547   g_list_free (elements);
12548
12549   return g_slist_reverse (retval);
12550 }
12551
12552 static GSList *
12553 parse_behaviours (ClutterScript *script,
12554                   ClutterActor  *actor,
12555                   JsonNode      *node)
12556 {
12557   GList *elements, *l;
12558   GSList *retval = NULL;
12559
12560   if (!JSON_NODE_HOLDS_ARRAY (node))
12561     return NULL;
12562
12563   elements = json_array_get_elements (json_node_get_array (node));
12564
12565   for (l = elements; l != NULL; l = l->next)
12566     {
12567       JsonNode *element = l->data;
12568       const gchar *id_ = _clutter_script_get_id_from_node (element);
12569       GObject *behaviour;
12570
12571       if (id_ == NULL || *id_ == '\0')
12572         continue;
12573
12574       behaviour = clutter_script_get_object (script, id_);
12575       if (behaviour == NULL)
12576         continue;
12577
12578       retval = g_slist_prepend (retval, behaviour);
12579     }
12580
12581   g_list_free (elements);
12582
12583   return g_slist_reverse (retval);
12584 }
12585
12586 static gboolean
12587 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12588                                  ClutterScript     *script,
12589                                  GValue            *value,
12590                                  const gchar       *name,
12591                                  JsonNode          *node)
12592 {
12593   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12594   gboolean retval = FALSE;
12595
12596   if ((name[0] == 'x' && name[1] == '\0') ||
12597       (name[0] == 'y' && name[1] == '\0') ||
12598       (strcmp (name, "width") == 0) ||
12599       (strcmp (name, "height") == 0) ||
12600       (strcmp (name, "anchor_x") == 0) ||
12601       (strcmp (name, "anchor_y") == 0))
12602     {
12603       ParseDimension dimension;
12604       gfloat units;
12605
12606       if (name[0] == 'x')
12607         dimension = PARSE_X;
12608       else if (name[0] == 'y')
12609         dimension = PARSE_Y;
12610       else if (name[0] == 'w')
12611         dimension = PARSE_WIDTH;
12612       else if (name[0] == 'h')
12613         dimension = PARSE_HEIGHT;
12614       else if (name[0] == 'a' && name[7] == 'x')
12615         dimension = PARSE_ANCHOR_X;
12616       else if (name[0] == 'a' && name[7] == 'y')
12617         dimension = PARSE_ANCHOR_Y;
12618       else
12619         return FALSE;
12620
12621       units = parse_units (actor, dimension, node);
12622
12623       /* convert back to pixels: all properties are pixel-based */
12624       g_value_init (value, G_TYPE_FLOAT);
12625       g_value_set_float (value, units);
12626
12627       retval = TRUE;
12628     }
12629   else if (strcmp (name, "rotation") == 0)
12630     {
12631       RotationInfo *info;
12632
12633       info = g_slice_new0 (RotationInfo);
12634       retval = parse_rotation (actor, node, info);
12635
12636       if (retval)
12637         {
12638           g_value_init (value, G_TYPE_POINTER);
12639           g_value_set_pointer (value, info);
12640         }
12641       else
12642         g_slice_free (RotationInfo, info);
12643     }
12644   else if (strcmp (name, "behaviours") == 0)
12645     {
12646       GSList *l;
12647
12648 #ifdef CLUTTER_ENABLE_DEBUG
12649       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12650         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12651                                      "and it should not be used in newly "
12652                                      "written ClutterScript definitions.");
12653 #endif
12654
12655       l = parse_behaviours (script, actor, node);
12656
12657       g_value_init (value, G_TYPE_POINTER);
12658       g_value_set_pointer (value, l);
12659
12660       retval = TRUE;
12661     }
12662   else if (strcmp (name, "actions") == 0 ||
12663            strcmp (name, "constraints") == 0 ||
12664            strcmp (name, "effects") == 0)
12665     {
12666       GSList *l;
12667
12668       l = parse_actor_metas (script, actor, node);
12669
12670       g_value_init (value, G_TYPE_POINTER);
12671       g_value_set_pointer (value, l);
12672
12673       retval = TRUE;
12674     }
12675
12676   return retval;
12677 }
12678
12679 static void
12680 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12681                                    ClutterScript     *script,
12682                                    const gchar       *name,
12683                                    const GValue      *value)
12684 {
12685   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12686
12687 #ifdef CLUTTER_ENABLE_DEBUG
12688   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12689     {
12690       gchar *tmp = g_strdup_value_contents (value);
12691
12692       CLUTTER_NOTE (SCRIPT,
12693                     "in ClutterActor::set_custom_property('%s') = %s",
12694                     name,
12695                     tmp);
12696
12697       g_free (tmp);
12698     }
12699 #endif /* CLUTTER_ENABLE_DEBUG */
12700
12701   if (strcmp (name, "rotation") == 0)
12702     {
12703       RotationInfo *info;
12704
12705       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12706         return;
12707
12708       info = g_value_get_pointer (value);
12709
12710       clutter_actor_set_rotation (actor,
12711                                   info->axis, info->angle,
12712                                   info->center_x,
12713                                   info->center_y,
12714                                   info->center_z);
12715
12716       g_slice_free (RotationInfo, info);
12717
12718       return;
12719     }
12720
12721   if (strcmp (name, "behaviours") == 0)
12722     {
12723       GSList *behaviours, *l;
12724
12725       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12726         return;
12727
12728       behaviours = g_value_get_pointer (value);
12729       for (l = behaviours; l != NULL; l = l->next)
12730         {
12731           ClutterBehaviour *behaviour = l->data;
12732
12733           clutter_behaviour_apply (behaviour, actor);
12734         }
12735
12736       g_slist_free (behaviours);
12737
12738       return;
12739     }
12740
12741   if (strcmp (name, "actions") == 0 ||
12742       strcmp (name, "constraints") == 0 ||
12743       strcmp (name, "effects") == 0)
12744     {
12745       GSList *metas, *l;
12746
12747       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12748         return;
12749
12750       metas = g_value_get_pointer (value);
12751       for (l = metas; l != NULL; l = l->next)
12752         {
12753           if (name[0] == 'a')
12754             clutter_actor_add_action (actor, l->data);
12755
12756           if (name[0] == 'c')
12757             clutter_actor_add_constraint (actor, l->data);
12758
12759           if (name[0] == 'e')
12760             clutter_actor_add_effect (actor, l->data);
12761         }
12762
12763       g_slist_free (metas);
12764
12765       return;
12766     }
12767
12768   g_object_set_property (G_OBJECT (scriptable), name, value);
12769 }
12770
12771 static void
12772 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12773 {
12774   iface->parse_custom_node = clutter_actor_parse_custom_node;
12775   iface->set_custom_property = clutter_actor_set_custom_property;
12776 }
12777
12778 static ClutterActorMeta *
12779 get_meta_from_animation_property (ClutterActor  *actor,
12780                                   const gchar   *name,
12781                                   gchar        **name_p)
12782 {
12783   ClutterActorPrivate *priv = actor->priv;
12784   ClutterActorMeta *meta = NULL;
12785   gchar **tokens;
12786
12787   /* if this is not a special property, fall through */
12788   if (name[0] != '@')
12789     return NULL;
12790
12791   /* detect the properties named using the following spec:
12792    *
12793    *   @<section>.<meta-name>.<property-name>
12794    *
12795    * where <section> can be one of the following:
12796    *
12797    *   - actions
12798    *   - constraints
12799    *   - effects
12800    *
12801    * and <meta-name> is the name set on a specific ActorMeta
12802    */
12803
12804   tokens = g_strsplit (name + 1, ".", -1);
12805   if (tokens == NULL || g_strv_length (tokens) != 3)
12806     {
12807       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12808                     name + 1);
12809       g_strfreev (tokens);
12810       return NULL;
12811     }
12812
12813   if (strcmp (tokens[0], "actions") == 0)
12814     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12815
12816   if (strcmp (tokens[0], "constraints") == 0)
12817     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12818
12819   if (strcmp (tokens[0], "effects") == 0)
12820     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12821
12822   if (name_p != NULL)
12823     *name_p = g_strdup (tokens[2]);
12824
12825   CLUTTER_NOTE (ANIMATION,
12826                 "Looking for property '%s' of object '%s' in section '%s'",
12827                 tokens[2],
12828                 tokens[1],
12829                 tokens[0]);
12830
12831   g_strfreev (tokens);
12832
12833   return meta;
12834 }
12835
12836 static GParamSpec *
12837 clutter_actor_find_property (ClutterAnimatable *animatable,
12838                              const gchar       *property_name)
12839 {
12840   ClutterActorMeta *meta = NULL;
12841   GObjectClass *klass = NULL;
12842   GParamSpec *pspec = NULL;
12843   gchar *p_name = NULL;
12844
12845   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12846                                            property_name,
12847                                            &p_name);
12848
12849   if (meta != NULL)
12850     {
12851       klass = G_OBJECT_GET_CLASS (meta);
12852
12853       pspec = g_object_class_find_property (klass, p_name);
12854     }
12855   else
12856     {
12857       klass = G_OBJECT_GET_CLASS (animatable);
12858
12859       pspec = g_object_class_find_property (klass, property_name);
12860     }
12861
12862   g_free (p_name);
12863
12864   return pspec;
12865 }
12866
12867 static void
12868 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12869                                  const gchar       *property_name,
12870                                  GValue            *initial)
12871 {
12872   ClutterActorMeta *meta = NULL;
12873   gchar *p_name = NULL;
12874
12875   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12876                                            property_name,
12877                                            &p_name);
12878
12879   if (meta != NULL)
12880     g_object_get_property (G_OBJECT (meta), p_name, initial);
12881   else
12882     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12883
12884   g_free (p_name);
12885 }
12886
12887 /*
12888  * clutter_actor_set_animatable_property:
12889  * @actor: a #ClutterActor
12890  * @prop_id: the paramspec id
12891  * @value: the value to set
12892  * @pspec: the paramspec
12893  *
12894  * Sets values of animatable properties.
12895  *
12896  * This is a variant of clutter_actor_set_property() that gets called
12897  * by the #ClutterAnimatable implementation of #ClutterActor for the
12898  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12899  * #GParamSpec.
12900  *
12901  * Unlike the implementation of #GObjectClass.set_property(), this
12902  * function will not update the interval if a transition involving an
12903  * animatable property is in progress - this avoids cycles with the
12904  * transition API calling the public API.
12905  */
12906 static void
12907 clutter_actor_set_animatable_property (ClutterActor *actor,
12908                                        guint         prop_id,
12909                                        const GValue *value,
12910                                        GParamSpec   *pspec)
12911 {
12912   GObject *obj = G_OBJECT (actor);
12913
12914   g_object_freeze_notify (obj);
12915
12916   switch (prop_id)
12917     {
12918     case PROP_X:
12919       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12920       break;
12921
12922     case PROP_Y:
12923       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12924       break;
12925
12926     case PROP_WIDTH:
12927       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12928       break;
12929
12930     case PROP_HEIGHT:
12931       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12932       break;
12933
12934     case PROP_DEPTH:
12935       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12936       break;
12937
12938     case PROP_OPACITY:
12939       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12940       break;
12941
12942     case PROP_BACKGROUND_COLOR:
12943       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12944       break;
12945
12946     case PROP_SCALE_X:
12947       clutter_actor_set_scale_factor_internal (actor,
12948                                                g_value_get_double (value),
12949                                                pspec);
12950       break;
12951
12952     case PROP_SCALE_Y:
12953       clutter_actor_set_scale_factor_internal (actor,
12954                                                g_value_get_double (value),
12955                                                pspec);
12956       break;
12957
12958     case PROP_ROTATION_ANGLE_X:
12959       clutter_actor_set_rotation_angle_internal (actor,
12960                                                  CLUTTER_X_AXIS,
12961                                                  g_value_get_double (value));
12962       break;
12963
12964     case PROP_ROTATION_ANGLE_Y:
12965       clutter_actor_set_rotation_angle_internal (actor,
12966                                                  CLUTTER_Y_AXIS,
12967                                                  g_value_get_double (value));
12968       break;
12969
12970     case PROP_ROTATION_ANGLE_Z:
12971       clutter_actor_set_rotation_angle_internal (actor,
12972                                                  CLUTTER_Z_AXIS,
12973                                                  g_value_get_double (value));
12974       break;
12975
12976     default:
12977       g_object_set_property (obj, pspec->name, value);
12978       break;
12979     }
12980
12981   g_object_thaw_notify (obj);
12982 }
12983
12984 static void
12985 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12986                                const gchar       *property_name,
12987                                const GValue      *final)
12988 {
12989   ClutterActor *actor = CLUTTER_ACTOR (animatable);
12990   ClutterActorMeta *meta = NULL;
12991   gchar *p_name = NULL;
12992
12993   meta = get_meta_from_animation_property (actor,
12994                                            property_name,
12995                                            &p_name);
12996   if (meta != NULL)
12997     g_object_set_property (G_OBJECT (meta), p_name, final);
12998   else
12999     {
13000       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13001       GParamSpec *pspec;
13002
13003       pspec = g_object_class_find_property (obj_class, property_name);
13004
13005       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13006         {
13007           /* XXX - I'm going to the special hell for this */
13008           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13009         }
13010       else
13011         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13012     }
13013
13014   g_free (p_name);
13015 }
13016
13017 static void
13018 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13019 {
13020   iface->find_property = clutter_actor_find_property;
13021   iface->get_initial_state = clutter_actor_get_initial_state;
13022   iface->set_final_state = clutter_actor_set_final_state;
13023 }
13024
13025 /**
13026  * clutter_actor_transform_stage_point:
13027  * @self: A #ClutterActor
13028  * @x: (in): x screen coordinate of the point to unproject
13029  * @y: (in): y screen coordinate of the point to unproject
13030  * @x_out: (out): return location for the unprojected x coordinance
13031  * @y_out: (out): return location for the unprojected y coordinance
13032  *
13033  * This function translates screen coordinates (@x, @y) to
13034  * coordinates relative to the actor. For example, it can be used to translate
13035  * screen events from global screen coordinates into actor-local coordinates.
13036  *
13037  * The conversion can fail, notably if the transform stack results in the
13038  * actor being projected on the screen as a mere line.
13039  *
13040  * The conversion should not be expected to be pixel-perfect due to the
13041  * nature of the operation. In general the error grows when the skewing
13042  * of the actor rectangle on screen increases.
13043  *
13044  * <note><para>This function can be computationally intensive.</para></note>
13045  *
13046  * <note><para>This function only works when the allocation is up-to-date,
13047  * i.e. inside of paint().</para></note>
13048  *
13049  * Return value: %TRUE if conversion was successful.
13050  *
13051  * Since: 0.6
13052  */
13053 gboolean
13054 clutter_actor_transform_stage_point (ClutterActor *self,
13055                                      gfloat        x,
13056                                      gfloat        y,
13057                                      gfloat       *x_out,
13058                                      gfloat       *y_out)
13059 {
13060   ClutterVertex v[4];
13061   float ST[3][3];
13062   float RQ[3][3];
13063   int du, dv, xi, yi;
13064   float px, py;
13065   float xf, yf, wf, det;
13066   ClutterActorPrivate *priv;
13067
13068   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13069
13070   priv = self->priv;
13071
13072   /* This implementation is based on the quad -> quad projection algorithm
13073    * described by Paul Heckbert in:
13074    *
13075    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13076    *
13077    * and the sample implementation at:
13078    *
13079    *   http://www.cs.cmu.edu/~ph/src/texfund/
13080    *
13081    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13082    * quad to rectangle only, which significantly simplifies things; the
13083    * function calls have been unrolled, and most of the math is done in fixed
13084    * point.
13085    */
13086
13087   clutter_actor_get_abs_allocation_vertices (self, v);
13088
13089   /* Keeping these as ints simplifies the multiplication (no significant
13090    * loss of precision here).
13091    */
13092   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13093   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13094
13095   if (!du || !dv)
13096     return FALSE;
13097
13098 #define UX2FP(x)        (x)
13099 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13100
13101   /* First, find mapping from unit uv square to xy quadrilateral; this
13102    * equivalent to the pmap_square_quad() functions in the sample
13103    * implementation, which we can simplify, since our target is always
13104    * a rectangle.
13105    */
13106   px = v[0].x - v[1].x + v[3].x - v[2].x;
13107   py = v[0].y - v[1].y + v[3].y - v[2].y;
13108
13109   if (!px && !py)
13110     {
13111       /* affine transform */
13112       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13113       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13114       RQ[2][0] = UX2FP (v[0].x);
13115       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13116       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13117       RQ[2][1] = UX2FP (v[0].y);
13118       RQ[0][2] = 0;
13119       RQ[1][2] = 0;
13120       RQ[2][2] = 1.0;
13121     }
13122   else
13123     {
13124       /* projective transform */
13125       double dx1, dx2, dy1, dy2, del;
13126
13127       dx1 = UX2FP (v[1].x - v[3].x);
13128       dx2 = UX2FP (v[2].x - v[3].x);
13129       dy1 = UX2FP (v[1].y - v[3].y);
13130       dy2 = UX2FP (v[2].y - v[3].y);
13131
13132       del = DET2FP (dx1, dx2, dy1, dy2);
13133       if (!del)
13134         return FALSE;
13135
13136       /*
13137        * The division here needs to be done in floating point for
13138        * precisions reasons.
13139        */
13140       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13141       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13142       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13143       RQ[2][2] = 1.0;
13144       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13145       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13146       RQ[2][0] = UX2FP (v[0].x);
13147       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13148       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13149       RQ[2][1] = UX2FP (v[0].y);
13150     }
13151
13152   /*
13153    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13154    * square. Since our rectangle is based at 0,0 we only need to scale.
13155    */
13156   RQ[0][0] /= du;
13157   RQ[1][0] /= dv;
13158   RQ[0][1] /= du;
13159   RQ[1][1] /= dv;
13160   RQ[0][2] /= du;
13161   RQ[1][2] /= dv;
13162
13163   /*
13164    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13165    * inverse of that.
13166    */
13167   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13168   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13169   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13170   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13171   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13172   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13173   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13174   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13175   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13176
13177   /*
13178    * Check the resulting matrix is OK.
13179    */
13180   det = (RQ[0][0] * ST[0][0])
13181       + (RQ[0][1] * ST[0][1])
13182       + (RQ[0][2] * ST[0][2]);
13183   if (!det)
13184     return FALSE;
13185
13186   /*
13187    * Now transform our point with the ST matrix; the notional w
13188    * coordinate is 1, hence the last part is simply added.
13189    */
13190   xi = (int) x;
13191   yi = (int) y;
13192
13193   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13194   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13195   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13196
13197   if (x_out)
13198     *x_out = xf / wf;
13199
13200   if (y_out)
13201     *y_out = yf / wf;
13202
13203 #undef UX2FP
13204 #undef DET2FP
13205
13206   return TRUE;
13207 }
13208
13209 /*
13210  * ClutterGeometry
13211  */
13212
13213 static ClutterGeometry*
13214 clutter_geometry_copy (const ClutterGeometry *geometry)
13215 {
13216   return g_slice_dup (ClutterGeometry, geometry);
13217 }
13218
13219 static void
13220 clutter_geometry_free (ClutterGeometry *geometry)
13221 {
13222   if (G_LIKELY (geometry != NULL))
13223     g_slice_free (ClutterGeometry, geometry);
13224 }
13225
13226 /**
13227  * clutter_geometry_union:
13228  * @geometry_a: a #ClutterGeometry
13229  * @geometry_b: another #ClutterGeometry
13230  * @result: (out): location to store the result
13231  *
13232  * Find the union of two rectangles represented as #ClutterGeometry.
13233  *
13234  * Since: 1.4
13235  */
13236 void
13237 clutter_geometry_union (const ClutterGeometry *geometry_a,
13238                         const ClutterGeometry *geometry_b,
13239                         ClutterGeometry       *result)
13240 {
13241   /* We don't try to handle rectangles that can't be represented
13242    * as a signed integer box */
13243   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13244   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13245   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13246                   geometry_b->x + (gint)geometry_b->width);
13247   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13248                   geometry_b->y + (gint)geometry_b->height);
13249   result->x = x_1;
13250   result->y = y_1;
13251   result->width = x_2 - x_1;
13252   result->height = y_2 - y_1;
13253 }
13254
13255 /**
13256  * clutter_geometry_intersects:
13257  * @geometry0: The first geometry to test
13258  * @geometry1: The second geometry to test
13259  *
13260  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13261  * they do else %FALSE.
13262  *
13263  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13264  * %FALSE.
13265  *
13266  * Since: 1.4
13267  */
13268 gboolean
13269 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13270                              const ClutterGeometry *geometry1)
13271 {
13272   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13273       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13274       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13275       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13276     return FALSE;
13277   else
13278     return TRUE;
13279 }
13280
13281 static gboolean
13282 clutter_geometry_progress (const GValue *a,
13283                            const GValue *b,
13284                            gdouble       progress,
13285                            GValue       *retval)
13286 {
13287   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13288   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13289   ClutterGeometry res = { 0, };
13290   gint a_width = a_geom->width;
13291   gint b_width = b_geom->width;
13292   gint a_height = a_geom->height;
13293   gint b_height = b_geom->height;
13294
13295   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13296   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13297
13298   res.width = a_width + (b_width - a_width) * progress;
13299   res.height = a_height + (b_height - a_height) * progress;
13300
13301   g_value_set_boxed (retval, &res);
13302
13303   return TRUE;
13304 }
13305
13306 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13307                                clutter_geometry_copy,
13308                                clutter_geometry_free,
13309                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13310
13311 /*
13312  * ClutterVertices
13313  */
13314
13315 /**
13316  * clutter_vertex_new:
13317  * @x: X coordinate
13318  * @y: Y coordinate
13319  * @z: Z coordinate
13320  *
13321  * Creates a new #ClutterVertex for the point in 3D space
13322  * identified by the 3 coordinates @x, @y, @z
13323  *
13324  * Return value: the newly allocate #ClutterVertex. Use
13325  *   clutter_vertex_free() to free the resources
13326  *
13327  * Since: 1.0
13328  */
13329 ClutterVertex *
13330 clutter_vertex_new (gfloat x,
13331                     gfloat y,
13332                     gfloat z)
13333 {
13334   ClutterVertex *vertex;
13335
13336   vertex = g_slice_new (ClutterVertex);
13337   clutter_vertex_init (vertex, x, y, z);
13338
13339   return vertex;
13340 }
13341
13342 /**
13343  * clutter_vertex_init:
13344  * @vertex: a #ClutterVertex
13345  * @x: X coordinate
13346  * @y: Y coordinate
13347  * @z: Z coordinate
13348  *
13349  * Initializes @vertex with the given coordinates.
13350  *
13351  * Since: 1.10
13352  */
13353 void
13354 clutter_vertex_init (ClutterVertex *vertex,
13355                      gfloat         x,
13356                      gfloat         y,
13357                      gfloat         z)
13358 {
13359   g_return_if_fail (vertex != NULL);
13360
13361   vertex->x = x;
13362   vertex->y = y;
13363   vertex->z = z;
13364 }
13365
13366 /**
13367  * clutter_vertex_copy:
13368  * @vertex: a #ClutterVertex
13369  *
13370  * Copies @vertex
13371  *
13372  * Return value: a newly allocated copy of #ClutterVertex. Use
13373  *   clutter_vertex_free() to free the allocated resources
13374  *
13375  * Since: 1.0
13376  */
13377 ClutterVertex *
13378 clutter_vertex_copy (const ClutterVertex *vertex)
13379 {
13380   if (G_LIKELY (vertex != NULL))
13381     return g_slice_dup (ClutterVertex, vertex);
13382
13383   return NULL;
13384 }
13385
13386 /**
13387  * clutter_vertex_free:
13388  * @vertex: a #ClutterVertex
13389  *
13390  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13391  *
13392  * Since: 1.0
13393  */
13394 void
13395 clutter_vertex_free (ClutterVertex *vertex)
13396 {
13397   if (G_UNLIKELY (vertex != NULL))
13398     g_slice_free (ClutterVertex, vertex);
13399 }
13400
13401 /**
13402  * clutter_vertex_equal:
13403  * @vertex_a: a #ClutterVertex
13404  * @vertex_b: a #ClutterVertex
13405  *
13406  * Compares @vertex_a and @vertex_b for equality
13407  *
13408  * Return value: %TRUE if the passed #ClutterVertex are equal
13409  *
13410  * Since: 1.0
13411  */
13412 gboolean
13413 clutter_vertex_equal (const ClutterVertex *vertex_a,
13414                       const ClutterVertex *vertex_b)
13415 {
13416   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13417
13418   if (vertex_a == vertex_b)
13419     return TRUE;
13420
13421   return vertex_a->x == vertex_b->x &&
13422          vertex_a->y == vertex_b->y &&
13423          vertex_a->z == vertex_b->z;
13424 }
13425
13426 static gboolean
13427 clutter_vertex_progress (const GValue *a,
13428                          const GValue *b,
13429                          gdouble       progress,
13430                          GValue       *retval)
13431 {
13432   const ClutterVertex *av = g_value_get_boxed (a);
13433   const ClutterVertex *bv = g_value_get_boxed (b);
13434   ClutterVertex res = { 0, };
13435
13436   res.x = av->x + (bv->x - av->x) * progress;
13437   res.y = av->y + (bv->y - av->y) * progress;
13438   res.z = av->z + (bv->z - av->z) * progress;
13439
13440   g_value_set_boxed (retval, &res);
13441
13442   return TRUE;
13443 }
13444
13445 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13446                                clutter_vertex_copy,
13447                                clutter_vertex_free,
13448                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13449
13450 /**
13451  * clutter_actor_is_rotated:
13452  * @self: a #ClutterActor
13453  *
13454  * Checks whether any rotation is applied to the actor.
13455  *
13456  * Return value: %TRUE if the actor is rotated.
13457  *
13458  * Since: 0.6
13459  */
13460 gboolean
13461 clutter_actor_is_rotated (ClutterActor *self)
13462 {
13463   const ClutterTransformInfo *info;
13464
13465   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13466
13467   info = _clutter_actor_get_transform_info_or_defaults (self);
13468
13469   if (info->rx_angle || info->ry_angle || info->rz_angle)
13470     return TRUE;
13471
13472   return FALSE;
13473 }
13474
13475 /**
13476  * clutter_actor_is_scaled:
13477  * @self: a #ClutterActor
13478  *
13479  * Checks whether the actor is scaled in either dimension.
13480  *
13481  * Return value: %TRUE if the actor is scaled.
13482  *
13483  * Since: 0.6
13484  */
13485 gboolean
13486 clutter_actor_is_scaled (ClutterActor *self)
13487 {
13488   const ClutterTransformInfo *info;
13489
13490   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13491
13492   info = _clutter_actor_get_transform_info_or_defaults (self);
13493
13494   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13495     return TRUE;
13496
13497   return FALSE;
13498 }
13499
13500 ClutterActor *
13501 _clutter_actor_get_stage_internal (ClutterActor *actor)
13502 {
13503   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13504     actor = actor->priv->parent;
13505
13506   return actor;
13507 }
13508
13509 /**
13510  * clutter_actor_get_stage:
13511  * @actor: a #ClutterActor
13512  *
13513  * Retrieves the #ClutterStage where @actor is contained.
13514  *
13515  * Return value: (transfer none) (type Clutter.Stage): the stage
13516  *   containing the actor, or %NULL
13517  *
13518  * Since: 0.8
13519  */
13520 ClutterActor *
13521 clutter_actor_get_stage (ClutterActor *actor)
13522 {
13523   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13524
13525   return _clutter_actor_get_stage_internal (actor);
13526 }
13527
13528 /**
13529  * clutter_actor_allocate_available_size:
13530  * @self: a #ClutterActor
13531  * @x: the actor's X coordinate
13532  * @y: the actor's Y coordinate
13533  * @available_width: the maximum available width, or -1 to use the
13534  *   actor's natural width
13535  * @available_height: the maximum available height, or -1 to use the
13536  *   actor's natural height
13537  * @flags: flags controlling the allocation
13538  *
13539  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13540  * preferred size, but limiting it to the maximum available width
13541  * and height provided.
13542  *
13543  * This function will do the right thing when dealing with the
13544  * actor's request mode.
13545  *
13546  * The implementation of this function is equivalent to:
13547  *
13548  * |[
13549  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13550  *     {
13551  *       clutter_actor_get_preferred_width (self, available_height,
13552  *                                          &amp;min_width,
13553  *                                          &amp;natural_width);
13554  *       width = CLAMP (natural_width, min_width, available_width);
13555  *
13556  *       clutter_actor_get_preferred_height (self, width,
13557  *                                           &amp;min_height,
13558  *                                           &amp;natural_height);
13559  *       height = CLAMP (natural_height, min_height, available_height);
13560  *     }
13561  *   else
13562  *     {
13563  *       clutter_actor_get_preferred_height (self, available_width,
13564  *                                           &amp;min_height,
13565  *                                           &amp;natural_height);
13566  *       height = CLAMP (natural_height, min_height, available_height);
13567  *
13568  *       clutter_actor_get_preferred_width (self, height,
13569  *                                          &amp;min_width,
13570  *                                          &amp;natural_width);
13571  *       width = CLAMP (natural_width, min_width, available_width);
13572  *     }
13573  *
13574  *   box.x1 = x; box.y1 = y;
13575  *   box.x2 = box.x1 + available_width;
13576  *   box.y2 = box.y1 + available_height;
13577  *   clutter_actor_allocate (self, &amp;box, flags);
13578  * ]|
13579  *
13580  * This function can be used by fluid layout managers to allocate
13581  * an actor's preferred size without making it bigger than the area
13582  * available for the container.
13583  *
13584  * Since: 1.0
13585  */
13586 void
13587 clutter_actor_allocate_available_size (ClutterActor           *self,
13588                                        gfloat                  x,
13589                                        gfloat                  y,
13590                                        gfloat                  available_width,
13591                                        gfloat                  available_height,
13592                                        ClutterAllocationFlags  flags)
13593 {
13594   ClutterActorPrivate *priv;
13595   gfloat width, height;
13596   gfloat min_width, min_height;
13597   gfloat natural_width, natural_height;
13598   ClutterActorBox box;
13599
13600   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13601
13602   priv = self->priv;
13603
13604   width = height = 0.0;
13605
13606   switch (priv->request_mode)
13607     {
13608     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13609       clutter_actor_get_preferred_width (self, available_height,
13610                                          &min_width,
13611                                          &natural_width);
13612       width  = CLAMP (natural_width, min_width, available_width);
13613
13614       clutter_actor_get_preferred_height (self, width,
13615                                           &min_height,
13616                                           &natural_height);
13617       height = CLAMP (natural_height, min_height, available_height);
13618       break;
13619
13620     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13621       clutter_actor_get_preferred_height (self, available_width,
13622                                           &min_height,
13623                                           &natural_height);
13624       height = CLAMP (natural_height, min_height, available_height);
13625
13626       clutter_actor_get_preferred_width (self, height,
13627                                          &min_width,
13628                                          &natural_width);
13629       width  = CLAMP (natural_width, min_width, available_width);
13630       break;
13631     }
13632
13633
13634   box.x1 = x;
13635   box.y1 = y;
13636   box.x2 = box.x1 + width;
13637   box.y2 = box.y1 + height;
13638   clutter_actor_allocate (self, &box, flags);
13639 }
13640
13641 /**
13642  * clutter_actor_allocate_preferred_size:
13643  * @self: a #ClutterActor
13644  * @flags: flags controlling the allocation
13645  *
13646  * Allocates the natural size of @self.
13647  *
13648  * This function is a utility call for #ClutterActor implementations
13649  * that allocates the actor's preferred natural size. It can be used
13650  * by fixed layout managers (like #ClutterGroup or so called
13651  * 'composite actors') inside the ClutterActor::allocate
13652  * implementation to give each child exactly how much space it
13653  * requires.
13654  *
13655  * This function is not meant to be used by applications. It is also
13656  * not meant to be used outside the implementation of the
13657  * ClutterActor::allocate virtual function.
13658  *
13659  * Since: 0.8
13660  */
13661 void
13662 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13663                                        ClutterAllocationFlags  flags)
13664 {
13665   gfloat actor_x, actor_y;
13666   gfloat natural_width, natural_height;
13667   ClutterActorBox actor_box;
13668
13669   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13670
13671   actor_x = clutter_actor_get_x (self);
13672   actor_y = clutter_actor_get_y (self);
13673
13674   clutter_actor_get_preferred_size (self,
13675                                     NULL, NULL,
13676                                     &natural_width,
13677                                     &natural_height);
13678
13679   actor_box.x1 = actor_x;
13680   actor_box.y1 = actor_y;
13681   actor_box.x2 = actor_box.x1 + natural_width;
13682   actor_box.y2 = actor_box.y1 + natural_height;
13683
13684   clutter_actor_allocate (self, &actor_box, flags);
13685 }
13686
13687 /**
13688  * clutter_actor_allocate_align_fill:
13689  * @self: a #ClutterActor
13690  * @box: a #ClutterActorBox, containing the available width and height
13691  * @x_align: the horizontal alignment, between 0 and 1
13692  * @y_align: the vertical alignment, between 0 and 1
13693  * @x_fill: whether the actor should fill horizontally
13694  * @y_fill: whether the actor should fill vertically
13695  * @flags: allocation flags to be passed to clutter_actor_allocate()
13696  *
13697  * Allocates @self by taking into consideration the available allocation
13698  * area; an alignment factor on either axis; and whether the actor should
13699  * fill the allocation on either axis.
13700  *
13701  * The @box should contain the available allocation width and height;
13702  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13703  * allocation will be offset by their value.
13704  *
13705  * This function takes into consideration the geometry request specified by
13706  * the #ClutterActor:request-mode property, and the text direction.
13707  *
13708  * This function is useful for fluid layout managers, like #ClutterBinLayout
13709  * or #ClutterTableLayout
13710  *
13711  * Since: 1.4
13712  */
13713 void
13714 clutter_actor_allocate_align_fill (ClutterActor           *self,
13715                                    const ClutterActorBox  *box,
13716                                    gdouble                 x_align,
13717                                    gdouble                 y_align,
13718                                    gboolean                x_fill,
13719                                    gboolean                y_fill,
13720                                    ClutterAllocationFlags  flags)
13721 {
13722   ClutterActorPrivate *priv;
13723   ClutterActorBox allocation = { 0, };
13724   gfloat x_offset, y_offset;
13725   gfloat available_width, available_height;
13726   gfloat child_width, child_height;
13727
13728   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13729   g_return_if_fail (box != NULL);
13730   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13731   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13732
13733   priv = self->priv;
13734
13735   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13736   clutter_actor_box_get_size (box, &available_width, &available_height);
13737
13738   if (available_width < 0)
13739     available_width = 0;
13740
13741   if (available_height < 0)
13742     available_height = 0;
13743
13744   if (x_fill)
13745     {
13746       allocation.x1 = x_offset;
13747       allocation.x2 = allocation.x1 + available_width;
13748     }
13749
13750   if (y_fill)
13751     {
13752       allocation.y1 = y_offset;
13753       allocation.y2 = allocation.y1 + available_height;
13754     }
13755
13756   /* if we are filling horizontally and vertically then we're done */
13757   if (x_fill && y_fill)
13758     goto out;
13759
13760   child_width = child_height = 0.0f;
13761
13762   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13763     {
13764       gfloat min_width, natural_width;
13765       gfloat min_height, natural_height;
13766
13767       clutter_actor_get_preferred_width (self, available_height,
13768                                          &min_width,
13769                                          &natural_width);
13770
13771       child_width = CLAMP (natural_width, min_width, available_width);
13772
13773       if (!y_fill)
13774         {
13775           clutter_actor_get_preferred_height (self, child_width,
13776                                               &min_height,
13777                                               &natural_height);
13778
13779           child_height = CLAMP (natural_height, min_height, available_height);
13780         }
13781     }
13782   else
13783     {
13784       gfloat min_width, natural_width;
13785       gfloat min_height, natural_height;
13786
13787       clutter_actor_get_preferred_height (self, available_width,
13788                                           &min_height,
13789                                           &natural_height);
13790
13791       child_height = CLAMP (natural_height, min_height, available_height);
13792
13793       if (!x_fill)
13794         {
13795           clutter_actor_get_preferred_width (self, child_height,
13796                                              &min_width,
13797                                              &natural_width);
13798
13799           child_width = CLAMP (natural_width, min_width, available_width);
13800         }
13801     }
13802
13803   /* invert the horizontal alignment for RTL languages */
13804   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13805     x_align = 1.0 - x_align;
13806
13807   if (!x_fill)
13808     {
13809       allocation.x1 = x_offset
13810                     + ((available_width - child_width) * x_align);
13811       allocation.x2 = allocation.x1 + child_width;
13812     }
13813
13814   if (!y_fill)
13815     {
13816       allocation.y1 = y_offset
13817                     + ((available_height - child_height) * y_align);
13818       allocation.y2 = allocation.y1 + child_height;
13819     }
13820
13821 out:
13822   clutter_actor_box_clamp_to_pixel (&allocation);
13823   clutter_actor_allocate (self, &allocation, flags);
13824 }
13825
13826 /**
13827  * clutter_actor_grab_key_focus:
13828  * @self: a #ClutterActor
13829  *
13830  * Sets the key focus of the #ClutterStage including @self
13831  * to this #ClutterActor.
13832  *
13833  * Since: 1.0
13834  */
13835 void
13836 clutter_actor_grab_key_focus (ClutterActor *self)
13837 {
13838   ClutterActor *stage;
13839
13840   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13841
13842   stage = _clutter_actor_get_stage_internal (self);
13843   if (stage != NULL)
13844     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13845 }
13846
13847 /**
13848  * clutter_actor_get_pango_context:
13849  * @self: a #ClutterActor
13850  *
13851  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13852  * is already configured using the appropriate font map, resolution
13853  * and font options.
13854  *
13855  * Unlike clutter_actor_create_pango_context(), this context is owend
13856  * by the #ClutterActor and it will be updated each time the options
13857  * stored by the #ClutterBackend change.
13858  *
13859  * You can use the returned #PangoContext to create a #PangoLayout
13860  * and render text using cogl_pango_render_layout() to reuse the
13861  * glyphs cache also used by Clutter.
13862  *
13863  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13864  *   The returned #PangoContext is owned by the actor and should not be
13865  *   unreferenced by the application code
13866  *
13867  * Since: 1.0
13868  */
13869 PangoContext *
13870 clutter_actor_get_pango_context (ClutterActor *self)
13871 {
13872   ClutterActorPrivate *priv;
13873
13874   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13875
13876   priv = self->priv;
13877
13878   if (priv->pango_context != NULL)
13879     return priv->pango_context;
13880
13881   priv->pango_context = _clutter_context_get_pango_context ();
13882   g_object_ref (priv->pango_context);
13883
13884   return priv->pango_context;
13885 }
13886
13887 /**
13888  * clutter_actor_create_pango_context:
13889  * @self: a #ClutterActor
13890  *
13891  * Creates a #PangoContext for the given actor. The #PangoContext
13892  * is already configured using the appropriate font map, resolution
13893  * and font options.
13894  *
13895  * See also clutter_actor_get_pango_context().
13896  *
13897  * Return value: (transfer full): the newly created #PangoContext.
13898  *   Use g_object_unref() on the returned value to deallocate its
13899  *   resources
13900  *
13901  * Since: 1.0
13902  */
13903 PangoContext *
13904 clutter_actor_create_pango_context (ClutterActor *self)
13905 {
13906   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13907
13908   return _clutter_context_create_pango_context ();
13909 }
13910
13911 /**
13912  * clutter_actor_create_pango_layout:
13913  * @self: a #ClutterActor
13914  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13915  *
13916  * Creates a new #PangoLayout from the same #PangoContext used
13917  * by the #ClutterActor. The #PangoLayout is already configured
13918  * with the font map, resolution and font options, and the
13919  * given @text.
13920  *
13921  * If you want to keep around a #PangoLayout created by this
13922  * function you will have to connect to the #ClutterBackend::font-changed
13923  * and #ClutterBackend::resolution-changed signals, and call
13924  * pango_layout_context_changed() in response to them.
13925  *
13926  * Return value: (transfer full): the newly created #PangoLayout.
13927  *   Use g_object_unref() when done
13928  *
13929  * Since: 1.0
13930  */
13931 PangoLayout *
13932 clutter_actor_create_pango_layout (ClutterActor *self,
13933                                    const gchar  *text)
13934 {
13935   PangoContext *context;
13936   PangoLayout *layout;
13937
13938   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13939
13940   context = clutter_actor_get_pango_context (self);
13941   layout = pango_layout_new (context);
13942
13943   if (text)
13944     pango_layout_set_text (layout, text, -1);
13945
13946   return layout;
13947 }
13948
13949 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13950  * ClutterOffscreenEffect.
13951  */
13952 void
13953 _clutter_actor_set_opacity_override (ClutterActor *self,
13954                                      gint          opacity)
13955 {
13956   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13957
13958   self->priv->opacity_override = opacity;
13959 }
13960
13961 gint
13962 _clutter_actor_get_opacity_override (ClutterActor *self)
13963 {
13964   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13965
13966   return self->priv->opacity_override;
13967 }
13968
13969 /* Allows you to disable applying the actors model view transform during
13970  * a paint. Used by ClutterClone. */
13971 void
13972 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13973                                                 gboolean      enable)
13974 {
13975   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13976
13977   self->priv->enable_model_view_transform = enable;
13978 }
13979
13980 void
13981 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13982                                           gboolean      enable)
13983 {
13984   ClutterActorPrivate *priv;
13985
13986   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13987
13988   priv = self->priv;
13989
13990   priv->enable_paint_unmapped = enable;
13991
13992   if (priv->enable_paint_unmapped)
13993     {
13994       /* Make sure that the parents of the widget are realized first;
13995        * otherwise checks in clutter_actor_update_map_state() will
13996        * fail.
13997        */
13998       clutter_actor_realize (self);
13999
14000       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14001     }
14002   else
14003     {
14004       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14005     }
14006 }
14007
14008 static void
14009 clutter_anchor_coord_get_units (ClutterActor      *self,
14010                                 const AnchorCoord *coord,
14011                                 gfloat            *x,
14012                                 gfloat            *y,
14013                                 gfloat            *z)
14014 {
14015   if (coord->is_fractional)
14016     {
14017       gfloat actor_width, actor_height;
14018
14019       clutter_actor_get_size (self, &actor_width, &actor_height);
14020
14021       if (x)
14022         *x = actor_width * coord->v.fraction.x;
14023
14024       if (y)
14025         *y = actor_height * coord->v.fraction.y;
14026
14027       if (z)
14028         *z = 0;
14029     }
14030   else
14031     {
14032       if (x)
14033         *x = coord->v.units.x;
14034
14035       if (y)
14036         *y = coord->v.units.y;
14037
14038       if (z)
14039         *z = coord->v.units.z;
14040     }
14041 }
14042
14043 static void
14044 clutter_anchor_coord_set_units (AnchorCoord *coord,
14045                                 gfloat       x,
14046                                 gfloat       y,
14047                                 gfloat       z)
14048 {
14049   coord->is_fractional = FALSE;
14050   coord->v.units.x = x;
14051   coord->v.units.y = y;
14052   coord->v.units.z = z;
14053 }
14054
14055 static ClutterGravity
14056 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14057 {
14058   if (coord->is_fractional)
14059     {
14060       if (coord->v.fraction.x == 0.0)
14061         {
14062           if (coord->v.fraction.y == 0.0)
14063             return CLUTTER_GRAVITY_NORTH_WEST;
14064           else if (coord->v.fraction.y == 0.5)
14065             return CLUTTER_GRAVITY_WEST;
14066           else if (coord->v.fraction.y == 1.0)
14067             return CLUTTER_GRAVITY_SOUTH_WEST;
14068           else
14069             return CLUTTER_GRAVITY_NONE;
14070         }
14071       else if (coord->v.fraction.x == 0.5)
14072         {
14073           if (coord->v.fraction.y == 0.0)
14074             return CLUTTER_GRAVITY_NORTH;
14075           else if (coord->v.fraction.y == 0.5)
14076             return CLUTTER_GRAVITY_CENTER;
14077           else if (coord->v.fraction.y == 1.0)
14078             return CLUTTER_GRAVITY_SOUTH;
14079           else
14080             return CLUTTER_GRAVITY_NONE;
14081         }
14082       else if (coord->v.fraction.x == 1.0)
14083         {
14084           if (coord->v.fraction.y == 0.0)
14085             return CLUTTER_GRAVITY_NORTH_EAST;
14086           else if (coord->v.fraction.y == 0.5)
14087             return CLUTTER_GRAVITY_EAST;
14088           else if (coord->v.fraction.y == 1.0)
14089             return CLUTTER_GRAVITY_SOUTH_EAST;
14090           else
14091             return CLUTTER_GRAVITY_NONE;
14092         }
14093       else
14094         return CLUTTER_GRAVITY_NONE;
14095     }
14096   else
14097     return CLUTTER_GRAVITY_NONE;
14098 }
14099
14100 static void
14101 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14102                                   ClutterGravity  gravity)
14103 {
14104   switch (gravity)
14105     {
14106     case CLUTTER_GRAVITY_NORTH:
14107       coord->v.fraction.x = 0.5;
14108       coord->v.fraction.y = 0.0;
14109       break;
14110
14111     case CLUTTER_GRAVITY_NORTH_EAST:
14112       coord->v.fraction.x = 1.0;
14113       coord->v.fraction.y = 0.0;
14114       break;
14115
14116     case CLUTTER_GRAVITY_EAST:
14117       coord->v.fraction.x = 1.0;
14118       coord->v.fraction.y = 0.5;
14119       break;
14120
14121     case CLUTTER_GRAVITY_SOUTH_EAST:
14122       coord->v.fraction.x = 1.0;
14123       coord->v.fraction.y = 1.0;
14124       break;
14125
14126     case CLUTTER_GRAVITY_SOUTH:
14127       coord->v.fraction.x = 0.5;
14128       coord->v.fraction.y = 1.0;
14129       break;
14130
14131     case CLUTTER_GRAVITY_SOUTH_WEST:
14132       coord->v.fraction.x = 0.0;
14133       coord->v.fraction.y = 1.0;
14134       break;
14135
14136     case CLUTTER_GRAVITY_WEST:
14137       coord->v.fraction.x = 0.0;
14138       coord->v.fraction.y = 0.5;
14139       break;
14140
14141     case CLUTTER_GRAVITY_NORTH_WEST:
14142       coord->v.fraction.x = 0.0;
14143       coord->v.fraction.y = 0.0;
14144       break;
14145
14146     case CLUTTER_GRAVITY_CENTER:
14147       coord->v.fraction.x = 0.5;
14148       coord->v.fraction.y = 0.5;
14149       break;
14150
14151     default:
14152       coord->v.fraction.x = 0.0;
14153       coord->v.fraction.y = 0.0;
14154       break;
14155     }
14156
14157   coord->is_fractional = TRUE;
14158 }
14159
14160 static gboolean
14161 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14162 {
14163   if (coord->is_fractional)
14164     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14165   else
14166     return (coord->v.units.x == 0.0
14167             && coord->v.units.y == 0.0
14168             && coord->v.units.z == 0.0);
14169 }
14170
14171 /**
14172  * clutter_actor_get_flags:
14173  * @self: a #ClutterActor
14174  *
14175  * Retrieves the flags set on @self
14176  *
14177  * Return value: a bitwise or of #ClutterActorFlags or 0
14178  *
14179  * Since: 1.0
14180  */
14181 ClutterActorFlags
14182 clutter_actor_get_flags (ClutterActor *self)
14183 {
14184   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14185
14186   return self->flags;
14187 }
14188
14189 /**
14190  * clutter_actor_set_flags:
14191  * @self: a #ClutterActor
14192  * @flags: the flags to set
14193  *
14194  * Sets @flags on @self
14195  *
14196  * This function will emit notifications for the changed properties
14197  *
14198  * Since: 1.0
14199  */
14200 void
14201 clutter_actor_set_flags (ClutterActor      *self,
14202                          ClutterActorFlags  flags)
14203 {
14204   ClutterActorFlags old_flags;
14205   GObject *obj;
14206   gboolean was_reactive_set, reactive_set;
14207   gboolean was_realized_set, realized_set;
14208   gboolean was_mapped_set, mapped_set;
14209   gboolean was_visible_set, visible_set;
14210
14211   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14212
14213   if (self->flags == flags)
14214     return;
14215
14216   obj = G_OBJECT (self);
14217   g_object_ref (obj);
14218   g_object_freeze_notify (obj);
14219
14220   old_flags = self->flags;
14221
14222   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14223   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14224   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14225   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14226
14227   self->flags |= flags;
14228
14229   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14230   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14231   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14232   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14233
14234   if (reactive_set != was_reactive_set)
14235     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14236
14237   if (realized_set != was_realized_set)
14238     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14239
14240   if (mapped_set != was_mapped_set)
14241     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14242
14243   if (visible_set != was_visible_set)
14244     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14245
14246   g_object_thaw_notify (obj);
14247   g_object_unref (obj);
14248 }
14249
14250 /**
14251  * clutter_actor_unset_flags:
14252  * @self: a #ClutterActor
14253  * @flags: the flags to unset
14254  *
14255  * Unsets @flags on @self
14256  *
14257  * This function will emit notifications for the changed properties
14258  *
14259  * Since: 1.0
14260  */
14261 void
14262 clutter_actor_unset_flags (ClutterActor      *self,
14263                            ClutterActorFlags  flags)
14264 {
14265   ClutterActorFlags old_flags;
14266   GObject *obj;
14267   gboolean was_reactive_set, reactive_set;
14268   gboolean was_realized_set, realized_set;
14269   gboolean was_mapped_set, mapped_set;
14270   gboolean was_visible_set, visible_set;
14271
14272   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14273
14274   obj = G_OBJECT (self);
14275   g_object_freeze_notify (obj);
14276
14277   old_flags = self->flags;
14278
14279   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14280   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14281   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14282   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14283
14284   self->flags &= ~flags;
14285
14286   if (self->flags == old_flags)
14287     return;
14288
14289   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14290   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14291   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14292   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14293
14294   if (reactive_set != was_reactive_set)
14295     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14296
14297   if (realized_set != was_realized_set)
14298     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14299
14300   if (mapped_set != was_mapped_set)
14301     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14302
14303   if (visible_set != was_visible_set)
14304     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14305
14306   g_object_thaw_notify (obj);
14307 }
14308
14309 /**
14310  * clutter_actor_get_transformation_matrix:
14311  * @self: a #ClutterActor
14312  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14313  *
14314  * Retrieves the transformations applied to @self relative to its
14315  * parent.
14316  *
14317  * Since: 1.0
14318  */
14319 void
14320 clutter_actor_get_transformation_matrix (ClutterActor *self,
14321                                          CoglMatrix   *matrix)
14322 {
14323   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14324
14325   cogl_matrix_init_identity (matrix);
14326
14327   _clutter_actor_apply_modelview_transform (self, matrix);
14328 }
14329
14330 void
14331 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14332                                    gboolean      is_in_clone_paint)
14333 {
14334   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14335   self->priv->in_clone_paint = is_in_clone_paint;
14336 }
14337
14338 /**
14339  * clutter_actor_is_in_clone_paint:
14340  * @self: a #ClutterActor
14341  *
14342  * Checks whether @self is being currently painted by a #ClutterClone
14343  *
14344  * This function is useful only inside the ::paint virtual function
14345  * implementations or within handlers for the #ClutterActor::paint
14346  * signal
14347  *
14348  * This function should not be used by applications
14349  *
14350  * Return value: %TRUE if the #ClutterActor is currently being painted
14351  *   by a #ClutterClone, and %FALSE otherwise
14352  *
14353  * Since: 1.0
14354  */
14355 gboolean
14356 clutter_actor_is_in_clone_paint (ClutterActor *self)
14357 {
14358   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14359
14360   return self->priv->in_clone_paint;
14361 }
14362
14363 static gboolean
14364 set_direction_recursive (ClutterActor *actor,
14365                          gpointer      user_data)
14366 {
14367   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14368
14369   clutter_actor_set_text_direction (actor, text_dir);
14370
14371   return TRUE;
14372 }
14373
14374 /**
14375  * clutter_actor_set_text_direction:
14376  * @self: a #ClutterActor
14377  * @text_dir: the text direction for @self
14378  *
14379  * Sets the #ClutterTextDirection for an actor
14380  *
14381  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14382  *
14383  * If @self implements #ClutterContainer then this function will recurse
14384  * inside all the children of @self (including the internal ones).
14385  *
14386  * Composite actors not implementing #ClutterContainer, or actors requiring
14387  * special handling when the text direction changes, should connect to
14388  * the #GObject::notify signal for the #ClutterActor:text-direction property
14389  *
14390  * Since: 1.2
14391  */
14392 void
14393 clutter_actor_set_text_direction (ClutterActor         *self,
14394                                   ClutterTextDirection  text_dir)
14395 {
14396   ClutterActorPrivate *priv;
14397
14398   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14399   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14400
14401   priv = self->priv;
14402
14403   if (priv->text_direction != text_dir)
14404     {
14405       priv->text_direction = text_dir;
14406
14407       /* we need to emit the notify::text-direction first, so that
14408        * the sub-classes can catch that and do specific handling of
14409        * the text direction; see clutter_text_direction_changed_cb()
14410        * inside clutter-text.c
14411        */
14412       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14413
14414       _clutter_actor_foreach_child (self, set_direction_recursive,
14415                                     GINT_TO_POINTER (text_dir));
14416
14417       clutter_actor_queue_relayout (self);
14418     }
14419 }
14420
14421 void
14422 _clutter_actor_set_has_pointer (ClutterActor *self,
14423                                 gboolean      has_pointer)
14424 {
14425   ClutterActorPrivate *priv = self->priv;
14426
14427   if (priv->has_pointer != has_pointer)
14428     {
14429       priv->has_pointer = has_pointer;
14430
14431       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14432     }
14433 }
14434
14435 /**
14436  * clutter_actor_get_text_direction:
14437  * @self: a #ClutterActor
14438  *
14439  * Retrieves the value set using clutter_actor_set_text_direction()
14440  *
14441  * If no text direction has been previously set, the default text
14442  * direction, as returned by clutter_get_default_text_direction(), will
14443  * be returned instead
14444  *
14445  * Return value: the #ClutterTextDirection for the actor
14446  *
14447  * Since: 1.2
14448  */
14449 ClutterTextDirection
14450 clutter_actor_get_text_direction (ClutterActor *self)
14451 {
14452   ClutterActorPrivate *priv;
14453
14454   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14455                         CLUTTER_TEXT_DIRECTION_LTR);
14456
14457   priv = self->priv;
14458
14459   /* if no direction has been set yet use the default */
14460   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14461     priv->text_direction = clutter_get_default_text_direction ();
14462
14463   return priv->text_direction;
14464 }
14465
14466 /**
14467  * clutter_actor_push_internal:
14468  * @self: a #ClutterActor
14469  *
14470  * Should be used by actors implementing the #ClutterContainer and with
14471  * internal children added through clutter_actor_set_parent(), for instance:
14472  *
14473  * |[
14474  *   static void
14475  *   my_actor_init (MyActor *self)
14476  *   {
14477  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14478  *
14479  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14480  *
14481  *     /&ast; calling clutter_actor_set_parent() now will result in
14482  *      &ast; the internal flag being set on a child of MyActor
14483  *      &ast;/
14484  *
14485  *     /&ast; internal child - a background texture &ast;/
14486  *     self->priv->background_tex = clutter_texture_new ();
14487  *     clutter_actor_set_parent (self->priv->background_tex,
14488  *                               CLUTTER_ACTOR (self));
14489  *
14490  *     /&ast; internal child - a label &ast;/
14491  *     self->priv->label = clutter_text_new ();
14492  *     clutter_actor_set_parent (self->priv->label,
14493  *                               CLUTTER_ACTOR (self));
14494  *
14495  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14496  *
14497  *     /&ast; calling clutter_actor_set_parent() now will not result in
14498  *      &ast; the internal flag being set on a child of MyActor
14499  *      &ast;/
14500  *   }
14501  * ]|
14502  *
14503  * This function will be used by Clutter to toggle an "internal child"
14504  * flag whenever clutter_actor_set_parent() is called; internal children
14505  * are handled differently by Clutter, specifically when destroying their
14506  * parent.
14507  *
14508  * Call clutter_actor_pop_internal() when you finished adding internal
14509  * children.
14510  *
14511  * Nested calls to clutter_actor_push_internal() are allowed, but each
14512  * one must by followed by a clutter_actor_pop_internal() call.
14513  *
14514  * Since: 1.2
14515  *
14516  * Deprecated: 1.10: All children of an actor are accessible through
14517  *   the #ClutterActor API, and #ClutterActor implements the
14518  *   #ClutterContainer interface, so this function is only useful
14519  *   for legacy containers overriding the default implementation.
14520  */
14521 void
14522 clutter_actor_push_internal (ClutterActor *self)
14523 {
14524   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14525
14526   self->priv->internal_child += 1;
14527 }
14528
14529 /**
14530  * clutter_actor_pop_internal:
14531  * @self: a #ClutterActor
14532  *
14533  * Disables the effects of clutter_actor_push_internal().
14534  *
14535  * Since: 1.2
14536  *
14537  * Deprecated: 1.10: All children of an actor are accessible through
14538  *   the #ClutterActor API. This function is only useful for legacy
14539  *   containers overriding the default implementation of the
14540  *   #ClutterContainer interface.
14541  */
14542 void
14543 clutter_actor_pop_internal (ClutterActor *self)
14544 {
14545   ClutterActorPrivate *priv;
14546
14547   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14548
14549   priv = self->priv;
14550
14551   if (priv->internal_child == 0)
14552     {
14553       g_warning ("Mismatched %s: you need to call "
14554                  "clutter_actor_push_composite() at least once before "
14555                  "calling this function", G_STRFUNC);
14556       return;
14557     }
14558
14559   priv->internal_child -= 1;
14560 }
14561
14562 /**
14563  * clutter_actor_has_pointer:
14564  * @self: a #ClutterActor
14565  *
14566  * Checks whether an actor contains the pointer of a
14567  * #ClutterInputDevice
14568  *
14569  * Return value: %TRUE if the actor contains the pointer, and
14570  *   %FALSE otherwise
14571  *
14572  * Since: 1.2
14573  */
14574 gboolean
14575 clutter_actor_has_pointer (ClutterActor *self)
14576 {
14577   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14578
14579   return self->priv->has_pointer;
14580 }
14581
14582 /* XXX: This is a workaround for not being able to break the ABI of
14583  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14584  * clutter_actor_queue_clipped_redraw() for details.
14585  */
14586 ClutterPaintVolume *
14587 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14588 {
14589   return g_object_get_data (G_OBJECT (self),
14590                             "-clutter-actor-queue-redraw-clip");
14591 }
14592
14593 void
14594 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14595                                       ClutterPaintVolume *clip)
14596 {
14597   g_object_set_data (G_OBJECT (self),
14598                      "-clutter-actor-queue-redraw-clip",
14599                      clip);
14600 }
14601
14602 /**
14603  * clutter_actor_has_allocation:
14604  * @self: a #ClutterActor
14605  *
14606  * Checks if the actor has an up-to-date allocation assigned to
14607  * it. This means that the actor should have an allocation: it's
14608  * visible and has a parent. It also means that there is no
14609  * outstanding relayout request in progress for the actor or its
14610  * children (There might be other outstanding layout requests in
14611  * progress that will cause the actor to get a new allocation
14612  * when the stage is laid out, however).
14613  *
14614  * If this function returns %FALSE, then the actor will normally
14615  * be allocated before it is next drawn on the screen.
14616  *
14617  * Return value: %TRUE if the actor has an up-to-date allocation
14618  *
14619  * Since: 1.4
14620  */
14621 gboolean
14622 clutter_actor_has_allocation (ClutterActor *self)
14623 {
14624   ClutterActorPrivate *priv;
14625
14626   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14627
14628   priv = self->priv;
14629
14630   return priv->parent != NULL &&
14631          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14632          !priv->needs_allocation;
14633 }
14634
14635 /**
14636  * clutter_actor_add_action:
14637  * @self: a #ClutterActor
14638  * @action: a #ClutterAction
14639  *
14640  * Adds @action to the list of actions applied to @self
14641  *
14642  * A #ClutterAction can only belong to one actor at a time
14643  *
14644  * The #ClutterActor will hold a reference on @action until either
14645  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14646  * is called
14647  *
14648  * Since: 1.4
14649  */
14650 void
14651 clutter_actor_add_action (ClutterActor  *self,
14652                           ClutterAction *action)
14653 {
14654   ClutterActorPrivate *priv;
14655
14656   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14657   g_return_if_fail (CLUTTER_IS_ACTION (action));
14658
14659   priv = self->priv;
14660
14661   if (priv->actions == NULL)
14662     {
14663       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14664       priv->actions->actor = self;
14665     }
14666
14667   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14668
14669   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14670 }
14671
14672 /**
14673  * clutter_actor_add_action_with_name:
14674  * @self: a #ClutterActor
14675  * @name: the name to set on the action
14676  * @action: a #ClutterAction
14677  *
14678  * A convenience function for setting the name of a #ClutterAction
14679  * while adding it to the list of actions applied to @self
14680  *
14681  * This function is the logical equivalent of:
14682  *
14683  * |[
14684  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14685  *   clutter_actor_add_action (self, action);
14686  * ]|
14687  *
14688  * Since: 1.4
14689  */
14690 void
14691 clutter_actor_add_action_with_name (ClutterActor  *self,
14692                                     const gchar   *name,
14693                                     ClutterAction *action)
14694 {
14695   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14696   g_return_if_fail (name != NULL);
14697   g_return_if_fail (CLUTTER_IS_ACTION (action));
14698
14699   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14700   clutter_actor_add_action (self, action);
14701 }
14702
14703 /**
14704  * clutter_actor_remove_action:
14705  * @self: a #ClutterActor
14706  * @action: a #ClutterAction
14707  *
14708  * Removes @action from the list of actions applied to @self
14709  *
14710  * The reference held by @self on the #ClutterAction will be released
14711  *
14712  * Since: 1.4
14713  */
14714 void
14715 clutter_actor_remove_action (ClutterActor  *self,
14716                              ClutterAction *action)
14717 {
14718   ClutterActorPrivate *priv;
14719
14720   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14721   g_return_if_fail (CLUTTER_IS_ACTION (action));
14722
14723   priv = self->priv;
14724
14725   if (priv->actions == NULL)
14726     return;
14727
14728   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14729
14730   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14731 }
14732
14733 /**
14734  * clutter_actor_remove_action_by_name:
14735  * @self: a #ClutterActor
14736  * @name: the name of the action to remove
14737  *
14738  * Removes the #ClutterAction with the given name from the list
14739  * of actions applied to @self
14740  *
14741  * Since: 1.4
14742  */
14743 void
14744 clutter_actor_remove_action_by_name (ClutterActor *self,
14745                                      const gchar  *name)
14746 {
14747   ClutterActorPrivate *priv;
14748   ClutterActorMeta *meta;
14749
14750   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14751   g_return_if_fail (name != NULL);
14752
14753   priv = self->priv;
14754
14755   if (priv->actions == NULL)
14756     return;
14757
14758   meta = _clutter_meta_group_get_meta (priv->actions, name);
14759   if (meta == NULL)
14760     return;
14761
14762   _clutter_meta_group_remove_meta (priv->actions, meta);
14763
14764   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14765 }
14766
14767 /**
14768  * clutter_actor_get_actions:
14769  * @self: a #ClutterActor
14770  *
14771  * Retrieves the list of actions applied to @self
14772  *
14773  * Return value: (transfer container) (element-type Clutter.Action): a copy
14774  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14775  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14776  *   allocated by the returned #GList
14777  *
14778  * Since: 1.4
14779  */
14780 GList *
14781 clutter_actor_get_actions (ClutterActor *self)
14782 {
14783   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14784
14785   if (self->priv->actions == NULL)
14786     return NULL;
14787
14788   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14789 }
14790
14791 /**
14792  * clutter_actor_get_action:
14793  * @self: a #ClutterActor
14794  * @name: the name of the action to retrieve
14795  *
14796  * Retrieves the #ClutterAction with the given name in the list
14797  * of actions applied to @self
14798  *
14799  * Return value: (transfer none): a #ClutterAction for the given
14800  *   name, or %NULL. The returned #ClutterAction is owned by the
14801  *   actor and it should not be unreferenced directly
14802  *
14803  * Since: 1.4
14804  */
14805 ClutterAction *
14806 clutter_actor_get_action (ClutterActor *self,
14807                           const gchar  *name)
14808 {
14809   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14810   g_return_val_if_fail (name != NULL, NULL);
14811
14812   if (self->priv->actions == NULL)
14813     return NULL;
14814
14815   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14816 }
14817
14818 /**
14819  * clutter_actor_clear_actions:
14820  * @self: a #ClutterActor
14821  *
14822  * Clears the list of actions applied to @self
14823  *
14824  * Since: 1.4
14825  */
14826 void
14827 clutter_actor_clear_actions (ClutterActor *self)
14828 {
14829   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14830
14831   if (self->priv->actions == NULL)
14832     return;
14833
14834   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14835 }
14836
14837 /**
14838  * clutter_actor_add_constraint:
14839  * @self: a #ClutterActor
14840  * @constraint: a #ClutterConstraint
14841  *
14842  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14843  * to @self
14844  *
14845  * The #ClutterActor will hold a reference on the @constraint until
14846  * either clutter_actor_remove_constraint() or
14847  * clutter_actor_clear_constraints() is called.
14848  *
14849  * Since: 1.4
14850  */
14851 void
14852 clutter_actor_add_constraint (ClutterActor      *self,
14853                               ClutterConstraint *constraint)
14854 {
14855   ClutterActorPrivate *priv;
14856
14857   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14858   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14859
14860   priv = self->priv;
14861
14862   if (priv->constraints == NULL)
14863     {
14864       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14865       priv->constraints->actor = self;
14866     }
14867
14868   _clutter_meta_group_add_meta (priv->constraints,
14869                                 CLUTTER_ACTOR_META (constraint));
14870   clutter_actor_queue_relayout (self);
14871
14872   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14873 }
14874
14875 /**
14876  * clutter_actor_add_constraint_with_name:
14877  * @self: a #ClutterActor
14878  * @name: the name to set on the constraint
14879  * @constraint: a #ClutterConstraint
14880  *
14881  * A convenience function for setting the name of a #ClutterConstraint
14882  * while adding it to the list of constraints applied to @self
14883  *
14884  * This function is the logical equivalent of:
14885  *
14886  * |[
14887  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14888  *   clutter_actor_add_constraint (self, constraint);
14889  * ]|
14890  *
14891  * Since: 1.4
14892  */
14893 void
14894 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14895                                         const gchar       *name,
14896                                         ClutterConstraint *constraint)
14897 {
14898   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14899   g_return_if_fail (name != NULL);
14900   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14901
14902   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14903   clutter_actor_add_constraint (self, constraint);
14904 }
14905
14906 /**
14907  * clutter_actor_remove_constraint:
14908  * @self: a #ClutterActor
14909  * @constraint: a #ClutterConstraint
14910  *
14911  * Removes @constraint from the list of constraints applied to @self
14912  *
14913  * The reference held by @self on the #ClutterConstraint will be released
14914  *
14915  * Since: 1.4
14916  */
14917 void
14918 clutter_actor_remove_constraint (ClutterActor      *self,
14919                                  ClutterConstraint *constraint)
14920 {
14921   ClutterActorPrivate *priv;
14922
14923   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14924   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14925
14926   priv = self->priv;
14927
14928   if (priv->constraints == NULL)
14929     return;
14930
14931   _clutter_meta_group_remove_meta (priv->constraints,
14932                                    CLUTTER_ACTOR_META (constraint));
14933   clutter_actor_queue_relayout (self);
14934
14935   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14936 }
14937
14938 /**
14939  * clutter_actor_remove_constraint_by_name:
14940  * @self: a #ClutterActor
14941  * @name: the name of the constraint to remove
14942  *
14943  * Removes the #ClutterConstraint with the given name from the list
14944  * of constraints applied to @self
14945  *
14946  * Since: 1.4
14947  */
14948 void
14949 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14950                                          const gchar  *name)
14951 {
14952   ClutterActorPrivate *priv;
14953   ClutterActorMeta *meta;
14954
14955   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14956   g_return_if_fail (name != NULL);
14957
14958   priv = self->priv;
14959
14960   if (priv->constraints == NULL)
14961     return;
14962
14963   meta = _clutter_meta_group_get_meta (priv->constraints, name);
14964   if (meta == NULL)
14965     return;
14966
14967   _clutter_meta_group_remove_meta (priv->constraints, meta);
14968   clutter_actor_queue_relayout (self);
14969 }
14970
14971 /**
14972  * clutter_actor_get_constraints:
14973  * @self: a #ClutterActor
14974  *
14975  * Retrieves the list of constraints applied to @self
14976  *
14977  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14978  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14979  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14980  *   allocated by the returned #GList
14981  *
14982  * Since: 1.4
14983  */
14984 GList *
14985 clutter_actor_get_constraints (ClutterActor *self)
14986 {
14987   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14988
14989   if (self->priv->constraints == NULL)
14990     return NULL;
14991
14992   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14993 }
14994
14995 /**
14996  * clutter_actor_get_constraint:
14997  * @self: a #ClutterActor
14998  * @name: the name of the constraint to retrieve
14999  *
15000  * Retrieves the #ClutterConstraint with the given name in the list
15001  * of constraints applied to @self
15002  *
15003  * Return value: (transfer none): a #ClutterConstraint for the given
15004  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15005  *   actor and it should not be unreferenced directly
15006  *
15007  * Since: 1.4
15008  */
15009 ClutterConstraint *
15010 clutter_actor_get_constraint (ClutterActor *self,
15011                               const gchar  *name)
15012 {
15013   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15014   g_return_val_if_fail (name != NULL, NULL);
15015
15016   if (self->priv->constraints == NULL)
15017     return NULL;
15018
15019   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15020 }
15021
15022 /**
15023  * clutter_actor_clear_constraints:
15024  * @self: a #ClutterActor
15025  *
15026  * Clears the list of constraints applied to @self
15027  *
15028  * Since: 1.4
15029  */
15030 void
15031 clutter_actor_clear_constraints (ClutterActor *self)
15032 {
15033   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15034
15035   if (self->priv->constraints == NULL)
15036     return;
15037
15038   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15039
15040   clutter_actor_queue_relayout (self);
15041 }
15042
15043 /**
15044  * clutter_actor_set_clip_to_allocation:
15045  * @self: a #ClutterActor
15046  * @clip_set: %TRUE to apply a clip tracking the allocation
15047  *
15048  * Sets whether @self should be clipped to the same size as its
15049  * allocation
15050  *
15051  * Since: 1.4
15052  */
15053 void
15054 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15055                                       gboolean      clip_set)
15056 {
15057   ClutterActorPrivate *priv;
15058
15059   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15060
15061   clip_set = !!clip_set;
15062
15063   priv = self->priv;
15064
15065   if (priv->clip_to_allocation != clip_set)
15066     {
15067       priv->clip_to_allocation = clip_set;
15068
15069       clutter_actor_queue_redraw (self);
15070
15071       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15072     }
15073 }
15074
15075 /**
15076  * clutter_actor_get_clip_to_allocation:
15077  * @self: a #ClutterActor
15078  *
15079  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15080  *
15081  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15082  *
15083  * Since: 1.4
15084  */
15085 gboolean
15086 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15087 {
15088   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15089
15090   return self->priv->clip_to_allocation;
15091 }
15092
15093 /**
15094  * clutter_actor_add_effect:
15095  * @self: a #ClutterActor
15096  * @effect: a #ClutterEffect
15097  *
15098  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15099  *
15100  * The #ClutterActor will hold a reference on the @effect until either
15101  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15102  * called.
15103  *
15104  * Since: 1.4
15105  */
15106 void
15107 clutter_actor_add_effect (ClutterActor  *self,
15108                           ClutterEffect *effect)
15109 {
15110   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15111   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15112
15113   _clutter_actor_add_effect_internal (self, effect);
15114
15115   clutter_actor_queue_redraw (self);
15116
15117   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15118 }
15119
15120 /**
15121  * clutter_actor_add_effect_with_name:
15122  * @self: a #ClutterActor
15123  * @name: the name to set on the effect
15124  * @effect: a #ClutterEffect
15125  *
15126  * A convenience function for setting the name of a #ClutterEffect
15127  * while adding it to the list of effectss applied to @self
15128  *
15129  * This function is the logical equivalent of:
15130  *
15131  * |[
15132  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15133  *   clutter_actor_add_effect (self, effect);
15134  * ]|
15135  *
15136  * Since: 1.4
15137  */
15138 void
15139 clutter_actor_add_effect_with_name (ClutterActor  *self,
15140                                     const gchar   *name,
15141                                     ClutterEffect *effect)
15142 {
15143   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15144   g_return_if_fail (name != NULL);
15145   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15146
15147   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15148   clutter_actor_add_effect (self, effect);
15149 }
15150
15151 /**
15152  * clutter_actor_remove_effect:
15153  * @self: a #ClutterActor
15154  * @effect: a #ClutterEffect
15155  *
15156  * Removes @effect from the list of effects applied to @self
15157  *
15158  * The reference held by @self on the #ClutterEffect will be released
15159  *
15160  * Since: 1.4
15161  */
15162 void
15163 clutter_actor_remove_effect (ClutterActor  *self,
15164                              ClutterEffect *effect)
15165 {
15166   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15167   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15168
15169   _clutter_actor_remove_effect_internal (self, effect);
15170
15171   clutter_actor_queue_redraw (self);
15172
15173   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15174 }
15175
15176 /**
15177  * clutter_actor_remove_effect_by_name:
15178  * @self: a #ClutterActor
15179  * @name: the name of the effect to remove
15180  *
15181  * Removes the #ClutterEffect with the given name from the list
15182  * of effects applied to @self
15183  *
15184  * Since: 1.4
15185  */
15186 void
15187 clutter_actor_remove_effect_by_name (ClutterActor *self,
15188                                      const gchar  *name)
15189 {
15190   ClutterActorPrivate *priv;
15191   ClutterActorMeta *meta;
15192
15193   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15194   g_return_if_fail (name != NULL);
15195
15196   priv = self->priv;
15197
15198   if (priv->effects == NULL)
15199     return;
15200
15201   meta = _clutter_meta_group_get_meta (priv->effects, name);
15202   if (meta == NULL)
15203     return;
15204
15205   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15206 }
15207
15208 /**
15209  * clutter_actor_get_effects:
15210  * @self: a #ClutterActor
15211  *
15212  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15213  *
15214  * Return value: (transfer container) (element-type Clutter.Effect): a list
15215  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15216  *   list are owned by Clutter and they should not be freed. You should
15217  *   free the returned list using g_list_free() when done
15218  *
15219  * Since: 1.4
15220  */
15221 GList *
15222 clutter_actor_get_effects (ClutterActor *self)
15223 {
15224   ClutterActorPrivate *priv;
15225
15226   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15227
15228   priv = self->priv;
15229
15230   if (priv->effects == NULL)
15231     return NULL;
15232
15233   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15234 }
15235
15236 /**
15237  * clutter_actor_get_effect:
15238  * @self: a #ClutterActor
15239  * @name: the name of the effect to retrieve
15240  *
15241  * Retrieves the #ClutterEffect with the given name in the list
15242  * of effects applied to @self
15243  *
15244  * Return value: (transfer none): a #ClutterEffect for the given
15245  *   name, or %NULL. The returned #ClutterEffect is owned by the
15246  *   actor and it should not be unreferenced directly
15247  *
15248  * Since: 1.4
15249  */
15250 ClutterEffect *
15251 clutter_actor_get_effect (ClutterActor *self,
15252                           const gchar  *name)
15253 {
15254   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15255   g_return_val_if_fail (name != NULL, NULL);
15256
15257   if (self->priv->effects == NULL)
15258     return NULL;
15259
15260   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15261 }
15262
15263 /**
15264  * clutter_actor_clear_effects:
15265  * @self: a #ClutterActor
15266  *
15267  * Clears the list of effects applied to @self
15268  *
15269  * Since: 1.4
15270  */
15271 void
15272 clutter_actor_clear_effects (ClutterActor *self)
15273 {
15274   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15275
15276   if (self->priv->effects == NULL)
15277     return;
15278
15279   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15280
15281   clutter_actor_queue_redraw (self);
15282 }
15283
15284 /**
15285  * clutter_actor_has_key_focus:
15286  * @self: a #ClutterActor
15287  *
15288  * Checks whether @self is the #ClutterActor that has key focus
15289  *
15290  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15291  *
15292  * Since: 1.4
15293  */
15294 gboolean
15295 clutter_actor_has_key_focus (ClutterActor *self)
15296 {
15297   ClutterActor *stage;
15298
15299   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15300
15301   stage = _clutter_actor_get_stage_internal (self);
15302   if (stage == NULL)
15303     return FALSE;
15304
15305   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15306 }
15307
15308 static gboolean
15309 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15310                                       ClutterPaintVolume *pv)
15311 {
15312   ClutterActorPrivate *priv = self->priv;
15313
15314   /* Actors are only expected to report a valid paint volume
15315    * while they have a valid allocation. */
15316   if (G_UNLIKELY (priv->needs_allocation))
15317     {
15318       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15319                     "Actor needs allocation",
15320                     _clutter_actor_get_debug_name (self));
15321       return FALSE;
15322     }
15323
15324   /* Check if there are any handlers connected to the paint
15325    * signal. If there are then all bets are off for what the paint
15326    * volume for this actor might possibly be!
15327    *
15328    * XXX: It's expected that this is going to end up being quite a
15329    * costly check to have to do here, but we haven't come up with
15330    * another solution that can reliably catch paint signal handlers at
15331    * the right time to either avoid artefacts due to invalid stage
15332    * clipping or due to incorrect culling.
15333    *
15334    * Previously we checked in clutter_actor_paint(), but at that time
15335    * we may already be using a stage clip that could be derived from
15336    * an invalid paint-volume. We used to try and handle that by
15337    * queuing a follow up, unclipped, redraw but still the previous
15338    * checking wasn't enough to catch invalid volumes involved in
15339    * culling (considering that containers may derive their volume from
15340    * children that haven't yet been painted)
15341    *
15342    * Longer term, improved solutions could be:
15343    * - Disallow painting in the paint signal, only allow using it
15344    *   for tracking when paints happen. We can add another API that
15345    *   allows monkey patching the paint of arbitrary actors but in a
15346    *   more controlled way and that also supports modifying the
15347    *   paint-volume.
15348    * - If we could be notified somehow when signal handlers are
15349    *   connected we wouldn't have to poll for handlers like this.
15350    */
15351   if (g_signal_has_handler_pending (self,
15352                                     actor_signals[PAINT],
15353                                     0,
15354                                     TRUE))
15355     {
15356       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15357                     "Actor has \"paint\" signal handlers",
15358                     _clutter_actor_get_debug_name (self));
15359       return FALSE;
15360     }
15361
15362   _clutter_paint_volume_init_static (pv, self);
15363
15364   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15365     {
15366       clutter_paint_volume_free (pv);
15367       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15368                     "Actor failed to report a volume",
15369                     _clutter_actor_get_debug_name (self));
15370       return FALSE;
15371     }
15372
15373   /* since effects can modify the paint volume, we allow them to actually
15374    * do this by making get_paint_volume() "context sensitive"
15375    */
15376   if (priv->effects != NULL)
15377     {
15378       if (priv->current_effect != NULL)
15379         {
15380           const GList *effects, *l;
15381
15382           /* if we are being called from within the paint sequence of
15383            * an actor, get the paint volume up to the current effect
15384            */
15385           effects = _clutter_meta_group_peek_metas (priv->effects);
15386           for (l = effects;
15387                l != NULL || (l != NULL && l->data != priv->current_effect);
15388                l = l->next)
15389             {
15390               if (!_clutter_effect_get_paint_volume (l->data, pv))
15391                 {
15392                   clutter_paint_volume_free (pv);
15393                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15394                                 "Effect (%s) failed to report a volume",
15395                                 _clutter_actor_get_debug_name (self),
15396                                 _clutter_actor_meta_get_debug_name (l->data));
15397                   return FALSE;
15398                 }
15399             }
15400         }
15401       else
15402         {
15403           const GList *effects, *l;
15404
15405           /* otherwise, get the cumulative volume */
15406           effects = _clutter_meta_group_peek_metas (priv->effects);
15407           for (l = effects; l != NULL; l = l->next)
15408             if (!_clutter_effect_get_paint_volume (l->data, pv))
15409               {
15410                 clutter_paint_volume_free (pv);
15411                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15412                               "Effect (%s) failed to report a volume",
15413                               _clutter_actor_get_debug_name (self),
15414                               _clutter_actor_meta_get_debug_name (l->data));
15415                 return FALSE;
15416               }
15417         }
15418     }
15419
15420   return TRUE;
15421 }
15422
15423 /* The public clutter_actor_get_paint_volume API returns a const
15424  * pointer since we return a pointer directly to the cached
15425  * PaintVolume associated with the actor and don't want the user to
15426  * inadvertently modify it, but for internal uses we sometimes need
15427  * access to the same PaintVolume but need to apply some book-keeping
15428  * modifications to it so we don't want a const pointer.
15429  */
15430 static ClutterPaintVolume *
15431 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15432 {
15433   ClutterActorPrivate *priv;
15434
15435   priv = self->priv;
15436
15437   if (priv->paint_volume_valid)
15438     clutter_paint_volume_free (&priv->paint_volume);
15439
15440   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15441     {
15442       priv->paint_volume_valid = TRUE;
15443       return &priv->paint_volume;
15444     }
15445   else
15446     {
15447       priv->paint_volume_valid = FALSE;
15448       return NULL;
15449     }
15450 }
15451
15452 /**
15453  * clutter_actor_get_paint_volume:
15454  * @self: a #ClutterActor
15455  *
15456  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15457  * when a paint volume can't be determined.
15458  *
15459  * The paint volume is defined as the 3D space occupied by an actor
15460  * when being painted.
15461  *
15462  * This function will call the <function>get_paint_volume()</function>
15463  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15464  * should not usually care about overriding the default implementation,
15465  * unless they are, for instance: painting outside their allocation, or
15466  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15467  * 3D depth).
15468  *
15469  * <note>2D actors overriding <function>get_paint_volume()</function>
15470  * ensure their volume has a depth of 0. (This will be true so long as
15471  * you don't call clutter_paint_volume_set_depth().)</note>
15472  *
15473  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15474  *   or %NULL if no volume could be determined. The returned pointer
15475  *   is not guaranteed to be valid across multiple frames; if you want
15476  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15477  *
15478  * Since: 1.6
15479  */
15480 const ClutterPaintVolume *
15481 clutter_actor_get_paint_volume (ClutterActor *self)
15482 {
15483   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15484
15485   return _clutter_actor_get_paint_volume_mutable (self);
15486 }
15487
15488 /**
15489  * clutter_actor_get_transformed_paint_volume:
15490  * @self: a #ClutterActor
15491  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15492  *    (or %NULL for the stage)
15493  *
15494  * Retrieves the 3D paint volume of an actor like
15495  * clutter_actor_get_paint_volume() does (Please refer to the
15496  * documentation of clutter_actor_get_paint_volume() for more
15497  * details.) and it additionally transforms the paint volume into the
15498  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15499  * is passed for @relative_to_ancestor)
15500  *
15501  * This can be used by containers that base their paint volume on
15502  * the volume of their children. Such containers can query the
15503  * transformed paint volume of all of its children and union them
15504  * together using clutter_paint_volume_union().
15505  *
15506  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15507  *   or %NULL if no volume could be determined. The returned pointer is
15508  *   not guaranteed to be valid across multiple frames; if you wish to
15509  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15510  *
15511  * Since: 1.6
15512  */
15513 const ClutterPaintVolume *
15514 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15515                                             ClutterActor *relative_to_ancestor)
15516 {
15517   const ClutterPaintVolume *volume;
15518   ClutterActor *stage;
15519   ClutterPaintVolume *transformed_volume;
15520
15521   stage = _clutter_actor_get_stage_internal (self);
15522   if (G_UNLIKELY (stage == NULL))
15523     return NULL;
15524
15525   if (relative_to_ancestor == NULL)
15526     relative_to_ancestor = stage;
15527
15528   volume = clutter_actor_get_paint_volume (self);
15529   if (volume == NULL)
15530     return NULL;
15531
15532   transformed_volume =
15533     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15534
15535   _clutter_paint_volume_copy_static (volume, transformed_volume);
15536
15537   _clutter_paint_volume_transform_relative (transformed_volume,
15538                                             relative_to_ancestor);
15539
15540   return transformed_volume;
15541 }
15542
15543 /**
15544  * clutter_actor_get_paint_box:
15545  * @self: a #ClutterActor
15546  * @box: (out): return location for a #ClutterActorBox
15547  *
15548  * Retrieves the paint volume of the passed #ClutterActor, and
15549  * transforms it into a 2D bounding box in stage coordinates.
15550  *
15551  * This function is useful to determine the on screen area occupied by
15552  * the actor. The box is only an approximation and may often be
15553  * considerably larger due to the optimizations used to calculate the
15554  * box. The box is never smaller though, so it can reliably be used
15555  * for culling.
15556  *
15557  * There are times when a 2D paint box can't be determined, e.g.
15558  * because the actor isn't yet parented under a stage or because
15559  * the actor is unable to determine a paint volume.
15560  *
15561  * Return value: %TRUE if a 2D paint box could be determined, else
15562  * %FALSE.
15563  *
15564  * Since: 1.6
15565  */
15566 gboolean
15567 clutter_actor_get_paint_box (ClutterActor    *self,
15568                              ClutterActorBox *box)
15569 {
15570   ClutterActor *stage;
15571   ClutterPaintVolume *pv;
15572
15573   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15574   g_return_val_if_fail (box != NULL, FALSE);
15575
15576   stage = _clutter_actor_get_stage_internal (self);
15577   if (G_UNLIKELY (!stage))
15578     return FALSE;
15579
15580   pv = _clutter_actor_get_paint_volume_mutable (self);
15581   if (G_UNLIKELY (!pv))
15582     return FALSE;
15583
15584   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15585
15586   return TRUE;
15587 }
15588
15589 /**
15590  * clutter_actor_has_overlaps:
15591  * @self: A #ClutterActor
15592  *
15593  * Asks the actor's implementation whether it may contain overlapping
15594  * primitives.
15595  *
15596  * For example; Clutter may use this to determine whether the painting
15597  * should be redirected to an offscreen buffer to correctly implement
15598  * the opacity property.
15599  *
15600  * Custom actors can override the default response by implementing the
15601  * #ClutterActor <function>has_overlaps</function> virtual function. See
15602  * clutter_actor_set_offscreen_redirect() for more information.
15603  *
15604  * Return value: %TRUE if the actor may have overlapping primitives, and
15605  *   %FALSE otherwise
15606  *
15607  * Since: 1.8
15608  */
15609 gboolean
15610 clutter_actor_has_overlaps (ClutterActor *self)
15611 {
15612   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15613
15614   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15615 }
15616
15617 /**
15618  * clutter_actor_has_effects:
15619  * @self: A #ClutterActor
15620  *
15621  * Returns whether the actor has any effects applied.
15622  *
15623  * Return value: %TRUE if the actor has any effects,
15624  *   %FALSE otherwise
15625  *
15626  * Since: 1.10
15627  */
15628 gboolean
15629 clutter_actor_has_effects (ClutterActor *self)
15630 {
15631   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15632
15633   if (self->priv->effects == NULL)
15634     return FALSE;
15635
15636   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15637 }
15638
15639 /**
15640  * clutter_actor_has_constraints:
15641  * @self: A #ClutterActor
15642  *
15643  * Returns whether the actor has any constraints applied.
15644  *
15645  * Return value: %TRUE if the actor has any constraints,
15646  *   %FALSE otherwise
15647  *
15648  * Since: 1.10
15649  */
15650 gboolean
15651 clutter_actor_has_constraints (ClutterActor *self)
15652 {
15653   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15654
15655   return self->priv->constraints != NULL;
15656 }
15657
15658 /**
15659  * clutter_actor_has_actions:
15660  * @self: A #ClutterActor
15661  *
15662  * Returns whether the actor has any actions applied.
15663  *
15664  * Return value: %TRUE if the actor has any actions,
15665  *   %FALSE otherwise
15666  *
15667  * Since: 1.10
15668  */
15669 gboolean
15670 clutter_actor_has_actions (ClutterActor *self)
15671 {
15672   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15673
15674   return self->priv->actions != NULL;
15675 }
15676
15677 /**
15678  * clutter_actor_get_n_children:
15679  * @self: a #ClutterActor
15680  *
15681  * Retrieves the number of children of @self.
15682  *
15683  * Return value: the number of children of an actor
15684  *
15685  * Since: 1.10
15686  */
15687 gint
15688 clutter_actor_get_n_children (ClutterActor *self)
15689 {
15690   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15691
15692   return self->priv->n_children;
15693 }
15694
15695 /**
15696  * clutter_actor_get_child_at_index:
15697  * @self: a #ClutterActor
15698  * @index_: the position in the list of children
15699  *
15700  * Retrieves the actor at the given @index_ inside the list of
15701  * children of @self.
15702  *
15703  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15704  *
15705  * Since: 1.10
15706  */
15707 ClutterActor *
15708 clutter_actor_get_child_at_index (ClutterActor *self,
15709                                   gint          index_)
15710 {
15711   ClutterActor *iter;
15712   int i;
15713
15714   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15715   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15716
15717   for (iter = self->priv->first_child, i = 0;
15718        iter != NULL && i < index_;
15719        iter = iter->priv->next_sibling, i += 1)
15720     ;
15721
15722   return iter;
15723 }
15724
15725 /*< private >
15726  * _clutter_actor_foreach_child:
15727  * @actor: The actor whos children you want to iterate
15728  * @callback: The function to call for each child
15729  * @user_data: Private data to pass to @callback
15730  *
15731  * Calls a given @callback once for each child of the specified @actor and
15732  * passing the @user_data pointer each time.
15733  *
15734  * Return value: returns %TRUE if all children were iterated, else
15735  *    %FALSE if a callback broke out of iteration early.
15736  */
15737 gboolean
15738 _clutter_actor_foreach_child (ClutterActor           *self,
15739                               ClutterForeachCallback  callback,
15740                               gpointer                user_data)
15741 {
15742   ClutterActorPrivate *priv = self->priv;
15743   ClutterActor *iter;
15744   gboolean cont;
15745
15746   for (cont = TRUE, iter = priv->first_child;
15747        cont && iter != NULL;
15748        iter = iter->priv->next_sibling)
15749     {
15750       cont = callback (iter, user_data);
15751     }
15752
15753   return cont;
15754 }
15755
15756 #if 0
15757 /* For debugging purposes this gives us a simple way to print out
15758  * the scenegraph e.g in gdb using:
15759  * [|
15760  *   _clutter_actor_traverse (stage,
15761  *                            0,
15762  *                            clutter_debug_print_actor_cb,
15763  *                            NULL,
15764  *                            NULL);
15765  * |]
15766  */
15767 static ClutterActorTraverseVisitFlags
15768 clutter_debug_print_actor_cb (ClutterActor *actor,
15769                               int depth,
15770                               void *user_data)
15771 {
15772   g_print ("%*s%s:%p\n",
15773            depth * 2, "",
15774            _clutter_actor_get_debug_name (actor),
15775            actor);
15776
15777   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15778 }
15779 #endif
15780
15781 static void
15782 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15783                                  ClutterTraverseCallback callback,
15784                                  gpointer                user_data)
15785 {
15786   GQueue *queue = g_queue_new ();
15787   ClutterActor dummy;
15788   int current_depth = 0;
15789
15790   g_queue_push_tail (queue, actor);
15791   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15792
15793   while ((actor = g_queue_pop_head (queue)))
15794     {
15795       ClutterActorTraverseVisitFlags flags;
15796
15797       if (actor == &dummy)
15798         {
15799           current_depth++;
15800           g_queue_push_tail (queue, &dummy);
15801           continue;
15802         }
15803
15804       flags = callback (actor, current_depth, user_data);
15805       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15806         break;
15807       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15808         {
15809           ClutterActor *iter;
15810
15811           for (iter = actor->priv->first_child;
15812                iter != NULL;
15813                iter = iter->priv->next_sibling)
15814             {
15815               g_queue_push_tail (queue, iter);
15816             }
15817         }
15818     }
15819
15820   g_queue_free (queue);
15821 }
15822
15823 static ClutterActorTraverseVisitFlags
15824 _clutter_actor_traverse_depth (ClutterActor           *actor,
15825                                ClutterTraverseCallback before_children_callback,
15826                                ClutterTraverseCallback after_children_callback,
15827                                int                     current_depth,
15828                                gpointer                user_data)
15829 {
15830   ClutterActorTraverseVisitFlags flags;
15831
15832   flags = before_children_callback (actor, current_depth, user_data);
15833   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15834     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15835
15836   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15837     {
15838       ClutterActor *iter;
15839
15840       for (iter = actor->priv->first_child;
15841            iter != NULL;
15842            iter = iter->priv->next_sibling)
15843         {
15844           flags = _clutter_actor_traverse_depth (iter,
15845                                                  before_children_callback,
15846                                                  after_children_callback,
15847                                                  current_depth + 1,
15848                                                  user_data);
15849
15850           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15851             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15852         }
15853     }
15854
15855   if (after_children_callback)
15856     return after_children_callback (actor, current_depth, user_data);
15857   else
15858     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15859 }
15860
15861 /* _clutter_actor_traverse:
15862  * @actor: The actor to start traversing the graph from
15863  * @flags: These flags may affect how the traversal is done
15864  * @before_children_callback: A function to call before visiting the
15865  *   children of the current actor.
15866  * @after_children_callback: A function to call after visiting the
15867  *   children of the current actor. (Ignored if
15868  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15869  * @user_data: The private data to pass to the callbacks
15870  *
15871  * Traverses the scenegraph starting at the specified @actor and
15872  * descending through all its children and its children's children.
15873  * For each actor traversed @before_children_callback and
15874  * @after_children_callback are called with the specified
15875  * @user_data, before and after visiting that actor's children.
15876  *
15877  * The callbacks can return flags that affect the ongoing traversal
15878  * such as by skipping over an actors children or bailing out of
15879  * any further traversing.
15880  */
15881 void
15882 _clutter_actor_traverse (ClutterActor              *actor,
15883                          ClutterActorTraverseFlags  flags,
15884                          ClutterTraverseCallback    before_children_callback,
15885                          ClutterTraverseCallback    after_children_callback,
15886                          gpointer                   user_data)
15887 {
15888   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15889     _clutter_actor_traverse_breadth (actor,
15890                                      before_children_callback,
15891                                      user_data);
15892   else /* DEPTH_FIRST */
15893     _clutter_actor_traverse_depth (actor,
15894                                    before_children_callback,
15895                                    after_children_callback,
15896                                    0, /* start depth */
15897                                    user_data);
15898 }
15899
15900 static void
15901 on_layout_manager_changed (ClutterLayoutManager *manager,
15902                            ClutterActor         *self)
15903 {
15904   clutter_actor_queue_relayout (self);
15905 }
15906
15907 /**
15908  * clutter_actor_set_layout_manager:
15909  * @self: a #ClutterActor
15910  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15911  *
15912  * Sets the #ClutterLayoutManager delegate object that will be used to
15913  * lay out the children of @self.
15914  *
15915  * The #ClutterActor will take a reference on the passed @manager which
15916  * will be released either when the layout manager is removed, or when
15917  * the actor is destroyed.
15918  *
15919  * Since: 1.10
15920  */
15921 void
15922 clutter_actor_set_layout_manager (ClutterActor         *self,
15923                                   ClutterLayoutManager *manager)
15924 {
15925   ClutterActorPrivate *priv;
15926
15927   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15928   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15929
15930   priv = self->priv;
15931
15932   if (priv->layout_manager != NULL)
15933     {
15934       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15935                                             G_CALLBACK (on_layout_manager_changed),
15936                                             self);
15937       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15938       g_clear_object (&priv->layout_manager);
15939     }
15940
15941   priv->layout_manager = manager;
15942
15943   if (priv->layout_manager != NULL)
15944     {
15945       g_object_ref_sink (priv->layout_manager);
15946       clutter_layout_manager_set_container (priv->layout_manager,
15947                                             CLUTTER_CONTAINER (self));
15948       g_signal_connect (priv->layout_manager, "layout-changed",
15949                         G_CALLBACK (on_layout_manager_changed),
15950                         self);
15951     }
15952
15953   clutter_actor_queue_relayout (self);
15954
15955   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15956 }
15957
15958 /**
15959  * clutter_actor_get_layout_manager:
15960  * @self: a #ClutterActor
15961  *
15962  * Retrieves the #ClutterLayoutManager used by @self.
15963  *
15964  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15965  *   or %NULL
15966  *
15967  * Since: 1.10
15968  */
15969 ClutterLayoutManager *
15970 clutter_actor_get_layout_manager (ClutterActor *self)
15971 {
15972   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15973
15974   return self->priv->layout_manager;
15975 }
15976
15977 static const ClutterLayoutInfo default_layout_info = {
15978   0.f,                          /* fixed-x */
15979   0.f,                          /* fixed-y */
15980   { 0, 0, 0, 0 },               /* margin */
15981   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
15982   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
15983   0.f, 0.f,                     /* min_width, natural_width */
15984   0.f, 0.f,                     /* natual_width, natural_height */
15985 };
15986
15987 static void
15988 layout_info_free (gpointer data)
15989 {
15990   if (G_LIKELY (data != NULL))
15991     g_slice_free (ClutterLayoutInfo, data);
15992 }
15993
15994 /*< private >
15995  * _clutter_actor_get_layout_info:
15996  * @self: a #ClutterActor
15997  *
15998  * Retrieves a pointer to the ClutterLayoutInfo structure.
15999  *
16000  * If the actor does not have a ClutterLayoutInfo associated to it, one
16001  * will be created and initialized to the default values.
16002  *
16003  * This function should be used for setters.
16004  *
16005  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16006  * instead.
16007  *
16008  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16009  */
16010 ClutterLayoutInfo *
16011 _clutter_actor_get_layout_info (ClutterActor *self)
16012 {
16013   ClutterLayoutInfo *retval;
16014
16015   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16016   if (retval == NULL)
16017     {
16018       retval = g_slice_new (ClutterLayoutInfo);
16019
16020       *retval = default_layout_info;
16021
16022       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16023                                retval,
16024                                layout_info_free);
16025     }
16026
16027   return retval;
16028 }
16029
16030 /*< private >
16031  * _clutter_actor_get_layout_info_or_defaults:
16032  * @self: a #ClutterActor
16033  *
16034  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16035  *
16036  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16037  * then the default structure will be returned.
16038  *
16039  * This function should only be used for getters.
16040  *
16041  * Return value: a const pointer to the ClutterLayoutInfo structure
16042  */
16043 const ClutterLayoutInfo *
16044 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16045 {
16046   const ClutterLayoutInfo *info;
16047
16048   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16049   if (info == NULL)
16050     return &default_layout_info;
16051
16052   return info;
16053 }
16054
16055 /**
16056  * clutter_actor_set_x_align:
16057  * @self: a #ClutterActor
16058  * @x_align: the horizontal alignment policy
16059  *
16060  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16061  * actor received extra horizontal space.
16062  *
16063  * See also the #ClutterActor:x-align property.
16064  *
16065  * Since: 1.10
16066  */
16067 void
16068 clutter_actor_set_x_align (ClutterActor      *self,
16069                            ClutterActorAlign  x_align)
16070 {
16071   ClutterLayoutInfo *info;
16072
16073   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16074
16075   info = _clutter_actor_get_layout_info (self);
16076
16077   if (info->x_align != x_align)
16078     {
16079       info->x_align = x_align;
16080
16081       clutter_actor_queue_relayout (self);
16082
16083       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16084     }
16085 }
16086
16087 /**
16088  * clutter_actor_get_x_align:
16089  * @self: a #ClutterActor
16090  *
16091  * Retrieves the horizontal alignment policy set using
16092  * clutter_actor_set_x_align().
16093  *
16094  * Return value: the horizontal alignment policy.
16095  *
16096  * Since: 1.10
16097  */
16098 ClutterActorAlign
16099 clutter_actor_get_x_align (ClutterActor *self)
16100 {
16101   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16102
16103   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16104 }
16105
16106 /**
16107  * clutter_actor_set_y_align:
16108  * @self: a #ClutterActor
16109  * @y_align: the vertical alignment policy
16110  *
16111  * Sets the vertical alignment policy of a #ClutterActor, in case the
16112  * actor received extra vertical space.
16113  *
16114  * See also the #ClutterActor:y-align property.
16115  *
16116  * Since: 1.10
16117  */
16118 void
16119 clutter_actor_set_y_align (ClutterActor      *self,
16120                            ClutterActorAlign  y_align)
16121 {
16122   ClutterLayoutInfo *info;
16123
16124   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16125
16126   info = _clutter_actor_get_layout_info (self);
16127
16128   if (info->y_align != y_align)
16129     {
16130       info->y_align = y_align;
16131
16132       clutter_actor_queue_relayout (self);
16133
16134       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16135     }
16136 }
16137
16138 /**
16139  * clutter_actor_get_y_align:
16140  * @self: a #ClutterActor
16141  *
16142  * Retrieves the vertical alignment policy set using
16143  * clutter_actor_set_y_align().
16144  *
16145  * Return value: the vertical alignment policy.
16146  *
16147  * Since: 1.10
16148  */
16149 ClutterActorAlign
16150 clutter_actor_get_y_align (ClutterActor *self)
16151 {
16152   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16153
16154   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16155 }
16156
16157
16158 /**
16159  * clutter_margin_new:
16160  *
16161  * Creates a new #ClutterMargin.
16162  *
16163  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16164  *   clutter_margin_free() to free the resources associated with it when
16165  *   done.
16166  *
16167  * Since: 1.10
16168  */
16169 ClutterMargin *
16170 clutter_margin_new (void)
16171 {
16172   return g_slice_new0 (ClutterMargin);
16173 }
16174
16175 /**
16176  * clutter_margin_copy:
16177  * @margin_: a #ClutterMargin
16178  *
16179  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16180  * the newly created structure.
16181  *
16182  * Return value: (transfer full): a copy of the #ClutterMargin.
16183  *
16184  * Since: 1.10
16185  */
16186 ClutterMargin *
16187 clutter_margin_copy (const ClutterMargin *margin_)
16188 {
16189   if (G_LIKELY (margin_ != NULL))
16190     return g_slice_dup (ClutterMargin, margin_);
16191
16192   return NULL;
16193 }
16194
16195 /**
16196  * clutter_margin_free:
16197  * @margin_: a #ClutterMargin
16198  *
16199  * Frees the resources allocated by clutter_margin_new() and
16200  * clutter_margin_copy().
16201  *
16202  * Since: 1.10
16203  */
16204 void
16205 clutter_margin_free (ClutterMargin *margin_)
16206 {
16207   if (G_LIKELY (margin_ != NULL))
16208     g_slice_free (ClutterMargin, margin_);
16209 }
16210
16211 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16212                      clutter_margin_copy,
16213                      clutter_margin_free)
16214
16215 /**
16216  * clutter_actor_set_margin:
16217  * @self: a #ClutterActor
16218  * @margin: a #ClutterMargin
16219  *
16220  * Sets all the components of the margin of a #ClutterActor.
16221  *
16222  * Since: 1.10
16223  */
16224 void
16225 clutter_actor_set_margin (ClutterActor        *self,
16226                           const ClutterMargin *margin)
16227 {
16228   ClutterLayoutInfo *info;
16229   gboolean changed;
16230   GObject *obj;
16231
16232   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16233   g_return_if_fail (margin != NULL);
16234
16235   obj = G_OBJECT (self);
16236   changed = FALSE;
16237
16238   g_object_freeze_notify (obj);
16239
16240   info = _clutter_actor_get_layout_info (self);
16241
16242   if (info->margin.top != margin->top)
16243     {
16244       info->margin.top = margin->top;
16245       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16246       changed = TRUE;
16247     }
16248
16249   if (info->margin.right != margin->right)
16250     {
16251       info->margin.right = margin->right;
16252       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16253       changed = TRUE;
16254     }
16255
16256   if (info->margin.bottom != margin->bottom)
16257     {
16258       info->margin.bottom = margin->bottom;
16259       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16260       changed = TRUE;
16261     }
16262
16263   if (info->margin.left != margin->left)
16264     {
16265       info->margin.left = margin->left;
16266       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16267       changed = TRUE;
16268     }
16269
16270   if (changed)
16271     clutter_actor_queue_relayout (self);
16272
16273   g_object_thaw_notify (obj);
16274 }
16275
16276 /**
16277  * clutter_actor_get_margin:
16278  * @self: a #ClutterActor
16279  * @margin: (out caller-allocates): return location for a #ClutterMargin
16280  *
16281  * Retrieves all the components of the margin of a #ClutterActor.
16282  *
16283  * Since: 1.10
16284  */
16285 void
16286 clutter_actor_get_margin (ClutterActor  *self,
16287                           ClutterMargin *margin)
16288 {
16289   const ClutterLayoutInfo *info;
16290
16291   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16292   g_return_if_fail (margin != NULL);
16293
16294   info = _clutter_actor_get_layout_info_or_defaults (self);
16295
16296   *margin = info->margin;
16297 }
16298
16299 /**
16300  * clutter_actor_set_margin_top:
16301  * @self: a #ClutterActor
16302  * @margin: the top margin
16303  *
16304  * Sets the margin from the top of a #ClutterActor.
16305  *
16306  * Since: 1.10
16307  */
16308 void
16309 clutter_actor_set_margin_top (ClutterActor *self,
16310                               gfloat        margin)
16311 {
16312   ClutterLayoutInfo *info;
16313
16314   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16315   g_return_if_fail (margin >= 0.f);
16316
16317   info = _clutter_actor_get_layout_info (self);
16318
16319   if (info->margin.top == margin)
16320     return;
16321
16322   info->margin.top = margin;
16323
16324   clutter_actor_queue_relayout (self);
16325
16326   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16327 }
16328
16329 /**
16330  * clutter_actor_get_margin_top:
16331  * @self: a #ClutterActor
16332  *
16333  * Retrieves the top margin of a #ClutterActor.
16334  *
16335  * Return value: the top margin
16336  *
16337  * Since: 1.10
16338  */
16339 gfloat
16340 clutter_actor_get_margin_top (ClutterActor *self)
16341 {
16342   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16343
16344   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16345 }
16346
16347 /**
16348  * clutter_actor_set_margin_bottom:
16349  * @self: a #ClutterActor
16350  * @margin: the bottom margin
16351  *
16352  * Sets the margin from the bottom of a #ClutterActor.
16353  *
16354  * Since: 1.10
16355  */
16356 void
16357 clutter_actor_set_margin_bottom (ClutterActor *self,
16358                                  gfloat        margin)
16359 {
16360   ClutterLayoutInfo *info;
16361
16362   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16363   g_return_if_fail (margin >= 0.f);
16364
16365   info = _clutter_actor_get_layout_info (self);
16366
16367   if (info->margin.bottom == margin)
16368     return;
16369
16370   info->margin.bottom = margin;
16371
16372   clutter_actor_queue_relayout (self);
16373
16374   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16375 }
16376
16377 /**
16378  * clutter_actor_get_margin_bottom:
16379  * @self: a #ClutterActor
16380  *
16381  * Retrieves the bottom margin of a #ClutterActor.
16382  *
16383  * Return value: the bottom margin
16384  *
16385  * Since: 1.10
16386  */
16387 gfloat
16388 clutter_actor_get_margin_bottom (ClutterActor *self)
16389 {
16390   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16391
16392   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16393 }
16394
16395 /**
16396  * clutter_actor_set_margin_left:
16397  * @self: a #ClutterActor
16398  * @margin: the left margin
16399  *
16400  * Sets the margin from the left of a #ClutterActor.
16401  *
16402  * Since: 1.10
16403  */
16404 void
16405 clutter_actor_set_margin_left (ClutterActor *self,
16406                                gfloat        margin)
16407 {
16408   ClutterLayoutInfo *info;
16409
16410   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16411   g_return_if_fail (margin >= 0.f);
16412
16413   info = _clutter_actor_get_layout_info (self);
16414
16415   if (info->margin.left == margin)
16416     return;
16417
16418   info->margin.left = margin;
16419
16420   clutter_actor_queue_relayout (self);
16421
16422   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16423 }
16424
16425 /**
16426  * clutter_actor_get_margin_left:
16427  * @self: a #ClutterActor
16428  *
16429  * Retrieves the left margin of a #ClutterActor.
16430  *
16431  * Return value: the left margin
16432  *
16433  * Since: 1.10
16434  */
16435 gfloat
16436 clutter_actor_get_margin_left (ClutterActor *self)
16437 {
16438   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16439
16440   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16441 }
16442
16443 /**
16444  * clutter_actor_set_margin_right:
16445  * @self: a #ClutterActor
16446  * @margin: the right margin
16447  *
16448  * Sets the margin from the right of a #ClutterActor.
16449  *
16450  * Since: 1.10
16451  */
16452 void
16453 clutter_actor_set_margin_right (ClutterActor *self,
16454                                 gfloat        margin)
16455 {
16456   ClutterLayoutInfo *info;
16457
16458   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16459   g_return_if_fail (margin >= 0.f);
16460
16461   info = _clutter_actor_get_layout_info (self);
16462
16463   if (info->margin.right == margin)
16464     return;
16465
16466   info->margin.right = margin;
16467
16468   clutter_actor_queue_relayout (self);
16469
16470   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16471 }
16472
16473 /**
16474  * clutter_actor_get_margin_right:
16475  * @self: a #ClutterActor
16476  *
16477  * Retrieves the right margin of a #ClutterActor.
16478  *
16479  * Return value: the right margin
16480  *
16481  * Since: 1.10
16482  */
16483 gfloat
16484 clutter_actor_get_margin_right (ClutterActor *self)
16485 {
16486   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16487
16488   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16489 }
16490
16491 static inline void
16492 clutter_actor_set_background_color_internal (ClutterActor *self,
16493                                              const ClutterColor *color)
16494 {
16495   ClutterActorPrivate *priv = self->priv;
16496   GObject *obj;
16497
16498   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16499     return;
16500
16501   obj = G_OBJECT (self);
16502
16503   priv->bg_color = *color;
16504   priv->bg_color_set = TRUE;
16505
16506   clutter_actor_queue_redraw (self);
16507
16508   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16509   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16510 }
16511
16512 /**
16513  * clutter_actor_set_background_color:
16514  * @self: a #ClutterActor
16515  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16516  *  set color
16517  *
16518  * Sets the background color of a #ClutterActor.
16519  *
16520  * The background color will be used to cover the whole allocation of the
16521  * actor. The default background color of an actor is transparent.
16522  *
16523  * To check whether an actor has a background color, you can use the
16524  * #ClutterActor:background-color-set actor property.
16525  *
16526  * The #ClutterActor:background-color property is animatable.
16527  *
16528  * Since: 1.10
16529  */
16530 void
16531 clutter_actor_set_background_color (ClutterActor       *self,
16532                                     const ClutterColor *color)
16533 {
16534   ClutterActorPrivate *priv;
16535   GObject *obj;
16536   GParamSpec *bg_color_pspec;
16537
16538   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16539
16540   obj = G_OBJECT (self);
16541
16542   priv = self->priv;
16543
16544   if (color == NULL)
16545     {
16546       priv->bg_color_set = FALSE;
16547       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16548       clutter_actor_queue_redraw (self);
16549       return;
16550     }
16551
16552   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16553   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16554     {
16555       _clutter_actor_create_transition (self, bg_color_pspec,
16556                                         &priv->bg_color,
16557                                         color);
16558     }
16559   else
16560     _clutter_actor_update_transition (self, bg_color_pspec, color);
16561
16562   clutter_actor_queue_redraw (self);
16563 }
16564
16565 /**
16566  * clutter_actor_get_background_color:
16567  * @self: a #ClutterActor
16568  * @color: (out caller-allocates): return location for a #ClutterColor
16569  *
16570  * Retrieves the color set using clutter_actor_set_background_color().
16571  *
16572  * Since: 1.10
16573  */
16574 void
16575 clutter_actor_get_background_color (ClutterActor *self,
16576                                     ClutterColor *color)
16577 {
16578   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16579   g_return_if_fail (color != NULL);
16580
16581   *color = self->priv->bg_color;
16582 }
16583
16584 /**
16585  * clutter_actor_get_previous_sibling:
16586  * @self: a #ClutterActor
16587  *
16588  * Retrieves the sibling of @self that comes before it in the list
16589  * of children of @self's parent.
16590  *
16591  * The returned pointer is only valid until the scene graph changes; it
16592  * is not safe to modify the list of children of @self while iterating
16593  * it.
16594  *
16595  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16596  *
16597  * Since: 1.10
16598  */
16599 ClutterActor *
16600 clutter_actor_get_previous_sibling (ClutterActor *self)
16601 {
16602   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16603
16604   return self->priv->prev_sibling;
16605 }
16606
16607 /**
16608  * clutter_actor_get_next_sibling:
16609  * @self: a #ClutterActor
16610  *
16611  * Retrieves the sibling of @self that comes after it in the list
16612  * of children of @self's parent.
16613  *
16614  * The returned pointer is only valid until the scene graph changes; it
16615  * is not safe to modify the list of children of @self while iterating
16616  * it.
16617  *
16618  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16619  *
16620  * Since: 1.10
16621  */
16622 ClutterActor *
16623 clutter_actor_get_next_sibling (ClutterActor *self)
16624 {
16625   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16626
16627   return self->priv->next_sibling;
16628 }
16629
16630 /**
16631  * clutter_actor_get_first_child:
16632  * @self: a #ClutterActor
16633  *
16634  * Retrieves the first child of @self.
16635  *
16636  * The returned pointer is only valid until the scene graph changes; it
16637  * is not safe to modify the list of children of @self while iterating
16638  * it.
16639  *
16640  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16641  *
16642  * Since: 1.10
16643  */
16644 ClutterActor *
16645 clutter_actor_get_first_child (ClutterActor *self)
16646 {
16647   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16648
16649   return self->priv->first_child;
16650 }
16651
16652 /**
16653  * clutter_actor_get_last_child:
16654  * @self: a #ClutterActor
16655  *
16656  * Retrieves the last child of @self.
16657  *
16658  * The returned pointer is only valid until the scene graph changes; it
16659  * is not safe to modify the list of children of @self while iterating
16660  * it.
16661  *
16662  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16663  *
16664  * Since: 1.10
16665  */
16666 ClutterActor *
16667 clutter_actor_get_last_child (ClutterActor *self)
16668 {
16669   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16670
16671   return self->priv->last_child;
16672 }
16673
16674 /* easy way to have properly named fields instead of the dummy ones
16675  * we use in the public structure
16676  */
16677 typedef struct _RealActorIter
16678 {
16679   ClutterActor *root;           /* dummy1 */
16680   ClutterActor *current;        /* dummy2 */
16681   gpointer padding_1;           /* dummy3 */
16682   gint age;                     /* dummy4 */
16683   gpointer padding_2;           /* dummy5 */
16684 } RealActorIter;
16685
16686 /**
16687  * clutter_actor_iter_init:
16688  * @iter: a #ClutterActorIter
16689  * @root: a #ClutterActor
16690  *
16691  * Initializes a #ClutterActorIter, which can then be used to iterate
16692  * efficiently over a section of the scene graph, and associates it
16693  * with @root.
16694  *
16695  * Modifying the scene graph section that contains @root will invalidate
16696  * the iterator.
16697  *
16698  * |[
16699  *   ClutterActorIter iter;
16700  *   ClutterActor *child;
16701  *
16702  *   clutter_actor_iter_init (&iter, container);
16703  *   while (clutter_actor_iter_next (&iter, &child))
16704  *     {
16705  *       /&ast; do something with child &ast;/
16706  *     }
16707  * ]|
16708  *
16709  * Since: 1.10
16710  */
16711 void
16712 clutter_actor_iter_init (ClutterActorIter *iter,
16713                          ClutterActor     *root)
16714 {
16715   RealActorIter *ri = (RealActorIter *) iter;
16716
16717   g_return_if_fail (iter != NULL);
16718   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16719
16720   ri->root = root;
16721   ri->current = NULL;
16722   ri->age = root->priv->age;
16723 }
16724
16725 /**
16726  * clutter_actor_iter_next:
16727  * @iter: a #ClutterActorIter
16728  * @child: (out): return location for a #ClutterActor
16729  *
16730  * Advances the @iter and retrieves the next child of the root #ClutterActor
16731  * that was used to initialize the #ClutterActorIterator.
16732  *
16733  * If the iterator can advance, this function returns %TRUE and sets the
16734  * @child argument.
16735  *
16736  * If the iterator cannot advance, this function returns %FALSE, and
16737  * the contents of @child are undefined.
16738  *
16739  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16740  *
16741  * Since: 1.10
16742  */
16743 gboolean
16744 clutter_actor_iter_next (ClutterActorIter  *iter,
16745                          ClutterActor     **child)
16746 {
16747   RealActorIter *ri = (RealActorIter *) iter;
16748
16749   g_return_val_if_fail (iter != NULL, FALSE);
16750   g_return_val_if_fail (ri->root != NULL, FALSE);
16751 #ifndef G_DISABLE_ASSERT
16752   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16753 #endif
16754
16755   if (ri->current == NULL)
16756     ri->current = ri->root->priv->first_child;
16757   else
16758     ri->current = ri->current->priv->next_sibling;
16759
16760   if (child != NULL)
16761     *child = ri->current;
16762
16763   return ri->current != NULL;
16764 }
16765
16766 /**
16767  * clutter_actor_iter_prev:
16768  * @iter: a #ClutterActorIter
16769  * @child: (out): return location for a #ClutterActor
16770  *
16771  * Advances the @iter and retrieves the previous child of the root
16772  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16773  *
16774  * If the iterator can advance, this function returns %TRUE and sets the
16775  * @child argument.
16776  *
16777  * If the iterator cannot advance, this function returns %FALSE, and
16778  * the contents of @child are undefined.
16779  *
16780  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16781  *
16782  * Since: 1.10
16783  */
16784 gboolean
16785 clutter_actor_iter_prev (ClutterActorIter  *iter,
16786                          ClutterActor     **child)
16787 {
16788   RealActorIter *ri = (RealActorIter *) iter;
16789
16790   g_return_val_if_fail (iter != NULL, FALSE);
16791   g_return_val_if_fail (ri->root != NULL, FALSE);
16792 #ifndef G_DISABLE_ASSERT
16793   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16794 #endif
16795
16796   if (ri->current == NULL)
16797     ri->current = ri->root->priv->last_child;
16798   else
16799     ri->current = ri->current->priv->prev_sibling;
16800
16801   if (child != NULL)
16802     *child = ri->current;
16803
16804   return ri->current != NULL;
16805 }
16806
16807 /**
16808  * clutter_actor_iter_remove:
16809  * @iter: a #ClutterActorIter
16810  *
16811  * Safely removes the #ClutterActor currently pointer to by the iterator
16812  * from its parent.
16813  *
16814  * This function can only be called after clutter_actor_iter_next() or
16815  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16816  * than once for the same actor.
16817  *
16818  * This function will call clutter_actor_remove_child() internally.
16819  *
16820  * Since: 1.10
16821  */
16822 void
16823 clutter_actor_iter_remove (ClutterActorIter *iter)
16824 {
16825   RealActorIter *ri = (RealActorIter *) iter;
16826   ClutterActor *cur;
16827
16828   g_return_if_fail (iter != NULL);
16829   g_return_if_fail (ri->root != NULL);
16830 #ifndef G_DISABLE_ASSERT
16831   g_return_if_fail (ri->age == ri->root->priv->age);
16832 #endif
16833   g_return_if_fail (ri->current != NULL);
16834
16835   cur = ri->current;
16836
16837   if (cur != NULL)
16838     {
16839       ri->current = cur->priv->prev_sibling;
16840
16841       clutter_actor_remove_child_internal (ri->root, cur,
16842                                            REMOVE_CHILD_DEFAULT_FLAGS);
16843
16844       ri->age += 1;
16845     }
16846 }
16847
16848 /**
16849  * clutter_actor_iter_destroy:
16850  * @iter: a #ClutterActorIter
16851  *
16852  * Safely destroys the #ClutterActor currently pointer to by the iterator
16853  * from its parent.
16854  *
16855  * This function can only be called after clutter_actor_iter_next() or
16856  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16857  * than once for the same actor.
16858  *
16859  * This function will call clutter_actor_destroy() internally.
16860  *
16861  * Since: 1.10
16862  */
16863 void
16864 clutter_actor_iter_destroy (ClutterActorIter *iter)
16865 {
16866   RealActorIter *ri = (RealActorIter *) iter;
16867   ClutterActor *cur;
16868
16869   g_return_if_fail (iter != NULL);
16870   g_return_if_fail (ri->root != NULL);
16871 #ifndef G_DISABLE_ASSERT
16872   g_return_if_fail (ri->age == ri->root->priv->age);
16873 #endif
16874   g_return_if_fail (ri->current != NULL);
16875
16876   cur = ri->current;
16877
16878   if (cur != NULL)
16879     {
16880       ri->current = cur->priv->prev_sibling;
16881
16882       clutter_actor_destroy (cur);
16883
16884       ri->age += 1;
16885     }
16886 }
16887
16888 static const ClutterAnimationInfo default_animation_info = {
16889   NULL,         /* transitions */
16890   NULL,         /* states */
16891   NULL,         /* cur_state */
16892 };
16893
16894 static void
16895 clutter_animation_info_free (gpointer data)
16896 {
16897   if (data != NULL)
16898     {
16899       ClutterAnimationInfo *info = data;
16900
16901       if (info->transitions != NULL)
16902         g_hash_table_unref (info->transitions);
16903
16904       if (info->states != NULL)
16905         g_array_unref (info->states);
16906
16907       g_slice_free (ClutterAnimationInfo, info);
16908     }
16909 }
16910
16911 const ClutterAnimationInfo *
16912 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16913 {
16914   const ClutterAnimationInfo *res;
16915   GObject *obj = G_OBJECT (self);
16916
16917   res = g_object_get_qdata (obj, quark_actor_animation_info);
16918   if (res != NULL)
16919     return res;
16920
16921   return &default_animation_info;
16922 }
16923
16924 ClutterAnimationInfo *
16925 _clutter_actor_get_animation_info (ClutterActor *self)
16926 {
16927   GObject *obj = G_OBJECT (self);
16928   ClutterAnimationInfo *res;
16929
16930   res = g_object_get_qdata (obj, quark_actor_animation_info);
16931   if (res == NULL)
16932     {
16933       res = g_slice_new (ClutterAnimationInfo);
16934
16935       *res = default_animation_info;
16936
16937       g_object_set_qdata_full (obj, quark_actor_animation_info,
16938                                res,
16939                                clutter_animation_info_free);
16940     }
16941
16942   return res;
16943 }
16944
16945 ClutterTransition *
16946 _clutter_actor_get_transition (ClutterActor *actor,
16947                                GParamSpec   *pspec)
16948 {
16949   const ClutterAnimationInfo *info;
16950
16951   info = _clutter_actor_get_animation_info_or_defaults (actor);
16952
16953   if (info->transitions == NULL)
16954     return NULL;
16955
16956   return g_hash_table_lookup (info->transitions, pspec->name);
16957 }
16958
16959 typedef struct _TransitionClosure
16960 {
16961   ClutterActor *actor;
16962   ClutterTransition *transition;
16963   gchar *name;
16964   gulong completed_id;
16965 } TransitionClosure;
16966
16967 static void
16968 transition_closure_free (gpointer data)
16969 {
16970   if (G_LIKELY (data != NULL))
16971     {
16972       TransitionClosure *clos = data;
16973
16974       if (clutter_timeline_is_playing (CLUTTER_TIMELINE (clos->transition)))
16975         clutter_timeline_stop (CLUTTER_TIMELINE (clos->transition));
16976
16977       g_signal_handler_disconnect (clos->transition, clos->completed_id);
16978
16979       g_object_unref (clos->transition);
16980       g_free (clos->name);
16981
16982       g_slice_free (TransitionClosure, clos);
16983     }
16984 }
16985
16986 static void
16987 on_transition_completed (ClutterTransition *transition,
16988                          TransitionClosure *clos)
16989 {
16990   ClutterActor *actor = clos->actor;
16991   ClutterAnimationInfo *info;
16992
16993   info = _clutter_actor_get_animation_info (actor);
16994
16995   /* this will take care of cleaning clos for us */
16996   if (clutter_transition_get_remove_on_complete (transition))
16997     {
16998       /* we take a reference here because removing the closure
16999        * will release the reference on the transition, and we
17000        * want the transition to survive the signal emission;
17001        * the master clock will release the laste reference at
17002        * the end of the frame processing.
17003        */
17004       g_object_ref (transition);
17005       g_hash_table_remove (info->transitions, clos->name);
17006     }
17007
17008   /* if it's the last transition then we clean up */
17009   if (g_hash_table_size (info->transitions) == 0)
17010     {
17011       g_hash_table_unref (info->transitions);
17012       info->transitions = NULL;
17013
17014       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17015                     _clutter_actor_get_debug_name (actor));
17016
17017       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17018     }
17019 }
17020
17021 void
17022 _clutter_actor_update_transition (ClutterActor *actor,
17023                                   GParamSpec   *pspec,
17024                                   ...)
17025 {
17026   TransitionClosure *clos;
17027   ClutterTimeline *timeline;
17028   ClutterInterval *interval;
17029   const ClutterAnimationInfo *info;
17030   va_list var_args;
17031   GType ptype;
17032   GValue initial = G_VALUE_INIT;
17033   GValue final = G_VALUE_INIT;
17034   char *error = NULL;
17035
17036   info = _clutter_actor_get_animation_info_or_defaults (actor);
17037
17038   if (info->transitions == NULL)
17039     return;
17040
17041   clos = g_hash_table_lookup (info->transitions, pspec->name);
17042   if (clos == NULL)
17043     return;
17044
17045   timeline = CLUTTER_TIMELINE (clos->transition);
17046
17047   va_start (var_args, pspec);
17048
17049   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17050
17051   g_value_init (&initial, ptype);
17052   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17053                                         pspec->name,
17054                                         &initial);
17055
17056   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17057   if (error != NULL)
17058     {
17059       g_critical ("%s: %s", G_STRLOC, error);
17060       g_free (error);
17061       goto out;
17062     }
17063
17064   interval = clutter_transition_get_interval (clos->transition);
17065   clutter_interval_set_initial_value (interval, &initial);
17066   clutter_interval_set_final_value (interval, &final);
17067
17068   /* if we're updating with an easing duration of zero milliseconds,
17069    * we just jump the timeline to the end and let it run its course
17070    */
17071   if (info->cur_state != NULL &&
17072       info->cur_state->easing_duration != 0)
17073     {
17074       guint cur_duration = clutter_timeline_get_duration (timeline);
17075       ClutterAnimationMode cur_mode =
17076         clutter_timeline_get_progress_mode (timeline);
17077
17078       if (cur_duration != info->cur_state->easing_duration)
17079         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17080
17081       if (cur_mode != info->cur_state->easing_mode)
17082         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17083
17084       clutter_timeline_rewind (timeline);
17085     }
17086   else
17087     {
17088       guint duration = clutter_timeline_get_duration (timeline);
17089
17090       clutter_timeline_advance (timeline, duration);
17091     }
17092
17093 out:
17094   g_value_unset (&initial);
17095   g_value_unset (&final);
17096
17097   va_end (var_args);
17098 }
17099
17100 /*< private >*
17101  * _clutter_actor_create_transition:
17102  * @actor: a #ClutterActor
17103  * @pspec: the property used for the transition
17104  * @...: initial and final state
17105  *
17106  * Creates a #ClutterTransition for the property represented by @pspec.
17107  *
17108  * Return value: a #ClutterTransition
17109  */
17110 ClutterTransition *
17111 _clutter_actor_create_transition (ClutterActor *actor,
17112                                   GParamSpec   *pspec,
17113                                   ...)
17114 {
17115   ClutterAnimationInfo *info;
17116   ClutterTransition *res = NULL;
17117   gboolean call_restore = FALSE;
17118   TransitionClosure *clos;
17119   va_list var_args;
17120
17121   info = _clutter_actor_get_animation_info (actor);
17122
17123   /* XXX - this will go away in 2.0
17124    *
17125    * if no state has been pushed, we assume that the easing state is
17126    * in "compatibility mode": all transitions have a duration of 0
17127    * msecs, which means that they happen immediately. in Clutter 2.0
17128    * this will turn into a g_assert(info->states != NULL), as every
17129    * actor will start with a predefined easing state
17130    */
17131   if (info->states == NULL)
17132     {
17133       clutter_actor_save_easing_state (actor);
17134       clutter_actor_set_easing_duration (actor, 0);
17135       call_restore = TRUE;
17136     }
17137
17138   if (info->transitions == NULL)
17139     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17140                                                NULL,
17141                                                transition_closure_free);
17142
17143   va_start (var_args, pspec);
17144
17145   clos = g_hash_table_lookup (info->transitions, pspec->name);
17146   if (clos == NULL)
17147     {
17148       ClutterInterval *interval;
17149       GValue initial = G_VALUE_INIT;
17150       GValue final = G_VALUE_INIT;
17151       GType ptype;
17152       char *error;
17153
17154       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17155
17156       G_VALUE_COLLECT_INIT (&initial, ptype,
17157                             var_args, 0,
17158                             &error);
17159       if (error != NULL)
17160         {
17161           g_critical ("%s: %s", G_STRLOC, error);
17162           g_free (error);
17163           goto out;
17164         }
17165
17166       G_VALUE_COLLECT_INIT (&final, ptype,
17167                             var_args, 0,
17168                             &error);
17169
17170       if (error != NULL)
17171         {
17172           g_critical ("%s: %s", G_STRLOC, error);
17173           g_value_unset (&initial);
17174           g_free (error);
17175           goto out;
17176         }
17177
17178       /* if the current easing state has a duration of 0, then we don't
17179        * bother to create the transition, and we just set the final value
17180        * directly on the actor; we don't go through the Animatable
17181        * interface because we know we got here through an animatable
17182        * property.
17183        */
17184       if (info->cur_state->easing_duration == 0)
17185         {
17186           clutter_actor_set_animatable_property (actor,
17187                                                  pspec->param_id,
17188                                                  &final,
17189                                                  pspec);
17190           g_value_unset (&initial);
17191           g_value_unset (&final);
17192
17193           goto out;
17194         }
17195
17196       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17197
17198       g_value_unset (&initial);
17199       g_value_unset (&final);
17200
17201       res = clutter_property_transition_new (pspec->name);
17202
17203       clutter_transition_set_interval (res, interval);
17204       clutter_transition_set_remove_on_complete (res, TRUE);
17205
17206       /* this will start the transition as well */
17207       clutter_actor_add_transition (actor, pspec->name, res);
17208
17209       /* the actor now owns the transition */
17210       g_object_unref (res);
17211     }
17212   else
17213     res = clos->transition;
17214
17215 out:
17216   if (call_restore)
17217     clutter_actor_restore_easing_state (actor);
17218
17219   va_end (var_args);
17220
17221   return res;
17222 }
17223
17224 /**
17225  * clutter_actor_add_transition:
17226  * @self: a #ClutterActor
17227  * @name: the name of the transition to add
17228  * @transition: the #ClutterTransition to add
17229  *
17230  * Adds a @transition to the #ClutterActor's list of animations.
17231  *
17232  * The @name string is a per-actor unique identifier of the @transition: only
17233  * one #ClutterTransition can be associated to the specified @name.
17234  *
17235  * The @transition will be given the easing duration, mode, and delay
17236  * associated to the actor's current easing state; it is possible to modify
17237  * these values after calling clutter_actor_add_transition().
17238  *
17239  * The @transition will be started once added.
17240  *
17241  * This function will take a reference on the @transition.
17242  *
17243  * This function is usually called implicitly when modifying an animatable
17244  * property.
17245  *
17246  * Since: 1.10
17247  */
17248 void
17249 clutter_actor_add_transition (ClutterActor      *self,
17250                               const char        *name,
17251                               ClutterTransition *transition)
17252 {
17253   ClutterTimeline *timeline;
17254   TransitionClosure *clos;
17255   ClutterAnimationInfo *info;
17256
17257   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17258   g_return_if_fail (name != NULL);
17259   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17260
17261   info = _clutter_actor_get_animation_info (self);
17262
17263   if (info->cur_state == NULL)
17264     {
17265       g_warning ("No easing state is defined for the actor '%s'; you "
17266                  "must call clutter_actor_save_easing_state() before "
17267                  "calling clutter_actor_add_transition().",
17268                  _clutter_actor_get_debug_name (self));
17269       return;
17270     }
17271
17272   if (info->transitions == NULL)
17273     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17274                                                NULL,
17275                                                transition_closure_free);
17276
17277   if (g_hash_table_lookup (info->transitions, name) != NULL)
17278     {
17279       g_warning ("A transition with name '%s' already exists for "
17280                  "the actor '%s'",
17281                  name,
17282                  _clutter_actor_get_debug_name (self));
17283       return;
17284     }
17285
17286   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17287
17288   timeline = CLUTTER_TIMELINE (transition);
17289
17290   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17291   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17292   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17293
17294   clos = g_slice_new (TransitionClosure);
17295   clos->actor = self;
17296   clos->transition = g_object_ref (transition);
17297   clos->name = g_strdup (name);
17298   clos->completed_id = g_signal_connect (timeline, "completed",
17299                                          G_CALLBACK (on_transition_completed),
17300                                          clos);
17301
17302   CLUTTER_NOTE (ANIMATION,
17303                 "Adding transition '%s' [%p] to actor '%s'",
17304                 clos->name,
17305                 clos->transition,
17306                 _clutter_actor_get_debug_name (self));
17307
17308   g_hash_table_insert (info->transitions, clos->name, clos);
17309   clutter_timeline_start (timeline);
17310 }
17311
17312 /**
17313  * clutter_actor_remove_transition:
17314  * @self: a #ClutterActor
17315  * @name: the name of the transition to remove
17316  *
17317  * Removes the transition stored inside a #ClutterActor using @name
17318  * identifier.
17319  *
17320  * If the transition is currently in progress, it will be stopped.
17321  *
17322  * This function releases the reference acquired when the transition
17323  * was added to the #ClutterActor.
17324  *
17325  * Since: 1.10
17326  */
17327 void
17328 clutter_actor_remove_transition (ClutterActor *self,
17329                                  const char   *name)
17330 {
17331   const ClutterAnimationInfo *info;
17332
17333   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17334   g_return_if_fail (name != NULL);
17335
17336   info = _clutter_actor_get_animation_info_or_defaults (self);
17337
17338   if (info->transitions == NULL)
17339     return;
17340
17341   g_hash_table_remove (info->transitions, name);
17342 }
17343
17344 /**
17345  * clutter_actor_remove_all_transitions:
17346  * @self: a #ClutterActor
17347  *
17348  * Removes all transitions associated to @self.
17349  *
17350  * Since: 1.10
17351  */
17352 void
17353 clutter_actor_remove_all_transitions (ClutterActor *self)
17354 {
17355   const ClutterAnimationInfo *info;
17356
17357   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17358
17359   info = _clutter_actor_get_animation_info_or_defaults (self);
17360   if (info->transitions == NULL)
17361     return;
17362
17363   g_hash_table_remove_all (info->transitions);
17364 }
17365
17366 /**
17367  * clutter_actor_set_easing_duration:
17368  * @self: a #ClutterActor
17369  * @msecs: the duration of the easing, or %NULL
17370  *
17371  * Sets the duration of the tweening for animatable properties
17372  * of @self for the current easing state.
17373  *
17374  * Since: 1.10
17375  */
17376 void
17377 clutter_actor_set_easing_duration (ClutterActor *self,
17378                                    guint         msecs)
17379 {
17380   ClutterAnimationInfo *info;
17381
17382   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17383
17384   info = _clutter_actor_get_animation_info (self);
17385
17386   if (info->cur_state == NULL)
17387     {
17388       g_warning ("You must call clutter_actor_save_easing_state() prior "
17389                  "to calling clutter_actor_set_easing_duration().");
17390       return;
17391     }
17392
17393   if (info->cur_state->easing_duration != msecs)
17394     info->cur_state->easing_duration = msecs;
17395 }
17396
17397 /**
17398  * clutter_actor_get_easing_duration:
17399  * @self: a #ClutterActor
17400  *
17401  * Retrieves the duration of the tweening for animatable
17402  * properties of @self for the current easing state.
17403  *
17404  * Return value: the duration of the tweening, in milliseconds
17405  *
17406  * Since: 1.10
17407  */
17408 guint
17409 clutter_actor_get_easing_duration (ClutterActor *self)
17410 {
17411   const ClutterAnimationInfo *info;
17412
17413   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17414
17415   info = _clutter_actor_get_animation_info_or_defaults (self);
17416
17417   if (info->cur_state != NULL)
17418     return info->cur_state->easing_duration;
17419
17420   return 0;
17421 }
17422
17423 /**
17424  * clutter_actor_set_easing_mode:
17425  * @self: a #ClutterActor
17426  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17427  *
17428  * Sets the easing mode for the tweening of animatable properties
17429  * of @self.
17430  *
17431  * Since: 1.10
17432  */
17433 void
17434 clutter_actor_set_easing_mode (ClutterActor         *self,
17435                                ClutterAnimationMode  mode)
17436 {
17437   ClutterAnimationInfo *info;
17438
17439   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17440   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17441   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17442
17443   info = _clutter_actor_get_animation_info (self);
17444
17445   if (info->cur_state == NULL)
17446     {
17447       g_warning ("You must call clutter_actor_save_easing_state() prior "
17448                  "to calling clutter_actor_set_easing_mode().");
17449       return;
17450     }
17451
17452   if (info->cur_state->easing_mode != mode)
17453     info->cur_state->easing_mode = mode;
17454 }
17455
17456 /**
17457  * clutter_actor_get_easing_mode:
17458  * @self: a #ClutterActor
17459  *
17460  * Retrieves the easing mode for the tweening of animatable properties
17461  * of @self for the current easing state.
17462  *
17463  * Return value: an easing mode
17464  *
17465  * Since: 1.10
17466  */
17467 ClutterAnimationMode
17468 clutter_actor_get_easing_mode (ClutterActor *self)
17469 {
17470   const ClutterAnimationInfo *info;
17471
17472   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17473
17474   info = _clutter_actor_get_animation_info_or_defaults (self);
17475
17476   if (info->cur_state != NULL)
17477     return info->cur_state->easing_mode;
17478
17479   return CLUTTER_EASE_OUT_CUBIC;
17480 }
17481
17482 /**
17483  * clutter_actor_set_easing_delay:
17484  * @self: a #ClutterActor
17485  * @msecs: the delay before the start of the tweening, in milliseconds
17486  *
17487  * Sets the delay that should be applied before tweening animatable
17488  * properties.
17489  *
17490  * Since: 1.10
17491  */
17492 void
17493 clutter_actor_set_easing_delay (ClutterActor *self,
17494                                 guint         msecs)
17495 {
17496   ClutterAnimationInfo *info;
17497
17498   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17499
17500   info = _clutter_actor_get_animation_info (self);
17501
17502   if (info->cur_state == NULL)
17503     {
17504       g_warning ("You must call clutter_actor_save_easing_state() prior "
17505                  "to calling clutter_actor_set_easing_delay().");
17506       return;
17507     }
17508
17509   if (info->cur_state->easing_delay != msecs)
17510     info->cur_state->easing_delay = msecs;
17511 }
17512
17513 /**
17514  * clutter_actor_get_easing_delay:
17515  * @self: a #ClutterActor
17516  *
17517  * Retrieves the delay that should be applied when tweening animatable
17518  * properties.
17519  *
17520  * Return value: a delay, in milliseconds
17521  *
17522  * Since: 1.10
17523  */
17524 guint
17525 clutter_actor_get_easing_delay (ClutterActor *self)
17526 {
17527   const ClutterAnimationInfo *info;
17528
17529   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17530
17531   info = _clutter_actor_get_animation_info_or_defaults (self);
17532
17533   if (info->cur_state != NULL)
17534     return info->cur_state->easing_delay;
17535
17536   return 0;
17537 }
17538
17539 /**
17540  * clutter_actor_get_transition:
17541  * @self: a #ClutterActor
17542  * @name: the name of the transition
17543  *
17544  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17545  * transition @name.
17546  *
17547  * Transitions created for animatable properties use the name of the
17548  * property itself, for instance the code below:
17549  *
17550  * |[
17551  *   clutter_actor_set_easing_duration (actor, 1000);
17552  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17553  *
17554  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17555  *   g_signal_connect (transition, "completed",
17556  *                     G_CALLBACK (on_transition_complete),
17557  *                     actor);
17558  * ]|
17559  *
17560  * will call the <function>on_transition_complete</function> callback when
17561  * the transition is complete.
17562  *
17563  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17564  *   was found to match the passed name; the returned instance is owned
17565  *   by Clutter and it should not be freed
17566  *
17567  * Since: 1.10
17568  */
17569 ClutterTransition *
17570 clutter_actor_get_transition (ClutterActor *self,
17571                               const char   *name)
17572 {
17573   TransitionClosure *clos;
17574   const ClutterAnimationInfo *info;
17575
17576   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17577   g_return_val_if_fail (name != NULL, NULL);
17578
17579   info = _clutter_actor_get_animation_info_or_defaults (self);
17580   if (info->transitions == NULL)
17581     return NULL;
17582
17583   clos = g_hash_table_lookup (info->transitions, name);
17584   if (clos == NULL)
17585     return NULL;
17586
17587   return clos->transition;
17588 }
17589
17590 /**
17591  * clutter_actor_save_easing_state:
17592  * @self: a #ClutterActor
17593  *
17594  * Saves the current easing state for animatable properties, and creates
17595  * a new state with the default values for easing mode and duration.
17596  *
17597  * Since: 1.10
17598  */
17599 void
17600 clutter_actor_save_easing_state (ClutterActor *self)
17601 {
17602   ClutterAnimationInfo *info;
17603   AState new_state;
17604
17605   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17606
17607   info = _clutter_actor_get_animation_info (self);
17608
17609   if (info->states == NULL)
17610     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17611
17612   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17613   new_state.easing_duration = 250;
17614   new_state.easing_delay = 0;
17615
17616   g_array_append_val (info->states, new_state);
17617
17618   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17619 }
17620
17621 /**
17622  * clutter_actor_restore_easing_state:
17623  * @self: a #ClutterActor
17624  *
17625  * Restores the easing state as it was prior to a call to
17626  * clutter_actor_save_easing_state().
17627  *
17628  * Since: 1.10
17629  */
17630 void
17631 clutter_actor_restore_easing_state (ClutterActor *self)
17632 {
17633   ClutterAnimationInfo *info;
17634
17635   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17636
17637   info = _clutter_actor_get_animation_info (self);
17638
17639   if (info->states == NULL)
17640     {
17641       g_critical ("The function clutter_actor_restore_easing_state() has "
17642                   "called without a previous call to "
17643                   "clutter_actor_save_easing_state().");
17644       return;
17645     }
17646
17647   g_array_remove_index (info->states, info->states->len - 1);
17648
17649   if (info->states->len > 0)
17650     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17651   else
17652     {
17653       g_array_unref (info->states);
17654       info->states = NULL;
17655       info->cur_state = NULL;
17656     }
17657 }
17658
17659 /**
17660  * clutter_actor_set_content:
17661  * @self: a #ClutterActor
17662  * @content: (allow-none): a #ClutterContent, or %NULL
17663  *
17664  * Sets the contents of a #ClutterActor.
17665  *
17666  * Since: 1.10
17667  */
17668 void
17669 clutter_actor_set_content (ClutterActor   *self,
17670                            ClutterContent *content)
17671 {
17672   ClutterActorPrivate *priv;
17673
17674   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17675   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17676
17677   priv = self->priv;
17678
17679   if (priv->content != NULL)
17680     {
17681       _clutter_content_detached (priv->content, self);
17682       g_clear_object (&priv->content);
17683     }
17684
17685   priv->content = content;
17686
17687   if (priv->content != NULL)
17688     {
17689       g_object_ref (priv->content);
17690       _clutter_content_attached (priv->content, self);
17691     }
17692
17693   /* given that the content is always painted within the allocation,
17694    * we only need to queue a redraw here
17695    */
17696   clutter_actor_queue_redraw (self);
17697
17698   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17699
17700   /* if the content gravity is not resize-fill, and the new content has a
17701    * different preferred size than the previous one, then the content box
17702    * may have been changed. since we compute that lazily, we just notify
17703    * here, and let whomever watches :content-box do whatever they need to
17704    * do.
17705    */
17706   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17707     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17708 }
17709
17710 /**
17711  * clutter_actor_get_content:
17712  * @self: a #ClutterActor
17713  *
17714  * Retrieves the contents of @self.
17715  *
17716  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17717  *   or %NULL if none was set
17718  *
17719  * Since: 1.10
17720  */
17721 ClutterContent *
17722 clutter_actor_get_content (ClutterActor *self)
17723 {
17724   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17725
17726   return self->priv->content;
17727 }
17728
17729 /**
17730  * clutter_actor_set_content_gravity:
17731  * @self: a #ClutterActor
17732  * @gravity: the #ClutterContentGravity
17733  *
17734  * Sets the gravity of the #ClutterContent used by @self.
17735  *
17736  * See the description of the #ClutterActor:content-gravity property for
17737  * more information.
17738  *
17739  * Since: 1.10
17740  */
17741 void
17742 clutter_actor_set_content_gravity (ClutterActor *self,
17743                                    ClutterContentGravity  gravity)
17744 {
17745   ClutterActorPrivate *priv;
17746
17747   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17748
17749   priv = self->priv;
17750
17751   if (priv->content_gravity == gravity)
17752     return;
17753
17754   priv->content_gravity = gravity;
17755
17756   clutter_actor_queue_redraw (self);
17757
17758   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17759   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17760 }
17761
17762 /**
17763  * clutter_actor_get_content_gravity:
17764  * @self: a #ClutterActor
17765  *
17766  * Retrieves the content gravity as set using
17767  * clutter_actor_get_content_gravity().
17768  *
17769  * Return value: the content gravity
17770  *
17771  * Since: 1.10
17772  */
17773 ClutterContentGravity
17774 clutter_actor_get_content_gravity (ClutterActor *self)
17775 {
17776   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17777                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17778
17779   return self->priv->content_gravity;
17780 }
17781
17782 /**
17783  * clutter_actor_get_content_box:
17784  * @self: a #ClutterActor
17785  * @box: (out caller-allocates): the return location for the bounding
17786  *   box for the #ClutterContent
17787  *
17788  * Retrieves the bounding box for the #ClutterContent of @self.
17789  *
17790  * The bounding box is relative to the actor's allocation.
17791  *
17792  * If no #ClutterContent is set for @self, or if @self has not been
17793  * allocated yet, then the result is undefined.
17794  *
17795  * The content box is guaranteed to be, at most, as big as the allocation
17796  * of the #ClutterActor.
17797  *
17798  * If the #ClutterContent used by the actor has a preferred size, then
17799  * it is possible to modify the content box by using the
17800  * #ClutterActor:content-gravity property.
17801  *
17802  * Since: 1.10
17803  */
17804 void
17805 clutter_actor_get_content_box (ClutterActor    *self,
17806                                ClutterActorBox *box)
17807 {
17808   ClutterActorPrivate *priv;
17809   gfloat content_w, content_h;
17810   gfloat alloc_w, alloc_h;
17811
17812   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17813   g_return_if_fail (box != NULL);
17814
17815   priv = self->priv;
17816
17817   box->x1 = 0.f;
17818   box->y1 = 0.f;
17819   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17820   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17821
17822   if (priv->content == NULL)
17823     return;
17824
17825   /* no need to do any more work */
17826   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17827     return;
17828
17829   /* if the content does not have a preferred size then there is
17830    * no point in computing the content box
17831    */
17832   if (!clutter_content_get_preferred_size (priv->content,
17833                                            &content_w,
17834                                            &content_h))
17835     return;
17836
17837   alloc_w = box->x2;
17838   alloc_h = box->y2;
17839
17840   switch (priv->content_gravity)
17841     {
17842     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17843       box->x2 = box->x1 + MIN (content_w, alloc_w);
17844       box->y2 = box->y1 + MIN (content_h, alloc_h);
17845       break;
17846
17847     case CLUTTER_CONTENT_GRAVITY_TOP:
17848       if (alloc_w > content_w)
17849         {
17850           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17851           box->x2 = box->x1 + content_w;
17852         }
17853       box->y2 = box->y1 + MIN (content_h, alloc_h);
17854       break;
17855
17856     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17857       if (alloc_w > content_w)
17858         {
17859           box->x1 += (alloc_w - content_w);
17860           box->x2 = box->x1 + content_w;
17861         }
17862       box->y2 = box->y1 + MIN (content_h, alloc_h);
17863       break;
17864
17865     case CLUTTER_CONTENT_GRAVITY_LEFT:
17866       box->x2 = box->x1 + MIN (content_w, alloc_w);
17867       if (alloc_h > content_h)
17868         {
17869           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17870           box->y2 = box->y1 + content_h;
17871         }
17872       break;
17873
17874     case CLUTTER_CONTENT_GRAVITY_CENTER:
17875       if (alloc_w > content_w)
17876         {
17877           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17878           box->x2 = box->x1 + content_w;
17879         }
17880       if (alloc_h > content_h)
17881         {
17882           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17883           box->y2 = box->y1 + content_h;
17884         }
17885       break;
17886
17887     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17888       if (alloc_w > content_w)
17889         {
17890           box->x1 += (alloc_w - content_w);
17891           box->x2 = box->x1 + content_w;
17892         }
17893       if (alloc_h > content_h)
17894         {
17895           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17896           box->y2 = box->y1 + content_h;
17897         }
17898       break;
17899
17900     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17901       box->x2 = box->x1 + MIN (content_w, alloc_w);
17902       if (alloc_h > content_h)
17903         {
17904           box->y1 += (alloc_h - content_h);
17905           box->y2 = box->y1 + content_h;
17906         }
17907       break;
17908
17909     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17910       if (alloc_w > content_w)
17911         {
17912           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17913           box->x2 = box->x1 + content_w;
17914         }
17915       if (alloc_h > content_h)
17916         {
17917           box->y1 += (alloc_h - content_h);
17918           box->y2 = box->y1 + content_h;
17919         }
17920       break;
17921
17922     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17923       if (alloc_w > content_w)
17924         {
17925           box->x1 += (alloc_w - content_w);
17926           box->x2 = box->x1 + content_w;
17927         }
17928       if (alloc_h > content_h)
17929         {
17930           box->y1 += (alloc_h - content_h);
17931           box->y2 = box->y1 + content_h;
17932         }
17933       break;
17934
17935     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17936       g_assert_not_reached ();
17937       break;
17938
17939     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17940       {
17941         double r_c = content_w / content_h;
17942         double r_a = alloc_w / alloc_h;
17943
17944         if (r_c >= 1.0)
17945           {
17946             if (r_a >= 1.0)
17947               {
17948                 box->x1 = 0.f;
17949                 box->x2 = alloc_w;
17950
17951                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17952                 box->y2 = box->y1 + (alloc_w * r_c);
17953               }
17954             else
17955               {
17956                 box->y1 = 0.f;
17957                 box->y2 = alloc_h;
17958
17959                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17960                 box->x2 = box->x1 + (alloc_h * r_c);
17961               }
17962           }
17963         else
17964           {
17965             if (r_a >= 1.0)
17966               {
17967                 box->y1 = 0.f;
17968                 box->y2 = alloc_h;
17969
17970                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17971                 box->x2 = box->x1 + (alloc_h * r_c);
17972               }
17973             else
17974               {
17975                 box->x1 = 0.f;
17976                 box->x2 = alloc_w;
17977
17978                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17979                 box->y2 = box->y1 + (alloc_w * r_c);
17980               }
17981           }
17982       }
17983       break;
17984     }
17985 }
17986
17987 /**
17988  * clutter_actor_set_content_scaling_filters:
17989  * @self: a #ClutterActor
17990  * @min_filter: the minification filter for the content
17991  * @mag_filter: the magnification filter for the content
17992  *
17993  * Sets the minification and magnification filter to be applied when
17994  * scaling the #ClutterActor:content of a #ClutterActor.
17995  *
17996  * The #ClutterActor:minification-filter will be used when reducing
17997  * the size of the content; the #ClutterActor:magnification-filter
17998  * will be used when increasing the size of the content.
17999  *
18000  * Since: 1.10
18001  */
18002 void
18003 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18004                                            ClutterScalingFilter  min_filter,
18005                                            ClutterScalingFilter  mag_filter)
18006 {
18007   ClutterActorPrivate *priv;
18008   gboolean changed;
18009   GObject *obj;
18010
18011   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18012
18013   priv = self->priv;
18014   obj = G_OBJECT (self);
18015
18016   g_object_freeze_notify (obj);
18017
18018   changed = FALSE;
18019
18020   if (priv->min_filter != min_filter)
18021     {
18022       priv->min_filter = min_filter;
18023       changed = TRUE;
18024
18025       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18026     }
18027
18028   if (priv->mag_filter != mag_filter)
18029     {
18030       priv->mag_filter = mag_filter;
18031       changed = TRUE;
18032
18033       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18034     }
18035
18036   if (changed)
18037     clutter_actor_queue_redraw (self);
18038
18039   g_object_thaw_notify (obj);
18040 }
18041
18042 /**
18043  * clutter_actor_get_content_scaling_filters:
18044  * @self: a #ClutterActor
18045  * @min_filter: (out) (allow-none): return location for the minification
18046  *   filter, or %NULL
18047  * @mag_filter: (out) (allow-none): return location for the magnification
18048  *   filter, or %NULL
18049  *
18050  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18051  *
18052  * Since: 1.10
18053  */
18054 void
18055 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18056                                            ClutterScalingFilter *min_filter,
18057                                            ClutterScalingFilter *mag_filter)
18058 {
18059   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18060
18061   if (min_filter != NULL)
18062     *min_filter = self->priv->min_filter;
18063
18064   if (mag_filter != NULL)
18065     *mag_filter = self->priv->mag_filter;
18066 }