4 * An OpenGL based 'interactive canvas' library.
6 * Authored By Matthew Allum <mallum@openedhand.com>
8 * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9 * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
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.
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.
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/>.
26 * SECTION:clutter-actor
27 * @short_description: The basic element of the scene graph
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
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>
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-angle-x and #ClutterActor:rotation-center-x;</para></listitem>
44 * <listitem><para>rotation around the #ClutterActor:rotation-angle-y and #ClutterActor:rotation-center-y;</para></listitem>
45 * <listitem><para>rotation around the #ClutterActor:rotation-angle-z and #ClutterActor:rotation-center-z;</para></listitem>
46 * <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
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>
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 ();
77 * /* set the bounding box of the actor */
78 * clutter_actor_set_position (actor, 0, 0);
79 * clutter_actor_set_size (actor, 480, 640);
81 * /* set the background color of the actor */
82 * clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
84 * /* set the bounding box of the child, relative to the parent */
85 * ClutterActor *child = clutter_actor_new ();
86 * clutter_actor_set_position (child, 20, 20);
87 * clutter_actor_set_size (child, 80, 240);
89 * /* set the background color of the child */
90 * clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
92 * /* add the child to the actor */
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
107 * <informalexample><programlisting>
108 * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../examples/basic-actor.c">
109 * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
111 * </programlisting></informalexample>
112 * <figure id="actor-example-image">
113 * <title>Actors</title>
114 * <graphic fileref="actor-example.png" format="PNG"/>
118 * <refsect2 id="ClutterActor-painting">
119 * <title>Painting an actor</title>
120 * <para>There are three ways to paint an actor:</para>
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>
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 ();
139 * /* set the bounding box */
140 * clutter_actor_set_position (actor, 50, 50);
141 * clutter_actor_set_size (actor, 100, 100);
143 * /* set the content; the image_content variable is set elsewhere */
144 * clutter_actor_set_content (actor, image_content);
145 * </programlisting></informalexample>
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>
159 * my_actor_paint_node (ClutterActor *actor,
160 * ClutterPaintNode *root)
162 * ClutterPaintNode *node;
163 * ClutterActorBox box;
165 * /* where the content of the actor should be painted */
166 * clutter_actor_get_allocation_box (actor, &box);
168 * /* the cogl_texture variable is set elsewhere */
169 * node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170 * CLUTTER_SCALING_FILTER_TRILINEAR,
171 * CLUTTER_SCALING_FILTER_LINEAR);
173 * /* paint the content of the node using the allocation */
174 * clutter_paint_node_add_rectangle (node, &box);
176 * /* add the node, and transfer ownership */
177 * clutter_paint_node_add_child (root, node);
178 * clutter_paint_node_unref (node);
180 * </programlisting></informalexample>
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>
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>
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>
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 * /* assume that the actor is currently positioned at (100, 100) */
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 * /* animate the actor's opacity and depth */
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);
251 * /* animate another actor's opacity */
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
266 * <informalexample><programlisting>
267 * clutter_actor_save_easing_state (actor);
268 * clutter_actor_set_x (actor, 200);
269 * clutter_actor_restore_easing_state (actor);
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
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>
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;
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_from (transition, G_TYPE_UINT, 255);
297 * clutter_transition_set_to (transition, G_TYPE_UINT, 0);
299 * clutter_actor_add_transition (actor, "animate-opacity", transition);
300 * </programlisting></informalexample>
301 * <para>The example above will animate the #ClutterActor:opacity property
302 * of an actor between fully opaque and fully transparent, and back, over
303 * a span of 3 seconds. The animation does not begin until it is added to
305 * <para>The explicit animation API should also be used when using custom
306 * animatable properties for #ClutterAction, #ClutterConstraint, and
307 * #ClutterEffect instances associated to an actor; see the section on
308 * <ulink linkend="ClutterActor-custom-animatable-properties">custom
309 * animatable properties below</ulink> for an example.</para>
310 * <para>Finally, explicit animations are useful for creating animations
311 * that run continuously, for instance:</para>
312 * <informalexample><programlisting>
313 * /* this animation will pulse the actor's opacity continuously */
314 * ClutterTransition *transition;
315 * ClutterInterval *interval;
317 * transition = clutter_property_transition_new ("opacity");
319 * /* we want to animate the opacity between 0 and 255 */
320 * clutter_transition_set_from (transition, G_TYPE_UINT, 0);
321 * clutter_transition_set_to (transition, G_TYPE_UINT, 255);
323 * /* over a one second duration, running an infinite amount of times */
324 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
325 * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
327 * /* we want to fade in and out, so we need to auto-reverse the transition */
328 * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
330 * /* and we want to use an easing function that eases both in and out */
331 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
332 * CLUTTER_EASE_IN_OUT_CUBIC);
334 * /* add the transition to the desired actor; this will
335 * * start the animation.
337 * clutter_actor_add_transition (actor, "opacityAnimation", transition);
338 * </programlisting></informalexample>
342 * <refsect2 id="ClutterActor-subclassing">
343 * <title>Implementing an actor</title>
344 * <para>Careful consideration should be given when deciding to implement
345 * a #ClutterActor sub-class. It is generally recommended to implement a
346 * sub-class of #ClutterActor only for actors that should be used as leaf
347 * nodes of a scene graph.</para>
348 * <para>If your actor should be painted in a custom way, you should
349 * override the #ClutterActor::paint signal class handler. You can either
350 * opt to chain up to the parent class implementation or decide to fully
351 * override the default paint implementation; Clutter will set up the
352 * transformations and clip regions prior to emitting the #ClutterActor::paint
354 * <para>By overriding the #ClutterActorClass.get_preferred_width() and
355 * #ClutterActorClass.get_preferred_height() virtual functions it is
356 * possible to change or provide the preferred size of an actor; similarly,
357 * by overriding the #ClutterActorClass.allocate() virtual function it is
358 * possible to control the layout of the children of an actor. Make sure to
359 * always chain up to the parent implementation of the
360 * #ClutterActorClass.allocate() virtual function.</para>
361 * <para>In general, it is strongly encouraged to use delegation and
362 * composition instead of direct subclassing.</para>
365 * <refsect2 id="ClutterActor-script">
366 * <title>ClutterActor custom properties for #ClutterScript</title>
367 * <para>#ClutterActor defines a custom "rotation" property which
368 * allows a short-hand description of the rotations to be applied
369 * to an actor.</para>
370 * <para>The syntax of the "rotation" property is the following:</para>
374 * { "<axis>" : [ <angle>, [ <center> ] ] }
378 * <para>where the <emphasis>axis</emphasis> is the name of an enumeration
379 * value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
380 * floating point value representing the rotation angle on the given axis,
382 * <para>The <emphasis>center</emphasis> array is optional, and if present
383 * it must contain the center of rotation as described by two coordinates:
384 * Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
386 * <para>#ClutterActor also defines a scriptable "margin" property which
387 * follows the CSS "margin" shorthand.
391 * "margin" : [ <top>, <right>, <bottom> <left> ]
393 * "margin" : [ <top>, <left/right>, <bottom> ]
395 * "margin" : [ <top/bottom>, <left/right> ]
397 * "margin" : [ <top/right/bottom/left> ]
401 * <para>#ClutterActor will also parse every positional and dimensional
402 * property defined as a string through clutter_units_from_string(); you
403 * should read the documentation for the #ClutterUnits parser format for
404 * the valid units and syntax.</para>
407 * <refsect2 id="ClutterActor-custom-animatable-properties">
408 * <title>Custom animatable properties</title>
409 * <para>#ClutterActor allows accessing properties of #ClutterAction,
410 * #ClutterEffect, and #ClutterConstraint instances associated to an actor
411 * instance for animation purposes.</para>
412 * <para>In order to access a specific #ClutterAction or a #ClutterConstraint
413 * property it is necessary to set the #ClutterActorMeta:name property on the
414 * given action or constraint.</para>
415 * <para>The property can be accessed using the following syntax:</para>
418 * @<section>.<meta-name>.<property-name>
421 * <para>The initial <emphasis>@</emphasis> is mandatory.</para>
422 * <para>The <emphasis>section</emphasis> fragment can be one between
423 * "actions", "constraints" and "effects".</para>
424 * <para>The <emphasis>meta-name</emphasis> fragment is the name of the
425 * action or constraint, as specified by the #ClutterActorMeta:name
427 * <para>The <emphasis>property-name</emphasis> fragment is the name of the
428 * action or constraint property to be animated.</para>
429 * <para>The example below animates a #ClutterBindConstraint applied to an
430 * actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
431 * a binding constraint for the <emphasis>origin</emphasis> actor, and in
432 * its initial state is overlapping the actor to which is bound to.</para>
433 * <informalexample><programlisting>
434 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
435 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
436 * clutter_actor_add_constraint (rect, constraint);
438 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
439 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
440 * clutter_actor_add_constraint (rect, constraint);
442 * clutter_actor_set_reactive (origin, TRUE);
444 * g_signal_connect (origin, "button-press-event",
445 * G_CALLBACK (on_button_press),
447 * </programlisting></informalexample>
448 * <para>On button press, the rectangle "slides" from behind the actor to
449 * which is bound to, using the #ClutterBindConstraint:offset property to
450 * achieve the effect:</para>
451 * <informalexample><programlisting>
453 * on_button_press (ClutterActor *origin,
454 * ClutterEvent *event,
455 * ClutterActor *rect)
457 * ClutterTransition *transition;
458 * ClutterInterval *interval;
460 * /* the offset that we want to apply; this will make the actor
461 * * slide in from behind the origin and rest at the right of
462 * * the origin, plus a padding value.
464 * float new_offset = clutter_actor_get_width (origin) + h_padding;
466 * /* the property we wish to animate; the "@constraints" section
467 * * tells Clutter to check inside the constraints associated
468 * * with the actor; the "bind-x" section is the name of the
469 * * constraint; and the "offset" is the name of the property
470 * * on the constraint.
472 * const char *prop = "@constraints.bind-x.offset";
474 * /* create a new transition for the given property */
475 * transition = clutter_property_transition_new (prop);
477 * /* set the easing mode and duration */
478 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
479 * CLUTTER_EASE_OUT_CUBIC);
480 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
482 * /* create the interval with the initial and final values */
483 * interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
484 * clutter_transition_set_interval (transition, interval);
486 * /* add the transition to the actor; this causes the animation
487 * * to start. the name "offsetAnimation" can be used to retrieve
488 * * the transition later.
490 * clutter_actor_add_transition (rect, "offsetAnimation", transition);
492 * /* we handled the event */
493 * return CLUTTER_EVENT_STOP;
495 * </programlisting></informalexample>
500 * CLUTTER_ACTOR_IS_MAPPED:
501 * @a: a #ClutterActor
503 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
505 * The mapped state is set when the actor is visible and all its parents up
506 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
508 * This check can be used to see if an actor is going to be painted, as only
509 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
511 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
512 * not be checked directly; instead, the recommended usage is to connect a
513 * handler on the #GObject::notify signal for the #ClutterActor:mapped
514 * property of #ClutterActor, and check the presence of
515 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
517 * It is also important to note that Clutter may delay the changes of
518 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
519 * limitations, or during the reparenting of an actor, to optimize
520 * unnecessary (and potentially expensive) state changes.
526 * CLUTTER_ACTOR_IS_REALIZED:
527 * @a: a #ClutterActor
529 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
531 * The realized state has an actor-dependant interpretation. If an
532 * actor wants to delay allocating resources until it is attached to a
533 * stage, it may use the realize state to do so. However it is
534 * perfectly acceptable for an actor to allocate Cogl resources before
535 * being realized because there is only one drawing context used by Clutter
536 * so any resources will work on any stage. If an actor is mapped it
537 * must also be realized, but an actor can be realized and unmapped
538 * (this is so hiding an actor temporarily doesn't do an expensive
539 * unrealize/realize).
541 * To be realized an actor must be inside a stage, and all its parents
548 * CLUTTER_ACTOR_IS_VISIBLE:
549 * @a: a #ClutterActor
551 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
552 * Equivalent to the ClutterActor::visible object property.
554 * Note that an actor is only painted onscreen if it's mapped, which
555 * means it's visible, and all its parents are visible, and one of the
556 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
562 * CLUTTER_ACTOR_IS_REACTIVE:
563 * @a: a #ClutterActor
565 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
567 * Only reactive actors will receive event-related signals.
578 #include <gobject/gvaluecollector.h>
580 #include <cogl/cogl.h>
582 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
583 #define CLUTTER_ENABLE_EXPERIMENTAL_API
585 #include "clutter-actor-private.h"
587 #include "clutter-action.h"
588 #include "clutter-actor-meta-private.h"
589 #include "clutter-animatable.h"
590 #include "clutter-color-static.h"
591 #include "clutter-color.h"
592 #include "clutter-constraint.h"
593 #include "clutter-container.h"
594 #include "clutter-content-private.h"
595 #include "clutter-debug.h"
596 #include "clutter-easing.h"
597 #include "clutter-effect-private.h"
598 #include "clutter-enum-types.h"
599 #include "clutter-fixed-layout.h"
600 #include "clutter-flatten-effect.h"
601 #include "clutter-interval.h"
602 #include "clutter-main.h"
603 #include "clutter-marshal.h"
604 #include "clutter-paint-nodes.h"
605 #include "clutter-paint-node-private.h"
606 #include "clutter-paint-volume-private.h"
607 #include "clutter-private.h"
608 #include "clutter-profile.h"
609 #include "clutter-property-transition.h"
610 #include "clutter-scriptable.h"
611 #include "clutter-script-private.h"
612 #include "clutter-stage-private.h"
613 #include "clutter-timeline.h"
614 #include "clutter-transition.h"
615 #include "clutter-units.h"
617 #include "deprecated/clutter-actor.h"
618 #include "deprecated/clutter-behaviour.h"
619 #include "deprecated/clutter-container.h"
621 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
622 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
624 /* Internal enum used to control mapped state update. This is a hint
625 * which indicates when to do something other than just enforce
629 MAP_STATE_CHECK, /* just enforce invariants. */
630 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
631 * used when about to unparent.
633 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
634 * used to set mapped on toplevels.
636 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
637 * used just before unmapping parent.
641 /* 3 entries should be a good compromise, few layout managers
642 * will ask for 3 different preferred size in each allocation cycle */
643 #define N_CACHED_SIZE_REQUESTS 3
645 struct _ClutterActorPrivate
648 ClutterRequestMode request_mode;
650 /* our cached size requests for different width / height */
651 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
652 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
654 /* An age of 0 means the entry is not set */
655 guint cached_height_age;
656 guint cached_width_age;
658 /* the bounding box of the actor, relative to the parent's
661 ClutterActorBox allocation;
662 ClutterAllocationFlags allocation_flags;
664 /* clip, in actor coordinates */
665 cairo_rectangle_t clip;
667 /* the cached transformation matrix; see apply_transform() */
668 CoglMatrix transform;
671 gint opacity_override;
673 ClutterOffscreenRedirect offscreen_redirect;
675 /* This is an internal effect used to implement the
676 offscreen-redirect property */
677 ClutterEffect *flatten_effect;
680 ClutterActor *parent;
681 ClutterActor *prev_sibling;
682 ClutterActor *next_sibling;
683 ClutterActor *first_child;
684 ClutterActor *last_child;
688 /* tracks whenever the children of an actor are changed; the
689 * age is incremented by 1 whenever an actor is added or
690 * removed. the age is not incremented when the first or the
691 * last child pointers are changed, or when grandchildren of
692 * an actor are changed.
696 gchar *name; /* a non-unique name, used for debugging */
697 guint32 id; /* unique id, used for backward compatibility */
699 gint32 pick_id; /* per-stage unique id, used for picking */
701 /* a back-pointer to the Pango context that we can use
702 * to create pre-configured PangoLayout
704 PangoContext *pango_context;
706 /* the text direction configured for this child - either by
707 * application code, or by the actor's parent
709 ClutterTextDirection text_direction;
711 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
715 ClutterMetaGroup *actions;
716 ClutterMetaGroup *constraints;
717 ClutterMetaGroup *effects;
719 /* delegate object used to allocate the children of this actor */
720 ClutterLayoutManager *layout_manager;
722 /* delegate object used to paint the contents of this actor */
723 ClutterContent *content;
725 ClutterActorBox content_box;
726 ClutterContentGravity content_gravity;
727 ClutterScalingFilter min_filter;
728 ClutterScalingFilter mag_filter;
730 /* used when painting, to update the paint volume */
731 ClutterEffect *current_effect;
733 /* This is used to store an effect which needs to be redrawn. A
734 redraw can be queued to start from a particular effect. This is
735 used by parametrised effects that can cache an image of the
736 actor. If a parameter of the effect changes then it only needs to
737 redraw the cached image, not the actual actor. The pointer is
738 only valid if is_dirty == TRUE. If the pointer is NULL then the
739 whole actor is dirty. */
740 ClutterEffect *effect_to_redraw;
742 /* This is used when painting effects to implement the
743 clutter_actor_continue_paint() function. It points to the node in
744 the list of effects that is next in the chain */
745 const GList *next_effect_to_paint;
747 ClutterPaintVolume paint_volume;
749 /* NB: This volume isn't relative to this actor, it is in eye
750 * coordinates so that it can remain valid after the actor changes.
752 ClutterPaintVolume last_paint_volume;
754 ClutterStageQueueRedrawEntry *queue_redraw_entry;
756 ClutterColor bg_color;
758 #ifdef CLUTTER_ENABLE_DEBUG
759 /* a string used for debugging messages */
765 /* fixed position and sizes */
766 guint position_set : 1;
767 guint min_width_set : 1;
768 guint min_height_set : 1;
769 guint natural_width_set : 1;
770 guint natural_height_set : 1;
771 /* cached request is invalid (implies allocation is too) */
772 guint needs_width_request : 1;
773 /* cached request is invalid (implies allocation is too) */
774 guint needs_height_request : 1;
775 /* cached allocation is invalid (request has changed, probably) */
776 guint needs_allocation : 1;
777 guint show_on_set_parent : 1;
779 guint clip_to_allocation : 1;
780 guint enable_model_view_transform : 1;
781 guint enable_paint_unmapped : 1;
782 guint has_pointer : 1;
783 guint propagated_one_redraw : 1;
784 guint paint_volume_valid : 1;
785 guint last_paint_volume_valid : 1;
786 guint in_clone_paint : 1;
787 guint transform_valid : 1;
788 /* This is TRUE if anything has queued a redraw since we were last
789 painted. In this case effect_to_redraw will point to an effect
790 the redraw was queued from or it will be NULL if the redraw was
791 queued without an effect. */
793 guint bg_color_set : 1;
794 guint content_box_valid : 1;
795 guint x_expand_set : 1;
796 guint y_expand_set : 1;
797 guint needs_compute_expand : 1;
798 guint needs_x_expand : 1;
799 guint needs_y_expand : 1;
808 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
809 * when set they force a size request, when gotten they
810 * get the allocation if the allocation is valid, and the
821 /* Then the rest of these size-related properties are the "actual"
822 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
827 PROP_FIXED_POSITION_SET,
836 PROP_NATURAL_WIDTH_SET,
839 PROP_NATURAL_HEIGHT_SET,
843 /* Allocation properties are read-only */
850 PROP_CLIP_TO_ALLOCATION,
854 PROP_OFFSCREEN_REDIRECT,
867 PROP_ROTATION_ANGLE_X,
868 PROP_ROTATION_ANGLE_Y,
869 PROP_ROTATION_ANGLE_Z,
870 PROP_ROTATION_CENTER_X,
871 PROP_ROTATION_CENTER_Y,
872 PROP_ROTATION_CENTER_Z,
873 /* This property only makes sense for the z rotation because the
874 others would depend on the actor having a size along the
876 PROP_ROTATION_CENTER_Z_GRAVITY,
882 PROP_SHOW_ON_SET_PARENT,
902 PROP_BACKGROUND_COLOR,
903 PROP_BACKGROUND_COLOR_SET,
909 PROP_CONTENT_GRAVITY,
911 PROP_MINIFICATION_FILTER,
912 PROP_MAGNIFICATION_FILTER,
917 static GParamSpec *obj_props[PROP_LAST];
936 BUTTON_RELEASE_EVENT,
944 TRANSITIONS_COMPLETED,
949 static guint actor_signals[LAST_SIGNAL] = { 0, };
951 typedef struct _TransitionClosure
954 ClutterTransition *transition;
959 static void clutter_container_iface_init (ClutterContainerIface *iface);
960 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
961 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
962 static void atk_implementor_iface_init (AtkImplementorIface *iface);
964 /* These setters are all static for now, maybe they should be in the
965 * public API, but they are perhaps obscure enough to leave only as
968 static void clutter_actor_set_min_width (ClutterActor *self,
970 static void clutter_actor_set_min_height (ClutterActor *self,
972 static void clutter_actor_set_natural_width (ClutterActor *self,
973 gfloat natural_width);
974 static void clutter_actor_set_natural_height (ClutterActor *self,
975 gfloat natural_height);
976 static void clutter_actor_set_min_width_set (ClutterActor *self,
977 gboolean use_min_width);
978 static void clutter_actor_set_min_height_set (ClutterActor *self,
979 gboolean use_min_height);
980 static void clutter_actor_set_natural_width_set (ClutterActor *self,
981 gboolean use_natural_width);
982 static void clutter_actor_set_natural_height_set (ClutterActor *self,
983 gboolean use_natural_height);
984 static void clutter_actor_update_map_state (ClutterActor *self,
985 MapStateChange change);
986 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
988 /* Helper routines for managing anchor coords */
989 static void clutter_anchor_coord_get_units (ClutterActor *self,
990 const AnchorCoord *coord,
994 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
999 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
1000 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
1001 ClutterGravity gravity);
1003 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
1005 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
1007 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
1008 ClutterActor *ancestor,
1009 CoglMatrix *matrix);
1011 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
1013 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
1015 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
1016 const ClutterColor *color);
1018 static void on_layout_manager_changed (ClutterLayoutManager *manager,
1019 ClutterActor *self);
1021 static inline void clutter_actor_queue_compute_expand (ClutterActor *self);
1023 /* Helper macro which translates by the anchor coord, applies the
1024 given transformation and then translates back */
1025 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
1026 gfloat _tx, _ty, _tz; \
1027 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
1028 cogl_matrix_translate ((m), _tx, _ty, _tz); \
1030 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
1032 static GQuark quark_shader_data = 0;
1033 static GQuark quark_actor_layout_info = 0;
1034 static GQuark quark_actor_transform_info = 0;
1035 static GQuark quark_actor_animation_info = 0;
1037 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1039 G_TYPE_INITIALLY_UNOWNED,
1040 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1041 clutter_container_iface_init)
1042 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1043 clutter_scriptable_iface_init)
1044 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1045 clutter_animatable_iface_init)
1046 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1047 atk_implementor_iface_init));
1050 * clutter_actor_get_debug_name:
1051 * @actor: a #ClutterActor
1053 * Retrieves a printable name of @actor for debugging messages
1055 * Return value: a string with a printable name
1058 _clutter_actor_get_debug_name (ClutterActor *actor)
1060 ClutterActorPrivate *priv = actor->priv;
1061 const gchar *retval;
1063 #ifdef CLUTTER_ENABLE_DEBUG
1064 if (G_UNLIKELY (priv->debug_name == NULL))
1066 priv->debug_name = g_strdup_printf ("<%s>[<%s>:%p]",
1067 priv->name != NULL ? priv->name
1069 G_OBJECT_TYPE_NAME (actor),
1073 retval = priv->debug_name;
1075 retval = priv->name != NULL
1077 : G_OBJECT_TYPE_NAME (actor);
1083 #ifdef CLUTTER_ENABLE_DEBUG
1084 /* XXX - this is for debugging only, remove once working (or leave
1085 * in only in some debug mode). Should leave it for a little while
1086 * until we're confident in the new map/realize/visible handling.
1089 clutter_actor_verify_map_state (ClutterActor *self)
1091 ClutterActorPrivate *priv = self->priv;
1093 if (CLUTTER_ACTOR_IS_REALIZED (self))
1095 /* all bets are off during reparent when we're potentially realized,
1096 * but should not be according to invariants
1098 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1100 if (priv->parent == NULL)
1102 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1106 g_warning ("Realized non-toplevel actor '%s' should "
1108 _clutter_actor_get_debug_name (self));
1110 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1112 g_warning ("Realized actor %s has an unrealized parent %s",
1113 _clutter_actor_get_debug_name (self),
1114 _clutter_actor_get_debug_name (priv->parent));
1119 if (CLUTTER_ACTOR_IS_MAPPED (self))
1121 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1122 g_warning ("Actor '%s' is mapped but not realized",
1123 _clutter_actor_get_debug_name (self));
1125 /* remaining bets are off during reparent when we're potentially
1126 * mapped, but should not be according to invariants
1128 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1130 if (priv->parent == NULL)
1132 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1134 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1135 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1137 g_warning ("Toplevel actor '%s' is mapped "
1139 _clutter_actor_get_debug_name (self));
1144 g_warning ("Mapped actor '%s' should have a parent",
1145 _clutter_actor_get_debug_name (self));
1150 ClutterActor *iter = self;
1152 /* check for the enable_paint_unmapped flag on the actor
1153 * and parents; if the flag is enabled at any point of this
1154 * branch of the scene graph then all the later checks
1157 while (iter != NULL)
1159 if (iter->priv->enable_paint_unmapped)
1162 iter = iter->priv->parent;
1165 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1167 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1169 _clutter_actor_get_debug_name (self),
1170 _clutter_actor_get_debug_name (priv->parent));
1173 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1175 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1177 _clutter_actor_get_debug_name (self),
1178 _clutter_actor_get_debug_name (priv->parent));
1181 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1183 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1184 g_warning ("Actor '%s' is mapped but its non-toplevel "
1185 "parent '%s' is not mapped",
1186 _clutter_actor_get_debug_name (self),
1187 _clutter_actor_get_debug_name (priv->parent));
1194 #endif /* CLUTTER_ENABLE_DEBUG */
1197 clutter_actor_set_mapped (ClutterActor *self,
1200 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1205 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1206 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1210 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1211 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1215 /* this function updates the mapped and realized states according to
1216 * invariants, in the appropriate order.
1219 clutter_actor_update_map_state (ClutterActor *self,
1220 MapStateChange change)
1222 gboolean was_mapped;
1224 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1226 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1228 /* the mapped flag on top-level actors must be set by the
1229 * per-backend implementation because it might be asynchronous.
1231 * That is, the MAPPED flag on toplevels currently tracks the X
1232 * server mapped-ness of the window, while the expected behavior
1233 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1234 * This creates some weird complexity by breaking the invariant
1235 * that if we're visible and all ancestors shown then we are
1236 * also mapped - instead, we are mapped if all ancestors
1237 * _possibly excepting_ the stage are mapped. The stage
1238 * will map/unmap for example when it is minimized or
1239 * moved to another workspace.
1241 * So, the only invariant on the stage is that if visible it
1242 * should be realized, and that it has to be visible to be
1245 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1246 clutter_actor_realize (self);
1250 case MAP_STATE_CHECK:
1253 case MAP_STATE_MAKE_MAPPED:
1254 g_assert (!was_mapped);
1255 clutter_actor_set_mapped (self, TRUE);
1258 case MAP_STATE_MAKE_UNMAPPED:
1259 g_assert (was_mapped);
1260 clutter_actor_set_mapped (self, FALSE);
1263 case MAP_STATE_MAKE_UNREALIZED:
1264 /* we only use MAKE_UNREALIZED in unparent,
1265 * and unparenting a stage isn't possible.
1266 * If someone wants to just unrealize a stage
1267 * then clutter_actor_unrealize() doesn't
1268 * go through this codepath.
1270 g_warning ("Trying to force unrealize stage is not allowed");
1274 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1275 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1276 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1278 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1279 "it is somehow still mapped",
1280 _clutter_actor_get_debug_name (self));
1285 ClutterActorPrivate *priv = self->priv;
1286 ClutterActor *parent = priv->parent;
1287 gboolean should_be_mapped;
1288 gboolean may_be_realized;
1289 gboolean must_be_realized;
1291 should_be_mapped = FALSE;
1292 may_be_realized = TRUE;
1293 must_be_realized = FALSE;
1295 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1297 may_be_realized = FALSE;
1301 /* Maintain invariant that if parent is mapped, and we are
1302 * visible, then we are mapped ... unless parent is a
1303 * stage, in which case we map regardless of parent's map
1304 * state but do require stage to be visible and realized.
1306 * If parent is realized, that does not force us to be
1307 * realized; but if parent is unrealized, that does force
1308 * us to be unrealized.
1310 * The reason we don't force children to realize with
1311 * parents is _clutter_actor_rerealize(); if we require that
1312 * a realized parent means children are realized, then to
1313 * unrealize an actor we would have to unrealize its
1314 * parents, which would end up meaning unrealizing and
1315 * hiding the entire stage. So we allow unrealizing a
1316 * child (as long as that child is not mapped) while that
1317 * child still has a realized parent.
1319 * Also, if we unrealize from leaf nodes to root, and
1320 * realize from root to leaf, the invariants are never
1321 * violated if we allow children to be unrealized
1322 * while parents are realized.
1324 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1325 * to force us to unmap, even though parent is still
1326 * mapped. This is because we're unmapping from leaf nodes
1329 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1330 change != MAP_STATE_MAKE_UNMAPPED)
1332 gboolean parent_is_visible_realized_toplevel;
1334 parent_is_visible_realized_toplevel =
1335 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1336 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1337 CLUTTER_ACTOR_IS_REALIZED (parent));
1339 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1340 parent_is_visible_realized_toplevel)
1342 must_be_realized = TRUE;
1343 should_be_mapped = TRUE;
1347 /* if the actor has been set to be painted even if unmapped
1348 * then we should map it and check for realization as well;
1349 * this is an override for the branch of the scene graph
1350 * which begins with this node
1352 if (priv->enable_paint_unmapped)
1354 if (priv->parent == NULL)
1355 g_warning ("Attempting to map an unparented actor '%s'",
1356 _clutter_actor_get_debug_name (self));
1358 should_be_mapped = TRUE;
1359 must_be_realized = TRUE;
1362 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1363 may_be_realized = FALSE;
1366 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1369 g_warning ("Attempting to map a child that does not "
1370 "meet the necessary invariants: the actor '%s' "
1372 _clutter_actor_get_debug_name (self));
1374 g_warning ("Attempting to map a child that does not "
1375 "meet the necessary invariants: the actor '%s' "
1376 "is parented to an unmapped actor '%s'",
1377 _clutter_actor_get_debug_name (self),
1378 _clutter_actor_get_debug_name (priv->parent));
1381 /* If in reparent, we temporarily suspend unmap and unrealize.
1383 * We want to go in the order "realize, map" and "unmap, unrealize"
1387 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1388 clutter_actor_set_mapped (self, FALSE);
1391 if (must_be_realized)
1392 clutter_actor_realize (self);
1394 /* if we must be realized then we may be, presumably */
1395 g_assert (!(must_be_realized && !may_be_realized));
1398 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1399 clutter_actor_unrealize_not_hiding (self);
1402 if (should_be_mapped)
1404 if (!must_be_realized)
1405 g_warning ("Somehow we think actor '%s' should be mapped but "
1406 "not realized, which isn't allowed",
1407 _clutter_actor_get_debug_name (self));
1409 /* realization is allowed to fail (though I don't know what
1410 * an app is supposed to do about that - shouldn't it just
1411 * be a g_error? anyway, we have to avoid mapping if this
1414 if (CLUTTER_ACTOR_IS_REALIZED (self))
1415 clutter_actor_set_mapped (self, TRUE);
1419 #ifdef CLUTTER_ENABLE_DEBUG
1420 /* check all invariants were kept */
1421 clutter_actor_verify_map_state (self);
1426 clutter_actor_real_map (ClutterActor *self)
1428 ClutterActorPrivate *priv = self->priv;
1429 ClutterActor *stage, *iter;
1431 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1433 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1434 _clutter_actor_get_debug_name (self));
1436 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1438 stage = _clutter_actor_get_stage_internal (self);
1439 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1441 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1443 _clutter_actor_get_debug_name (self));
1445 /* notify on parent mapped before potentially mapping
1446 * children, so apps see a top-down notification.
1448 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1450 for (iter = self->priv->first_child;
1452 iter = iter->priv->next_sibling)
1454 clutter_actor_map (iter);
1459 * clutter_actor_map:
1460 * @self: A #ClutterActor
1462 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1463 * and realizes its children if they are visible. Does nothing if the
1464 * actor is not visible.
1466 * Calling this function is strongly disencouraged: the default
1467 * implementation of #ClutterActorClass.map() will map all the children
1468 * of an actor when mapping its parent.
1470 * When overriding map, it is mandatory to chain up to the parent
1476 clutter_actor_map (ClutterActor *self)
1478 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1480 if (CLUTTER_ACTOR_IS_MAPPED (self))
1483 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1486 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1490 clutter_actor_real_unmap (ClutterActor *self)
1492 ClutterActorPrivate *priv = self->priv;
1495 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1497 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1498 _clutter_actor_get_debug_name (self));
1500 for (iter = self->priv->first_child;
1502 iter = iter->priv->next_sibling)
1504 clutter_actor_unmap (iter);
1507 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1509 /* clear the contents of the last paint volume, so that hiding + moving +
1510 * showing will not result in the wrong area being repainted
1512 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1513 priv->last_paint_volume_valid = TRUE;
1515 /* notify on parent mapped after potentially unmapping
1516 * children, so apps see a bottom-up notification.
1518 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1520 /* relinquish keyboard focus if we were unmapped while owning it */
1521 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1523 ClutterStage *stage;
1525 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1528 _clutter_stage_release_pick_id (stage, priv->pick_id);
1532 if (stage != NULL &&
1533 clutter_stage_get_key_focus (stage) == self)
1535 clutter_stage_set_key_focus (stage, NULL);
1541 * clutter_actor_unmap:
1542 * @self: A #ClutterActor
1544 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1545 * unmaps its children if they were mapped.
1547 * Calling this function is not encouraged: the default #ClutterActor
1548 * implementation of #ClutterActorClass.unmap() will also unmap any
1549 * eventual children by default when their parent is unmapped.
1551 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1552 * chain up to the parent implementation.
1554 * <note>It is important to note that the implementation of the
1555 * #ClutterActorClass.unmap() virtual function may be called after
1556 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1557 * implementation, but it is guaranteed to be called before the
1558 * #GObjectClass.finalize() implementation.</note>
1563 clutter_actor_unmap (ClutterActor *self)
1565 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1567 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1570 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1574 clutter_actor_real_show (ClutterActor *self)
1576 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1578 ClutterActorPrivate *priv = self->priv;
1580 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1582 /* we notify on the "visible" flag in the clutter_actor_show()
1583 * wrapper so the entire show signal emission completes first
1586 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1588 /* we queue a relayout unless the actor is inside a
1589 * container that explicitly told us not to
1591 if (priv->parent != NULL &&
1592 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1594 /* While an actor is hidden the parent may not have
1595 * allocated/requested so we need to start from scratch
1596 * and avoid the short-circuiting in
1597 * clutter_actor_queue_relayout().
1599 priv->needs_width_request = FALSE;
1600 priv->needs_height_request = FALSE;
1601 priv->needs_allocation = FALSE;
1602 clutter_actor_queue_relayout (self);
1608 set_show_on_set_parent (ClutterActor *self,
1611 ClutterActorPrivate *priv = self->priv;
1613 set_show = !!set_show;
1615 if (priv->show_on_set_parent == set_show)
1618 if (priv->parent == NULL)
1620 priv->show_on_set_parent = set_show;
1621 g_object_notify_by_pspec (G_OBJECT (self),
1622 obj_props[PROP_SHOW_ON_SET_PARENT]);
1627 * clutter_actor_show:
1628 * @self: A #ClutterActor
1630 * Flags an actor to be displayed. An actor that isn't shown will not
1631 * be rendered on the stage.
1633 * Actors are visible by default.
1635 * If this function is called on an actor without a parent, the
1636 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1640 clutter_actor_show (ClutterActor *self)
1642 ClutterActorPrivate *priv;
1644 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1646 /* simple optimization */
1647 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1649 /* we still need to set the :show-on-set-parent property, in
1650 * case show() is called on an unparented actor
1652 set_show_on_set_parent (self, TRUE);
1656 #ifdef CLUTTER_ENABLE_DEBUG
1657 clutter_actor_verify_map_state (self);
1662 g_object_freeze_notify (G_OBJECT (self));
1664 set_show_on_set_parent (self, TRUE);
1666 /* if we're showing a child that needs to expand, or may
1667 * expand, then we need to recompute the expand flags for
1668 * its parent as well
1670 if (priv->needs_compute_expand ||
1671 priv->needs_x_expand ||
1672 priv->needs_y_expand)
1674 clutter_actor_queue_compute_expand (self);
1677 g_signal_emit (self, actor_signals[SHOW], 0);
1678 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1680 if (priv->parent != NULL)
1681 clutter_actor_queue_redraw (priv->parent);
1683 g_object_thaw_notify (G_OBJECT (self));
1687 * clutter_actor_show_all:
1688 * @self: a #ClutterActor
1690 * Calls clutter_actor_show() on all children of an actor (if any).
1694 * Deprecated: 1.10: Actors are visible by default
1697 clutter_actor_show_all (ClutterActor *self)
1699 ClutterActorClass *klass;
1701 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1703 klass = CLUTTER_ACTOR_GET_CLASS (self);
1704 if (klass->show_all)
1705 klass->show_all (self);
1709 clutter_actor_real_hide (ClutterActor *self)
1711 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1713 ClutterActorPrivate *priv = self->priv;
1715 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1717 /* we notify on the "visible" flag in the clutter_actor_hide()
1718 * wrapper so the entire hide signal emission completes first
1721 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1723 /* we queue a relayout unless the actor is inside a
1724 * container that explicitly told us not to
1726 if (priv->parent != NULL &&
1727 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1728 clutter_actor_queue_relayout (priv->parent);
1733 * clutter_actor_hide:
1734 * @self: A #ClutterActor
1736 * Flags an actor to be hidden. A hidden actor will not be
1737 * rendered on the stage.
1739 * Actors are visible by default.
1741 * If this function is called on an actor without a parent, the
1742 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1746 clutter_actor_hide (ClutterActor *self)
1748 ClutterActorPrivate *priv;
1750 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1752 /* simple optimization */
1753 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1755 /* we still need to set the :show-on-set-parent property, in
1756 * case hide() is called on an unparented actor
1758 set_show_on_set_parent (self, FALSE);
1762 #ifdef CLUTTER_ENABLE_DEBUG
1763 clutter_actor_verify_map_state (self);
1768 g_object_freeze_notify (G_OBJECT (self));
1770 set_show_on_set_parent (self, FALSE);
1772 /* if we're hiding a child that needs to expand, or may
1773 * expand, then we need to recompute the expand flags for
1774 * its parent as well
1776 if (priv->needs_compute_expand ||
1777 priv->needs_x_expand ||
1778 priv->needs_y_expand)
1780 clutter_actor_queue_compute_expand (self);
1783 g_signal_emit (self, actor_signals[HIDE], 0);
1784 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1786 if (priv->parent != NULL)
1787 clutter_actor_queue_redraw (priv->parent);
1789 g_object_thaw_notify (G_OBJECT (self));
1793 * clutter_actor_hide_all:
1794 * @self: a #ClutterActor
1796 * Calls clutter_actor_hide() on all child actors (if any).
1800 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1801 * prevent its children from being painted as well.
1804 clutter_actor_hide_all (ClutterActor *self)
1806 ClutterActorClass *klass;
1808 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1810 klass = CLUTTER_ACTOR_GET_CLASS (self);
1811 if (klass->hide_all)
1812 klass->hide_all (self);
1816 * clutter_actor_realize:
1817 * @self: A #ClutterActor
1819 * Realization informs the actor that it is attached to a stage. It
1820 * can use this to allocate resources if it wanted to delay allocation
1821 * until it would be rendered. However it is perfectly acceptable for
1822 * an actor to create resources before being realized because Clutter
1823 * only ever has a single rendering context so that actor is free to
1824 * be moved from one stage to another.
1826 * This function does nothing if the actor is already realized.
1828 * Because a realized actor must have realized parent actors, calling
1829 * clutter_actor_realize() will also realize all parents of the actor.
1831 * This function does not realize child actors, except in the special
1832 * case that realizing the stage, when the stage is visible, will
1833 * suddenly map (and thus realize) the children of the stage.
1836 clutter_actor_realize (ClutterActor *self)
1838 ClutterActorPrivate *priv;
1840 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1844 #ifdef CLUTTER_ENABLE_DEBUG
1845 clutter_actor_verify_map_state (self);
1848 if (CLUTTER_ACTOR_IS_REALIZED (self))
1851 /* To be realized, our parent actors must be realized first.
1852 * This will only succeed if we're inside a toplevel.
1854 if (priv->parent != NULL)
1855 clutter_actor_realize (priv->parent);
1857 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1859 /* toplevels can be realized at any time */
1863 /* "Fail" the realization if parent is missing or unrealized;
1864 * this should really be a g_warning() not some kind of runtime
1865 * failure; how can an app possibly recover? Instead it's a bug
1866 * in the app and the app should get an explanatory warning so
1867 * someone can fix it. But for now it's too hard to fix this
1868 * because e.g. ClutterTexture needs reworking.
1870 if (priv->parent == NULL ||
1871 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1875 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1877 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1878 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1880 g_signal_emit (self, actor_signals[REALIZE], 0);
1882 /* Stage actor is allowed to unset the realized flag again in its
1883 * default signal handler, though that is a pathological situation.
1886 /* If realization "failed" we'll have to update child state. */
1887 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1891 clutter_actor_real_unrealize (ClutterActor *self)
1893 /* we must be unmapped (implying our children are also unmapped) */
1894 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1898 * clutter_actor_unrealize:
1899 * @self: A #ClutterActor
1901 * Unrealization informs the actor that it may be being destroyed or
1902 * moved to another stage. The actor may want to destroy any
1903 * underlying graphics resources at this point. However it is
1904 * perfectly acceptable for it to retain the resources until the actor
1905 * is destroyed because Clutter only ever uses a single rendering
1906 * context and all of the graphics resources are valid on any stage.
1908 * Because mapped actors must be realized, actors may not be
1909 * unrealized if they are mapped. This function hides the actor to be
1910 * sure it isn't mapped, an application-visible side effect that you
1911 * may not be expecting.
1913 * This function should not be called by application code.
1916 clutter_actor_unrealize (ClutterActor *self)
1918 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1919 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1921 /* This function should not really be in the public API, because
1922 * there isn't a good reason to call it. ClutterActor will already
1923 * unrealize things for you when it's important to do so.
1925 * If you were using clutter_actor_unrealize() in a dispose
1926 * implementation, then don't, just chain up to ClutterActor's
1929 * If you were using clutter_actor_unrealize() to implement
1930 * unrealizing children of your container, then don't, ClutterActor
1931 * will already take care of that.
1933 * If you were using clutter_actor_unrealize() to re-realize to
1934 * create your resources in a different way, then use
1935 * _clutter_actor_rerealize() (inside Clutter) or just call your
1936 * code that recreates your resources directly (outside Clutter).
1939 #ifdef CLUTTER_ENABLE_DEBUG
1940 clutter_actor_verify_map_state (self);
1943 clutter_actor_hide (self);
1945 clutter_actor_unrealize_not_hiding (self);
1948 static ClutterActorTraverseVisitFlags
1949 unrealize_actor_before_children_cb (ClutterActor *self,
1953 /* If an actor is already unrealized we know its children have also
1954 * already been unrealized... */
1955 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1956 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1958 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1960 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1963 static ClutterActorTraverseVisitFlags
1964 unrealize_actor_after_children_cb (ClutterActor *self,
1968 /* We want to unset the realized flag only _after_
1969 * child actors are unrealized, to maintain invariants.
1971 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1972 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1973 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1977 * clutter_actor_unrealize_not_hiding:
1978 * @self: A #ClutterActor
1980 * Unrealization informs the actor that it may be being destroyed or
1981 * moved to another stage. The actor may want to destroy any
1982 * underlying graphics resources at this point. However it is
1983 * perfectly acceptable for it to retain the resources until the actor
1984 * is destroyed because Clutter only ever uses a single rendering
1985 * context and all of the graphics resources are valid on any stage.
1987 * Because mapped actors must be realized, actors may not be
1988 * unrealized if they are mapped. You must hide the actor or one of
1989 * its parents before attempting to unrealize.
1991 * This function is separate from clutter_actor_unrealize() because it
1992 * does not automatically hide the actor.
1993 * Actors need not be hidden to be unrealized, they just need to
1994 * be unmapped. In fact we don't want to mess up the application's
1995 * setting of the "visible" flag, so hiding is very undesirable.
1997 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1998 * backward compatibility.
2001 clutter_actor_unrealize_not_hiding (ClutterActor *self)
2003 _clutter_actor_traverse (self,
2004 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
2005 unrealize_actor_before_children_cb,
2006 unrealize_actor_after_children_cb,
2011 * _clutter_actor_rerealize:
2012 * @self: A #ClutterActor
2013 * @callback: Function to call while unrealized
2014 * @data: data for callback
2016 * If an actor is already unrealized, this just calls the callback.
2018 * If it is realized, it unrealizes temporarily, calls the callback,
2019 * and then re-realizes the actor.
2021 * As a side effect, leaves all children of the actor unrealized if
2022 * the actor was realized but not showing. This is because when we
2023 * unrealize the actor temporarily we must unrealize its children
2024 * (e.g. children of a stage can't be realized if stage window is
2025 * gone). And we aren't clever enough to save the realization state of
2026 * all children. In most cases this should not matter, because
2027 * the children will automatically realize when they next become mapped.
2030 _clutter_actor_rerealize (ClutterActor *self,
2031 ClutterCallback callback,
2034 gboolean was_mapped;
2035 gboolean was_showing;
2036 gboolean was_realized;
2038 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2040 #ifdef CLUTTER_ENABLE_DEBUG
2041 clutter_actor_verify_map_state (self);
2044 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
2045 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
2046 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
2048 /* Must be unmapped to unrealize. Note we only have to hide this
2049 * actor if it was mapped (if all parents were showing). If actor
2050 * is merely visible (but not mapped), then that's fine, we can
2054 clutter_actor_hide (self);
2056 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
2058 /* unrealize self and all children */
2059 clutter_actor_unrealize_not_hiding (self);
2061 if (callback != NULL)
2063 (* callback) (self, data);
2067 clutter_actor_show (self); /* will realize only if mapping implies it */
2068 else if (was_realized)
2069 clutter_actor_realize (self); /* realize self and all parents */
2073 clutter_actor_real_pick (ClutterActor *self,
2074 const ClutterColor *color)
2076 /* the default implementation is just to paint a rectangle
2077 * with the same size of the actor using the passed color
2079 if (clutter_actor_should_pick_paint (self))
2081 ClutterActorBox box = { 0, };
2082 float width, height;
2084 clutter_actor_get_allocation_box (self, &box);
2086 width = box.x2 - box.x1;
2087 height = box.y2 - box.y1;
2089 cogl_set_source_color4ub (color->red,
2094 cogl_rectangle (0, 0, width, height);
2097 /* XXX - this thoroughly sucks, but we need to maintain compatibility
2098 * with existing container classes that override the pick() virtual
2099 * and chain up to the default implementation - otherwise we'll end up
2100 * painting our children twice.
2102 * this has to go away for 2.0; hopefully along the pick() itself.
2104 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2108 for (iter = self->priv->first_child;
2110 iter = iter->priv->next_sibling)
2111 clutter_actor_paint (iter);
2116 * clutter_actor_should_pick_paint:
2117 * @self: A #ClutterActor
2119 * Should be called inside the implementation of the
2120 * #ClutterActor::pick virtual function in order to check whether
2121 * the actor should paint itself in pick mode or not.
2123 * This function should never be called directly by applications.
2125 * Return value: %TRUE if the actor should paint its silhouette,
2129 clutter_actor_should_pick_paint (ClutterActor *self)
2131 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2133 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2134 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2135 CLUTTER_ACTOR_IS_REACTIVE (self)))
2142 clutter_actor_real_get_preferred_width (ClutterActor *self,
2144 gfloat *min_width_p,
2145 gfloat *natural_width_p)
2147 ClutterActorPrivate *priv = self->priv;
2149 if (priv->n_children != 0 &&
2150 priv->layout_manager != NULL)
2152 ClutterContainer *container = CLUTTER_CONTAINER (self);
2154 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2155 "for the preferred width",
2156 G_OBJECT_TYPE_NAME (priv->layout_manager),
2157 priv->layout_manager);
2159 clutter_layout_manager_get_preferred_width (priv->layout_manager,
2168 /* Default implementation is always 0x0, usually an actor
2169 * using this default is relying on someone to set the
2172 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2177 if (natural_width_p)
2178 *natural_width_p = 0;
2182 clutter_actor_real_get_preferred_height (ClutterActor *self,
2184 gfloat *min_height_p,
2185 gfloat *natural_height_p)
2187 ClutterActorPrivate *priv = self->priv;
2189 if (priv->n_children != 0 &&
2190 priv->layout_manager != NULL)
2192 ClutterContainer *container = CLUTTER_CONTAINER (self);
2194 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2195 "for the preferred height",
2196 G_OBJECT_TYPE_NAME (priv->layout_manager),
2197 priv->layout_manager);
2199 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2207 /* Default implementation is always 0x0, usually an actor
2208 * using this default is relying on someone to set the
2211 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2216 if (natural_height_p)
2217 *natural_height_p = 0;
2221 clutter_actor_store_old_geometry (ClutterActor *self,
2222 ClutterActorBox *box)
2224 *box = self->priv->allocation;
2228 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2229 const ClutterActorBox *old)
2231 ClutterActorPrivate *priv = self->priv;
2232 GObject *obj = G_OBJECT (self);
2234 g_object_freeze_notify (obj);
2236 /* to avoid excessive requisition or allocation cycles we
2237 * use the cached values.
2239 * - if we don't have an allocation we assume that we need
2241 * - if we don't have a width or a height request we notify
2243 * - if we have a valid allocation then we check the old
2244 * bounding box with the current allocation and we notify
2247 if (priv->needs_allocation)
2249 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2250 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2251 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2252 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2253 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2254 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2256 else if (priv->needs_width_request || priv->needs_height_request)
2258 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2259 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2260 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2265 gfloat width, height;
2267 x = priv->allocation.x1;
2268 y = priv->allocation.y1;
2269 width = priv->allocation.x2 - priv->allocation.x1;
2270 height = priv->allocation.y2 - priv->allocation.y1;
2274 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2275 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2280 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2281 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2284 if (width != (old->x2 - old->x1))
2286 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2287 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2290 if (height != (old->y2 - old->y1))
2292 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2293 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2297 g_object_thaw_notify (obj);
2301 * clutter_actor_set_allocation_internal:
2302 * @self: a #ClutterActor
2303 * @box: a #ClutterActorBox
2304 * @flags: allocation flags
2306 * Stores the allocation of @self.
2308 * This function only performs basic storage and property notification.
2310 * This function should be called by clutter_actor_set_allocation()
2311 * and by the default implementation of #ClutterActorClass.allocate().
2313 * Return value: %TRUE if the allocation of the #ClutterActor has been
2314 * changed, and %FALSE otherwise
2316 static inline gboolean
2317 clutter_actor_set_allocation_internal (ClutterActor *self,
2318 const ClutterActorBox *box,
2319 ClutterAllocationFlags flags)
2321 ClutterActorPrivate *priv = self->priv;
2323 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2325 ClutterActorBox old_alloc = { 0, };
2327 obj = G_OBJECT (self);
2329 g_object_freeze_notify (obj);
2331 clutter_actor_store_old_geometry (self, &old_alloc);
2333 x1_changed = priv->allocation.x1 != box->x1;
2334 y1_changed = priv->allocation.y1 != box->y1;
2335 x2_changed = priv->allocation.x2 != box->x2;
2336 y2_changed = priv->allocation.y2 != box->y2;
2338 priv->allocation = *box;
2339 priv->allocation_flags = flags;
2341 /* allocation is authoritative */
2342 priv->needs_width_request = FALSE;
2343 priv->needs_height_request = FALSE;
2344 priv->needs_allocation = FALSE;
2351 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2352 _clutter_actor_get_debug_name (self));
2354 priv->transform_valid = FALSE;
2356 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2358 /* if the allocation changes, so does the content box */
2359 if (priv->content != NULL)
2361 priv->content_box_valid = FALSE;
2362 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2370 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2372 g_object_thaw_notify (obj);
2377 static void clutter_actor_real_allocate (ClutterActor *self,
2378 const ClutterActorBox *box,
2379 ClutterAllocationFlags flags);
2382 clutter_actor_maybe_layout_children (ClutterActor *self,
2383 const ClutterActorBox *allocation,
2384 ClutterAllocationFlags flags)
2386 ClutterActorPrivate *priv = self->priv;
2388 /* this is going to be a bit hard to follow, so let's put an explanation
2391 * we want ClutterActor to have a default layout manager if the actor was
2392 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2394 * we also want any subclass of ClutterActor that does not override the
2395 * ::allocate() virtual function to delegate to a layout manager.
2397 * finally, we want to allow people subclassing ClutterActor and overriding
2398 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2400 * on the other hand, we want existing actor subclasses overriding the
2401 * ::allocate() virtual function and chaining up to the parent's
2402 * implementation to continue working without allocating their children
2403 * twice, or without entering an allocation loop.
2405 * for the first two points, we check if the class of the actor is
2406 * overridding the ::allocate() virtual function; if it isn't, then we
2407 * follow through with checking whether we have children and a layout
2408 * manager, and eventually calling clutter_layout_manager_allocate().
2410 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2411 * allocation flags that we got passed, and if it is present, we continue
2412 * with the check above.
2414 * if neither of these two checks yields a positive result, we just
2415 * assume that the ::allocate() virtual function that resulted in this
2416 * function being called will also allocate the children of the actor.
2419 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2422 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2428 if (priv->n_children != 0 &&
2429 priv->layout_manager != NULL)
2431 ClutterContainer *container = CLUTTER_CONTAINER (self);
2432 ClutterAllocationFlags children_flags;
2433 ClutterActorBox children_box;
2435 /* normalize the box passed to the layout manager */
2436 children_box.x1 = children_box.y1 = 0.f;
2437 children_box.x2 = (allocation->x2 - allocation->x1);
2438 children_box.y2 = (allocation->y2 - allocation->y1);
2440 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2441 * the actor's children, since it refers only to the current
2442 * actor's allocation.
2444 children_flags = flags;
2445 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2447 CLUTTER_NOTE (LAYOUT,
2448 "Allocating %d children of %s "
2449 "at { %.2f, %.2f - %.2f x %.2f } "
2452 _clutter_actor_get_debug_name (self),
2455 (allocation->x2 - allocation->x1),
2456 (allocation->y2 - allocation->y1),
2457 G_OBJECT_TYPE_NAME (priv->layout_manager));
2459 clutter_layout_manager_allocate (priv->layout_manager,
2467 clutter_actor_real_allocate (ClutterActor *self,
2468 const ClutterActorBox *box,
2469 ClutterAllocationFlags flags)
2471 ClutterActorPrivate *priv = self->priv;
2474 g_object_freeze_notify (G_OBJECT (self));
2476 changed = clutter_actor_set_allocation_internal (self, box, flags);
2478 /* we allocate our children before we notify changes in our geometry,
2479 * so that people connecting to properties will be able to get valid
2480 * data out of the sub-tree of the scene graph that has this actor at
2483 clutter_actor_maybe_layout_children (self, box, flags);
2487 ClutterActorBox signal_box = priv->allocation;
2488 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2490 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2495 g_object_thaw_notify (G_OBJECT (self));
2499 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2500 ClutterActor *origin)
2502 /* no point in queuing a redraw on a destroyed actor */
2503 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2506 /* NB: We can't bail out early here if the actor is hidden in case
2507 * the actor bas been cloned. In this case the clone will need to
2508 * receive the signal so it can queue its own redraw.
2511 /* calls klass->queue_redraw in default handler */
2512 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2516 clutter_actor_real_queue_redraw (ClutterActor *self,
2517 ClutterActor *origin)
2519 ClutterActor *parent;
2521 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2522 _clutter_actor_get_debug_name (self),
2523 origin != NULL ? _clutter_actor_get_debug_name (origin)
2526 /* no point in queuing a redraw on a destroyed actor */
2527 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2530 /* If the queue redraw is coming from a child then the actor has
2531 become dirty and any queued effect is no longer valid */
2534 self->priv->is_dirty = TRUE;
2535 self->priv->effect_to_redraw = NULL;
2538 /* If the actor isn't visible, we still had to emit the signal
2539 * to allow for a ClutterClone, but the appearance of the parent
2540 * won't change so we don't have to propagate up the hierarchy.
2542 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2545 /* Although we could determine here that a full stage redraw
2546 * has already been queued and immediately bail out, we actually
2547 * guarantee that we will propagate a queue-redraw signal to our
2548 * parent at least once so that it's possible to implement a
2549 * container that tracks which of its children have queued a
2552 if (self->priv->propagated_one_redraw)
2554 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2555 if (stage != NULL &&
2556 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2560 self->priv->propagated_one_redraw = TRUE;
2562 /* notify parents, if they are all visible eventually we'll
2563 * queue redraw on the stage, which queues the redraw idle.
2565 parent = clutter_actor_get_parent (self);
2568 /* this will go up recursively */
2569 _clutter_actor_signal_queue_redraw (parent, origin);
2574 clutter_actor_real_queue_relayout (ClutterActor *self)
2576 ClutterActorPrivate *priv = self->priv;
2578 /* no point in queueing a redraw on a destroyed actor */
2579 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2582 priv->needs_width_request = TRUE;
2583 priv->needs_height_request = TRUE;
2584 priv->needs_allocation = TRUE;
2586 /* reset the cached size requests */
2587 memset (priv->width_requests, 0,
2588 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2589 memset (priv->height_requests, 0,
2590 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2592 /* We need to go all the way up the hierarchy */
2593 if (priv->parent != NULL)
2594 _clutter_actor_queue_only_relayout (priv->parent);
2598 * clutter_actor_apply_relative_transform_to_point:
2599 * @self: A #ClutterActor
2600 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2601 * default #ClutterStage
2602 * @point: A point as #ClutterVertex
2603 * @vertex: (out caller-allocates): The translated #ClutterVertex
2605 * Transforms @point in coordinates relative to the actor into
2606 * ancestor-relative coordinates using the relevant transform
2607 * stack (i.e. scale, rotation, etc).
2609 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2610 * this case, the coordinates returned will be the coordinates on
2611 * the stage before the projection is applied. This is different from
2612 * the behaviour of clutter_actor_apply_transform_to_point().
2617 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2618 ClutterActor *ancestor,
2619 const ClutterVertex *point,
2620 ClutterVertex *vertex)
2625 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2626 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2627 g_return_if_fail (point != NULL);
2628 g_return_if_fail (vertex != NULL);
2633 if (ancestor == NULL)
2634 ancestor = _clutter_actor_get_stage_internal (self);
2636 if (ancestor == NULL)
2642 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2643 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2647 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2648 const ClutterVertex *vertices_in,
2649 ClutterVertex *vertices_out,
2652 ClutterActor *stage;
2653 CoglMatrix modelview;
2654 CoglMatrix projection;
2657 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2659 stage = _clutter_actor_get_stage_internal (self);
2661 /* We really can't do anything meaningful in this case so don't try
2662 * to do any transform */
2666 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2667 * that gets us to stage coordinates, we want to go all the way to eye
2669 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2671 /* Fetch the projection and viewport */
2672 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2673 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2679 _clutter_util_fully_transform_vertices (&modelview,
2690 * clutter_actor_apply_transform_to_point:
2691 * @self: A #ClutterActor
2692 * @point: A point as #ClutterVertex
2693 * @vertex: (out caller-allocates): The translated #ClutterVertex
2695 * Transforms @point in coordinates relative to the actor
2696 * into screen-relative coordinates with the current actor
2697 * transformation (i.e. scale, rotation, etc)
2702 clutter_actor_apply_transform_to_point (ClutterActor *self,
2703 const ClutterVertex *point,
2704 ClutterVertex *vertex)
2706 g_return_if_fail (point != NULL);
2707 g_return_if_fail (vertex != NULL);
2708 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2712 * _clutter_actor_get_relative_transformation_matrix:
2713 * @self: The actor whose coordinate space you want to transform from.
2714 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2715 * or %NULL if you want to transform all the way to eye coordinates.
2716 * @matrix: A #CoglMatrix to store the transformation
2718 * This gets a transformation @matrix that will transform coordinates from the
2719 * coordinate space of @self into the coordinate space of @ancestor.
2721 * For example if you need a matrix that can transform the local actor
2722 * coordinates of @self into stage coordinates you would pass the actor's stage
2723 * pointer as the @ancestor.
2725 * If you pass %NULL then the transformation will take you all the way through
2726 * to eye coordinates. This can be useful if you want to extract the entire
2727 * modelview transform that Clutter applies before applying the projection
2728 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2729 * using cogl_set_modelview_matrix() for example then you would want a matrix
2730 * that transforms into eye coordinates.
2732 * <note><para>This function explicitly initializes the given @matrix. If you just
2733 * want clutter to multiply a relative transformation with an existing matrix
2734 * you can use clutter_actor_apply_relative_transformation_matrix()
2735 * instead.</para></note>
2738 /* XXX: We should consider caching the stage relative modelview along with
2739 * the actor itself */
2741 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2742 ClutterActor *ancestor,
2745 cogl_matrix_init_identity (matrix);
2747 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2750 /* Project the given @box into stage window coordinates, writing the
2751 * transformed vertices to @verts[]. */
2753 _clutter_actor_transform_and_project_box (ClutterActor *self,
2754 const ClutterActorBox *box,
2755 ClutterVertex verts[])
2757 ClutterVertex box_vertices[4];
2759 box_vertices[0].x = box->x1;
2760 box_vertices[0].y = box->y1;
2761 box_vertices[0].z = 0;
2762 box_vertices[1].x = box->x2;
2763 box_vertices[1].y = box->y1;
2764 box_vertices[1].z = 0;
2765 box_vertices[2].x = box->x1;
2766 box_vertices[2].y = box->y2;
2767 box_vertices[2].z = 0;
2768 box_vertices[3].x = box->x2;
2769 box_vertices[3].y = box->y2;
2770 box_vertices[3].z = 0;
2773 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2777 * clutter_actor_get_allocation_vertices:
2778 * @self: A #ClutterActor
2779 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2780 * against, or %NULL to use the #ClutterStage
2781 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2782 * location for an array of 4 #ClutterVertex in which to store the result
2784 * Calculates the transformed coordinates of the four corners of the
2785 * actor in the plane of @ancestor. The returned vertices relate to
2786 * the #ClutterActorBox coordinates as follows:
2788 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2789 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2790 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2791 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2794 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2795 * this case, the coordinates returned will be the coordinates on
2796 * the stage before the projection is applied. This is different from
2797 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2802 clutter_actor_get_allocation_vertices (ClutterActor *self,
2803 ClutterActor *ancestor,
2804 ClutterVertex verts[])
2806 ClutterActorPrivate *priv;
2807 ClutterActorBox box;
2808 ClutterVertex vertices[4];
2809 CoglMatrix modelview;
2811 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2812 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2814 if (ancestor == NULL)
2815 ancestor = _clutter_actor_get_stage_internal (self);
2817 /* Fallback to a NOP transform if the actor isn't parented under a
2819 if (ancestor == NULL)
2824 /* if the actor needs to be allocated we force a relayout, so that
2825 * we will have valid values to use in the transformations */
2826 if (priv->needs_allocation)
2828 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2830 _clutter_stage_maybe_relayout (stage);
2833 box.x1 = box.y1 = 0;
2834 /* The result isn't really meaningful in this case but at
2835 * least try to do something *vaguely* reasonable... */
2836 clutter_actor_get_size (self, &box.x2, &box.y2);
2840 clutter_actor_get_allocation_box (self, &box);
2842 vertices[0].x = box.x1;
2843 vertices[0].y = box.y1;
2845 vertices[1].x = box.x2;
2846 vertices[1].y = box.y1;
2848 vertices[2].x = box.x1;
2849 vertices[2].y = box.y2;
2851 vertices[3].x = box.x2;
2852 vertices[3].y = box.y2;
2855 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2858 cogl_matrix_transform_points (&modelview,
2860 sizeof (ClutterVertex),
2862 sizeof (ClutterVertex),
2868 * clutter_actor_get_abs_allocation_vertices:
2869 * @self: A #ClutterActor
2870 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2871 * of 4 #ClutterVertex where to store the result.
2873 * Calculates the transformed screen coordinates of the four corners of
2874 * the actor; the returned vertices relate to the #ClutterActorBox
2875 * coordinates as follows:
2877 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2878 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2879 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2880 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2886 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2887 ClutterVertex verts[])
2889 ClutterActorPrivate *priv;
2890 ClutterActorBox actor_space_allocation;
2892 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2896 /* if the actor needs to be allocated we force a relayout, so that
2897 * the actor allocation box will be valid for
2898 * _clutter_actor_transform_and_project_box()
2900 if (priv->needs_allocation)
2902 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2903 /* There's nothing meaningful we can do now */
2907 _clutter_stage_maybe_relayout (stage);
2910 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2911 * own coordinate space... */
2912 actor_space_allocation.x1 = 0;
2913 actor_space_allocation.y1 = 0;
2914 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2915 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2916 _clutter_actor_transform_and_project_box (self,
2917 &actor_space_allocation,
2922 clutter_actor_real_apply_transform (ClutterActor *self,
2925 ClutterActorPrivate *priv = self->priv;
2927 if (!priv->transform_valid)
2929 CoglMatrix *transform = &priv->transform;
2930 const ClutterTransformInfo *info;
2932 info = _clutter_actor_get_transform_info_or_defaults (self);
2934 cogl_matrix_init_identity (transform);
2936 cogl_matrix_translate (transform,
2937 priv->allocation.x1,
2938 priv->allocation.y1,
2942 cogl_matrix_translate (transform, 0, 0, info->depth);
2945 * because the rotation involves translations, we must scale
2946 * before applying the rotations (if we apply the scale after
2947 * the rotations, the translations included in the rotation are
2948 * not scaled and so the entire object will move on the screen
2949 * as a result of rotating it).
2951 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2953 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2954 &info->scale_center,
2955 cogl_matrix_scale (transform,
2962 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2964 cogl_matrix_rotate (transform,
2969 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2971 cogl_matrix_rotate (transform,
2976 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2978 cogl_matrix_rotate (transform,
2982 if (!clutter_anchor_coord_is_zero (&info->anchor))
2986 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2987 cogl_matrix_translate (transform, -x, -y, -z);
2990 priv->transform_valid = TRUE;
2993 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2996 /* Applies the transforms associated with this actor to the given
2999 _clutter_actor_apply_modelview_transform (ClutterActor *self,
3002 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
3006 * clutter_actor_apply_relative_transformation_matrix:
3007 * @self: The actor whose coordinate space you want to transform from.
3008 * @ancestor: The ancestor actor whose coordinate space you want to transform too
3009 * or %NULL if you want to transform all the way to eye coordinates.
3010 * @matrix: A #CoglMatrix to apply the transformation too.
3012 * This multiplies a transform with @matrix that will transform coordinates
3013 * from the coordinate space of @self into the coordinate space of @ancestor.
3015 * For example if you need a matrix that can transform the local actor
3016 * coordinates of @self into stage coordinates you would pass the actor's stage
3017 * pointer as the @ancestor.
3019 * If you pass %NULL then the transformation will take you all the way through
3020 * to eye coordinates. This can be useful if you want to extract the entire
3021 * modelview transform that Clutter applies before applying the projection
3022 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
3023 * using cogl_set_modelview_matrix() for example then you would want a matrix
3024 * that transforms into eye coordinates.
3026 * <note>This function doesn't initialize the given @matrix, it simply
3027 * multiplies the requested transformation matrix with the existing contents of
3028 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
3029 * before calling this function, or you can use
3030 * clutter_actor_get_relative_transformation_matrix() instead.</note>
3033 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
3034 ClutterActor *ancestor,
3037 ClutterActor *parent;
3039 /* Note we terminate before ever calling stage->apply_transform()
3040 * since that would conceptually be relative to the underlying
3041 * window OpenGL coordinates so we'd need a special @ancestor
3042 * value to represent the fake parent of the stage. */
3043 if (self == ancestor)
3046 parent = clutter_actor_get_parent (self);
3049 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
3052 _clutter_actor_apply_modelview_transform (self, matrix);
3056 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
3057 ClutterPaintVolume *pv,
3059 const CoglColor *color)
3061 static CoglPipeline *outline = NULL;
3062 CoglPrimitive *prim;
3063 ClutterVertex line_ends[12 * 2];
3066 clutter_backend_get_cogl_context (clutter_get_default_backend ());
3067 /* XXX: at some point we'll query this from the stage but we can't
3068 * do that until the osx backend uses Cogl natively. */
3069 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
3071 if (outline == NULL)
3072 outline = cogl_pipeline_new (ctx);
3074 _clutter_paint_volume_complete (pv);
3076 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3079 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3080 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3081 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3082 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3087 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3088 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3089 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3090 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3092 /* Lines connecting front face to back face */
3093 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3094 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3095 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3096 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3099 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3101 (CoglVertexP3 *)line_ends);
3103 cogl_pipeline_set_color (outline, color);
3104 cogl_framebuffer_draw_primitive (fb, outline, prim);
3105 cogl_object_unref (prim);
3109 PangoLayout *layout;
3110 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3111 pango_layout_set_text (layout, label, -1);
3112 cogl_pango_render_layout (layout,
3117 g_object_unref (layout);
3122 _clutter_actor_draw_paint_volume (ClutterActor *self)
3124 ClutterPaintVolume *pv;
3127 pv = _clutter_actor_get_paint_volume_mutable (self);
3130 gfloat width, height;
3131 ClutterPaintVolume fake_pv;
3133 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3134 _clutter_paint_volume_init_static (&fake_pv, stage);
3136 clutter_actor_get_size (self, &width, &height);
3137 clutter_paint_volume_set_width (&fake_pv, width);
3138 clutter_paint_volume_set_height (&fake_pv, height);
3140 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3141 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3142 _clutter_actor_get_debug_name (self),
3145 clutter_paint_volume_free (&fake_pv);
3149 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3150 _clutter_actor_draw_paint_volume_full (self, pv,
3151 _clutter_actor_get_debug_name (self),
3157 _clutter_actor_paint_cull_result (ClutterActor *self,
3159 ClutterCullResult result)
3161 ClutterPaintVolume *pv;
3166 if (result == CLUTTER_CULL_RESULT_IN)
3167 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3168 else if (result == CLUTTER_CULL_RESULT_OUT)
3169 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3171 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3174 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3176 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3177 _clutter_actor_draw_paint_volume_full (self, pv,
3178 _clutter_actor_get_debug_name (self),
3182 PangoLayout *layout;
3184 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3185 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3186 cogl_set_source_color (&color);
3188 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3189 pango_layout_set_text (layout, label, -1);
3190 cogl_pango_render_layout (layout,
3196 g_object_unref (layout);
3200 static int clone_paint_level = 0;
3203 _clutter_actor_push_clone_paint (void)
3205 clone_paint_level++;
3209 _clutter_actor_pop_clone_paint (void)
3211 clone_paint_level--;
3215 in_clone_paint (void)
3217 return clone_paint_level > 0;
3220 /* Returns TRUE if the actor can be ignored */
3221 /* FIXME: we should return a ClutterCullResult, and
3222 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3223 * means there's no point in trying to cull descendants of the current
3226 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3228 ClutterActorPrivate *priv = self->priv;
3229 ClutterActor *stage;
3230 const ClutterPlane *stage_clip;
3232 if (!priv->last_paint_volume_valid)
3234 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3235 "->last_paint_volume_valid == FALSE",
3236 _clutter_actor_get_debug_name (self));
3240 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3243 stage = _clutter_actor_get_stage_internal (self);
3244 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3245 if (G_UNLIKELY (!stage_clip))
3247 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3248 "No stage clip set",
3249 _clutter_actor_get_debug_name (self));
3253 if (cogl_get_draw_framebuffer () !=
3254 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3256 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3257 "Current framebuffer doesn't correspond to stage",
3258 _clutter_actor_get_debug_name (self));
3263 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3268 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3270 ClutterActorPrivate *priv = self->priv;
3271 const ClutterPaintVolume *pv;
3273 if (priv->last_paint_volume_valid)
3275 clutter_paint_volume_free (&priv->last_paint_volume);
3276 priv->last_paint_volume_valid = FALSE;
3279 pv = clutter_actor_get_paint_volume (self);
3282 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3283 "Actor failed to report a paint volume",
3284 _clutter_actor_get_debug_name (self));
3288 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3290 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3291 NULL); /* eye coordinates */
3293 priv->last_paint_volume_valid = TRUE;
3296 static inline gboolean
3297 actor_has_shader_data (ClutterActor *self)
3299 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3303 _clutter_actor_get_pick_id (ClutterActor *self)
3305 if (self->priv->pick_id < 0)
3308 return self->priv->pick_id;
3311 /* This is the same as clutter_actor_add_effect except that it doesn't
3312 queue a redraw and it doesn't notify on the effect property */
3314 _clutter_actor_add_effect_internal (ClutterActor *self,
3315 ClutterEffect *effect)
3317 ClutterActorPrivate *priv = self->priv;
3319 if (priv->effects == NULL)
3321 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3322 priv->effects->actor = self;
3325 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3328 /* This is the same as clutter_actor_remove_effect except that it doesn't
3329 queue a redraw and it doesn't notify on the effect property */
3331 _clutter_actor_remove_effect_internal (ClutterActor *self,
3332 ClutterEffect *effect)
3334 ClutterActorPrivate *priv = self->priv;
3336 if (priv->effects == NULL)
3339 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3341 if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3342 g_clear_object (&priv->effects);
3346 needs_flatten_effect (ClutterActor *self)
3348 ClutterActorPrivate *priv = self->priv;
3350 if (G_UNLIKELY (clutter_paint_debug_flags &
3351 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3354 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3356 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3358 if (clutter_actor_get_paint_opacity (self) < 255 &&
3359 clutter_actor_has_overlaps (self))
3367 add_or_remove_flatten_effect (ClutterActor *self)
3369 ClutterActorPrivate *priv = self->priv;
3371 /* Add or remove the flatten effect depending on the
3372 offscreen-redirect property. */
3373 if (needs_flatten_effect (self))
3375 if (priv->flatten_effect == NULL)
3377 ClutterActorMeta *actor_meta;
3380 priv->flatten_effect = _clutter_flatten_effect_new ();
3381 /* Keep a reference to the effect so that we can queue
3383 g_object_ref_sink (priv->flatten_effect);
3385 /* Set the priority of the effect to high so that it will
3386 always be applied to the actor first. It uses an internal
3387 priority so that it won't be visible to applications */
3388 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3389 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3390 _clutter_actor_meta_set_priority (actor_meta, priority);
3392 /* This will add the effect without queueing a redraw */
3393 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3398 if (priv->flatten_effect != NULL)
3400 /* Destroy the effect so that it will lose its fbo cache of
3402 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3403 g_clear_object (&priv->flatten_effect);
3409 clutter_actor_real_paint (ClutterActor *actor)
3411 ClutterActorPrivate *priv = actor->priv;
3414 for (iter = priv->first_child;
3416 iter = iter->priv->next_sibling)
3418 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3419 _clutter_actor_get_debug_name (iter),
3420 _clutter_actor_get_debug_name (actor),
3421 iter->priv->allocation.x1,
3422 iter->priv->allocation.y1,
3423 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3424 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3426 clutter_actor_paint (iter);
3431 clutter_actor_paint_node (ClutterActor *actor,
3432 ClutterPaintNode *root)
3434 ClutterActorPrivate *priv = actor->priv;
3439 if (priv->bg_color_set &&
3440 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3442 ClutterPaintNode *node;
3443 ClutterColor bg_color;
3444 ClutterActorBox box;
3448 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3449 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3451 bg_color = priv->bg_color;
3452 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3453 * priv->bg_color.alpha
3456 node = clutter_color_node_new (&bg_color);
3457 clutter_paint_node_set_name (node, "backgroundColor");
3458 clutter_paint_node_add_rectangle (node, &box);
3459 clutter_paint_node_add_child (root, node);
3460 clutter_paint_node_unref (node);
3463 if (priv->content != NULL)
3464 _clutter_content_paint_content (priv->content, actor, root);
3466 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3467 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3469 if (clutter_paint_node_get_n_children (root) == 0)
3472 #ifdef CLUTTER_ENABLE_DEBUG
3473 if (CLUTTER_HAS_DEBUG (PAINT))
3475 /* dump the tree only if we have one */
3476 _clutter_paint_node_dump_tree (root);
3478 #endif /* CLUTTER_ENABLE_DEBUG */
3480 _clutter_paint_node_paint (root);
3483 /* XXX: Uncomment this when we disable emitting the paint signal */
3484 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3491 * clutter_actor_paint:
3492 * @self: A #ClutterActor
3494 * Renders the actor to display.
3496 * This function should not be called directly by applications.
3497 * Call clutter_actor_queue_redraw() to queue paints, instead.
3499 * This function is context-aware, and will either cause a
3500 * regular paint or a pick paint.
3502 * This function will emit the #ClutterActor::paint signal or
3503 * the #ClutterActor::pick signal, depending on the context.
3505 * This function does not paint the actor if the actor is set to 0,
3506 * unless it is performing a pick paint.
3509 clutter_actor_paint (ClutterActor *self)
3511 ClutterActorPrivate *priv;
3512 ClutterPickMode pick_mode;
3513 gboolean clip_set = FALSE;
3514 gboolean shader_applied = FALSE;
3516 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3517 "Actor real-paint counter",
3518 "Increments each time any actor is painted",
3519 0 /* no application private data */);
3520 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3521 "Actor pick-paint counter",
3522 "Increments each time any actor is painted "
3524 0 /* no application private data */);
3526 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3528 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3533 pick_mode = _clutter_context_get_pick_mode ();
3535 if (pick_mode == CLUTTER_PICK_NONE)
3536 priv->propagated_one_redraw = FALSE;
3538 /* It's an important optimization that we consider painting of
3539 * actors with 0 opacity to be a NOP... */
3540 if (pick_mode == CLUTTER_PICK_NONE &&
3541 /* ignore top-levels, since they might be transparent */
3542 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3543 /* Use the override opacity if its been set */
3544 ((priv->opacity_override >= 0) ?
3545 priv->opacity_override : priv->opacity) == 0)
3548 /* if we aren't paintable (not in a toplevel with all
3549 * parents paintable) then do nothing.
3551 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3554 /* mark that we are in the paint process */
3555 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3559 if (priv->enable_model_view_transform)
3563 /* XXX: It could be better to cache the modelview with the actor
3564 * instead of progressively building up the transformations on
3565 * the matrix stack every time we paint. */
3566 cogl_get_modelview_matrix (&matrix);
3567 _clutter_actor_apply_modelview_transform (self, &matrix);
3569 #ifdef CLUTTER_ENABLE_DEBUG
3570 /* Catch when out-of-band transforms have been made by actors not as part
3571 * of an apply_transform vfunc... */
3572 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3574 CoglMatrix expected_matrix;
3576 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3579 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3581 GString *buf = g_string_sized_new (1024);
3582 ClutterActor *parent;
3585 while (parent != NULL)
3587 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3589 if (parent->priv->parent != NULL)
3590 g_string_append (buf, "->");
3592 parent = parent->priv->parent;
3595 g_warning ("Unexpected transform found when painting actor "
3596 "\"%s\". This will be caused by one of the actor's "
3597 "ancestors (%s) using the Cogl API directly to transform "
3598 "children instead of using ::apply_transform().",
3599 _clutter_actor_get_debug_name (self),
3602 g_string_free (buf, TRUE);
3605 #endif /* CLUTTER_ENABLE_DEBUG */
3607 cogl_set_modelview_matrix (&matrix);
3612 cogl_clip_push_rectangle (priv->clip.x,
3614 priv->clip.x + priv->clip.width,
3615 priv->clip.y + priv->clip.height);
3618 else if (priv->clip_to_allocation)
3620 gfloat width, height;
3622 width = priv->allocation.x2 - priv->allocation.x1;
3623 height = priv->allocation.y2 - priv->allocation.y1;
3625 cogl_clip_push_rectangle (0, 0, width, height);
3629 if (pick_mode == CLUTTER_PICK_NONE)
3631 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3633 /* We check whether we need to add the flatten effect before
3634 each paint so that we can avoid having a mechanism for
3635 applications to notify when the value of the
3636 has_overlaps virtual changes. */
3637 add_or_remove_flatten_effect (self);
3640 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3642 /* We save the current paint volume so that the next time the
3643 * actor queues a redraw we can constrain the redraw to just
3644 * cover the union of the new bounding box and the old.
3646 * We also fetch the current paint volume to perform culling so
3647 * we can avoid painting actors outside the current clip region.
3649 * If we are painting inside a clone, we should neither update
3650 * the paint volume or use it to cull painting, since the paint
3651 * box represents the location of the source actor on the
3654 * XXX: We are starting to do a lot of vertex transforms on
3655 * the CPU in a typical paint, so at some point we should
3656 * audit these and consider caching some things.
3658 * NB: We don't perform culling while picking at this point because
3659 * clutter-stage.c doesn't setup the clipping planes appropriately.
3661 * NB: We don't want to update the last-paint-volume during picking
3662 * because the last-paint-volume is used to determine the old screen
3663 * space location of an actor that has moved so we can know the
3664 * minimal region to redraw to clear an old view of the actor. If we
3665 * update this during picking then by the time we come around to
3666 * paint then the last-paint-volume would likely represent the new
3667 * actor position not the old.
3669 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3672 /* annoyingly gcc warns if uninitialized even though
3673 * the initialization is redundant :-( */
3674 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3676 if (G_LIKELY ((clutter_paint_debug_flags &
3677 (CLUTTER_DEBUG_DISABLE_CULLING |
3678 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3679 (CLUTTER_DEBUG_DISABLE_CULLING |
3680 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3681 _clutter_actor_update_last_paint_volume (self);
3683 success = cull_actor (self, &result);
3685 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3686 _clutter_actor_paint_cull_result (self, success, result);
3687 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3691 if (priv->effects == NULL)
3693 if (pick_mode == CLUTTER_PICK_NONE &&
3694 actor_has_shader_data (self))
3696 _clutter_actor_shader_pre_paint (self, FALSE);
3697 shader_applied = TRUE;
3700 priv->next_effect_to_paint = NULL;
3703 priv->next_effect_to_paint =
3704 _clutter_meta_group_peek_metas (priv->effects);
3706 clutter_actor_continue_paint (self);
3709 _clutter_actor_shader_post_paint (self);
3711 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3712 pick_mode == CLUTTER_PICK_NONE))
3713 _clutter_actor_draw_paint_volume (self);
3716 /* If we make it here then the actor has run through a complete
3717 paint run including all the effects so it's no longer dirty */
3718 if (pick_mode == CLUTTER_PICK_NONE)
3719 priv->is_dirty = FALSE;
3726 /* paint sequence complete */
3727 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3731 * clutter_actor_continue_paint:
3732 * @self: A #ClutterActor
3734 * Run the next stage of the paint sequence. This function should only
3735 * be called within the implementation of the ‘run’ virtual of a
3736 * #ClutterEffect. It will cause the run method of the next effect to
3737 * be applied, or it will paint the actual actor if the current effect
3738 * is the last effect in the chain.
3743 clutter_actor_continue_paint (ClutterActor *self)
3745 ClutterActorPrivate *priv;
3747 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3748 /* This should only be called from with in the ‘run’ implementation
3749 of a ClutterEffect */
3750 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3754 /* Skip any effects that are disabled */
3755 while (priv->next_effect_to_paint &&
3756 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3757 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3759 /* If this has come from the last effect then we'll just paint the
3761 if (priv->next_effect_to_paint == NULL)
3763 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3765 ClutterPaintNode *dummy;
3767 /* XXX - this will go away in 2.0, when we can get rid of this
3768 * stuff and switch to a pure retained render tree of PaintNodes
3769 * for the entire frame, starting from the Stage; the paint()
3770 * virtual function can then be called directly.
3772 dummy = _clutter_dummy_node_new (self);
3773 clutter_paint_node_set_name (dummy, "Root");
3775 /* XXX - for 1.12, we use the return value of paint_node() to
3776 * decide whether we should emit the ::paint signal.
3778 clutter_actor_paint_node (self, dummy);
3779 clutter_paint_node_unref (dummy);
3781 g_signal_emit (self, actor_signals[PAINT], 0);
3785 ClutterColor col = { 0, };
3787 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3789 /* Actor will then paint silhouette of itself in supplied
3790 * color. See clutter_stage_get_actor_at_pos() for where
3791 * picking is enabled.
3793 g_signal_emit (self, actor_signals[PICK], 0, &col);
3798 ClutterEffect *old_current_effect;
3799 ClutterEffectPaintFlags run_flags = 0;
3801 /* Cache the current effect so that we can put it back before
3803 old_current_effect = priv->current_effect;
3805 priv->current_effect = priv->next_effect_to_paint->data;
3806 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3808 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3812 /* If there's an effect queued with this redraw then all
3813 effects up to that one will be considered dirty. It
3814 is expected the queued effect will paint the cached
3815 image and not call clutter_actor_continue_paint again
3816 (although it should work ok if it does) */
3817 if (priv->effect_to_redraw == NULL ||
3818 priv->current_effect != priv->effect_to_redraw)
3819 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3822 _clutter_effect_paint (priv->current_effect, run_flags);
3826 /* We can't determine when an actor has been modified since
3827 its last pick so lets just assume it has always been
3829 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3831 _clutter_effect_pick (priv->current_effect, run_flags);
3834 priv->current_effect = old_current_effect;
3839 _clutter_actor_stop_transitions (ClutterActor *self)
3841 const ClutterAnimationInfo *info;
3842 GHashTableIter iter;
3845 info = _clutter_actor_get_animation_info_or_defaults (self);
3846 if (info->transitions == NULL)
3849 g_hash_table_iter_init (&iter, info->transitions);
3850 while (g_hash_table_iter_next (&iter, NULL, &value))
3852 TransitionClosure *closure = value;
3853 clutter_timeline_stop (CLUTTER_TIMELINE (closure->transition));
3857 static ClutterActorTraverseVisitFlags
3858 invalidate_queue_redraw_entry (ClutterActor *self,
3862 ClutterActorPrivate *priv = self->priv;
3864 if (priv->queue_redraw_entry != NULL)
3866 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3867 priv->queue_redraw_entry = NULL;
3870 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3874 remove_child (ClutterActor *self,
3875 ClutterActor *child)
3877 ClutterActor *prev_sibling, *next_sibling;
3879 prev_sibling = child->priv->prev_sibling;
3880 next_sibling = child->priv->next_sibling;
3882 if (prev_sibling != NULL)
3883 prev_sibling->priv->next_sibling = next_sibling;
3885 if (next_sibling != NULL)
3886 next_sibling->priv->prev_sibling = prev_sibling;
3888 if (self->priv->first_child == child)
3889 self->priv->first_child = next_sibling;
3891 if (self->priv->last_child == child)
3892 self->priv->last_child = prev_sibling;
3894 child->priv->parent = NULL;
3895 child->priv->prev_sibling = NULL;
3896 child->priv->next_sibling = NULL;
3900 REMOVE_CHILD_DESTROY_META = 1 << 0,
3901 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3902 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3903 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3904 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3905 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3906 REMOVE_CHILD_STOP_TRANSITIONS = 1 << 6,
3908 /* default flags for public API */
3909 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_STOP_TRANSITIONS |
3910 REMOVE_CHILD_DESTROY_META |
3911 REMOVE_CHILD_EMIT_PARENT_SET |
3912 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3913 REMOVE_CHILD_CHECK_STATE |
3914 REMOVE_CHILD_FLUSH_QUEUE |
3915 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3917 /* flags for legacy/deprecated API */
3918 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_STOP_TRANSITIONS |
3919 REMOVE_CHILD_CHECK_STATE |
3920 REMOVE_CHILD_FLUSH_QUEUE |
3921 REMOVE_CHILD_EMIT_PARENT_SET |
3922 REMOVE_CHILD_NOTIFY_FIRST_LAST
3923 } ClutterActorRemoveChildFlags;
3926 * clutter_actor_remove_child_internal:
3927 * @self: a #ClutterActor
3928 * @child: the child of @self that has to be removed
3929 * @flags: control the removal operations
3931 * Removes @child from the list of children of @self.
3934 clutter_actor_remove_child_internal (ClutterActor *self,
3935 ClutterActor *child,
3936 ClutterActorRemoveChildFlags flags)
3938 ClutterActor *old_first, *old_last;
3939 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3940 gboolean flush_queue;
3941 gboolean notify_first_last;
3942 gboolean was_mapped;
3943 gboolean stop_transitions;
3945 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3946 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3947 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3948 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3949 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3950 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3951 stop_transitions = (flags & REMOVE_CHILD_STOP_TRANSITIONS) != 0;
3953 g_object_freeze_notify (G_OBJECT (self));
3955 if (stop_transitions)
3956 _clutter_actor_stop_transitions (child);
3959 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3963 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3965 /* we need to unrealize *before* we set parent_actor to NULL,
3966 * because in an unrealize method actors are dissociating from the
3967 * stage, which means they need to be able to
3968 * clutter_actor_get_stage().
3970 * yhis should unmap and unrealize, unless we're reparenting.
3972 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3979 /* We take this opportunity to invalidate any queue redraw entry
3980 * associated with the actor and descendants since we won't be able to
3981 * determine the appropriate stage after this.
3983 * we do this after we updated the mapped state because actors might
3984 * end up queueing redraws inside their mapped/unmapped virtual
3985 * functions, and if we invalidate the redraw entry we could end up
3986 * with an inconsistent state and weird memory corruption. see
3989 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3990 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3992 _clutter_actor_traverse (child,
3994 invalidate_queue_redraw_entry,
3999 old_first = self->priv->first_child;
4000 old_last = self->priv->last_child;
4002 remove_child (self, child);
4004 self->priv->n_children -= 1;
4006 self->priv->age += 1;
4008 /* if the child that got removed was visible and set to
4009 * expand then we want to reset the parent's state in
4010 * case the child was the only thing that was making it
4013 if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
4014 (child->priv->needs_compute_expand ||
4015 child->priv->needs_x_expand ||
4016 child->priv->needs_y_expand))
4018 clutter_actor_queue_compute_expand (self);
4021 /* clutter_actor_reparent() will emit ::parent-set for us */
4022 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
4023 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
4025 /* if the child was mapped then we need to relayout ourselves to account
4026 * for the removed child
4029 clutter_actor_queue_relayout (self);
4031 /* we need to emit the signal before dropping the reference */
4032 if (emit_actor_removed)
4033 g_signal_emit_by_name (self, "actor-removed", child);
4035 if (notify_first_last)
4037 if (old_first != self->priv->first_child)
4038 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
4040 if (old_last != self->priv->last_child)
4041 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
4044 g_object_thaw_notify (G_OBJECT (self));
4046 /* remove the reference we acquired in clutter_actor_add_child() */
4047 g_object_unref (child);
4050 static const ClutterTransformInfo default_transform_info = {
4051 0.0, { 0, }, /* rotation-x */
4052 0.0, { 0, }, /* rotation-y */
4053 0.0, { 0, }, /* rotation-z */
4055 1.0, 1.0, { 0, }, /* scale */
4057 { 0, }, /* anchor */
4063 * _clutter_actor_get_transform_info_or_defaults:
4064 * @self: a #ClutterActor
4066 * Retrieves the ClutterTransformInfo structure associated to an actor.
4068 * If the actor does not have a ClutterTransformInfo structure associated
4069 * to it, then the default structure will be returned.
4071 * This function should only be used for getters.
4073 * Return value: a const pointer to the ClutterTransformInfo structure
4075 const ClutterTransformInfo *
4076 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
4078 ClutterTransformInfo *info;
4080 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4084 return &default_transform_info;
4088 clutter_transform_info_free (gpointer data)
4091 g_slice_free (ClutterTransformInfo, data);
4095 * _clutter_actor_get_transform_info:
4096 * @self: a #ClutterActor
4098 * Retrieves a pointer to the ClutterTransformInfo structure.
4100 * If the actor does not have a ClutterTransformInfo associated to it, one
4101 * will be created and initialized to the default values.
4103 * This function should be used for setters.
4105 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
4108 * Return value: (transfer none): a pointer to the ClutterTransformInfo
4111 ClutterTransformInfo *
4112 _clutter_actor_get_transform_info (ClutterActor *self)
4114 ClutterTransformInfo *info;
4116 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4119 info = g_slice_new (ClutterTransformInfo);
4121 *info = default_transform_info;
4123 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4125 clutter_transform_info_free);
4132 * clutter_actor_set_rotation_angle_internal:
4133 * @self: a #ClutterActor
4134 * @axis: the axis of the angle to change
4135 * @angle: the angle of rotation
4137 * Sets the rotation angle on the given axis without affecting the
4138 * rotation center point.
4141 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
4142 ClutterRotateAxis axis,
4145 GObject *obj = G_OBJECT (self);
4146 ClutterTransformInfo *info;
4148 info = _clutter_actor_get_transform_info (self);
4150 g_object_freeze_notify (obj);
4154 case CLUTTER_X_AXIS:
4155 info->rx_angle = angle;
4156 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4159 case CLUTTER_Y_AXIS:
4160 info->ry_angle = angle;
4161 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4164 case CLUTTER_Z_AXIS:
4165 info->rz_angle = angle;
4166 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4170 self->priv->transform_valid = FALSE;
4172 g_object_thaw_notify (obj);
4174 clutter_actor_queue_redraw (self);
4178 clutter_actor_set_rotation_angle (ClutterActor *self,
4179 ClutterRotateAxis axis,
4182 const ClutterTransformInfo *info;
4183 const double *cur_angle_p = NULL;
4184 GParamSpec *pspec = NULL;
4186 info = _clutter_actor_get_transform_info_or_defaults (self);
4190 case CLUTTER_X_AXIS:
4191 cur_angle_p = &info->rx_angle;
4192 pspec = obj_props[PROP_ROTATION_ANGLE_X];
4195 case CLUTTER_Y_AXIS:
4196 cur_angle_p = &info->ry_angle;
4197 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4200 case CLUTTER_Z_AXIS:
4201 cur_angle_p = &info->rz_angle;
4202 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4206 g_assert (pspec != NULL);
4207 g_assert (cur_angle_p != NULL);
4209 if (_clutter_actor_get_transition (self, pspec) == NULL)
4210 _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4212 _clutter_actor_update_transition (self, pspec, angle);
4214 clutter_actor_queue_redraw (self);
4218 * clutter_actor_set_rotation_center_internal:
4219 * @self: a #ClutterActor
4220 * @axis: the axis of the center to change
4221 * @center: the coordinates of the rotation center
4223 * Sets the rotation center on the given axis without affecting the
4227 clutter_actor_set_rotation_center_internal (ClutterActor *self,
4228 ClutterRotateAxis axis,
4229 const ClutterVertex *center)
4231 GObject *obj = G_OBJECT (self);
4232 ClutterTransformInfo *info;
4233 ClutterVertex v = { 0, 0, 0 };
4235 info = _clutter_actor_get_transform_info (self);
4240 g_object_freeze_notify (obj);
4244 case CLUTTER_X_AXIS:
4245 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4246 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4249 case CLUTTER_Y_AXIS:
4250 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4251 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4254 case CLUTTER_Z_AXIS:
4255 /* if the previously set rotation center was fractional, then
4256 * setting explicit coordinates will have to notify the
4257 * :rotation-center-z-gravity property as well
4259 if (info->rz_center.is_fractional)
4260 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4262 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4263 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4267 self->priv->transform_valid = FALSE;
4269 g_object_thaw_notify (obj);
4271 clutter_actor_queue_redraw (self);
4275 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4279 GObject *obj = G_OBJECT (self);
4280 ClutterTransformInfo *info;
4282 info = _clutter_actor_get_transform_info (self);
4284 if (pspec == obj_props[PROP_SCALE_X])
4285 info->scale_x = factor;
4287 info->scale_y = factor;
4289 self->priv->transform_valid = FALSE;
4290 clutter_actor_queue_redraw (self);
4291 g_object_notify_by_pspec (obj, pspec);
4295 clutter_actor_set_scale_factor (ClutterActor *self,
4296 ClutterRotateAxis axis,
4299 const ClutterTransformInfo *info;
4300 const double *scale_p = NULL;
4301 GParamSpec *pspec = NULL;
4303 info = _clutter_actor_get_transform_info_or_defaults (self);
4307 case CLUTTER_X_AXIS:
4308 pspec = obj_props[PROP_SCALE_X];
4309 scale_p = &info->scale_x;
4312 case CLUTTER_Y_AXIS:
4313 pspec = obj_props[PROP_SCALE_Y];
4314 scale_p = &info->scale_y;
4317 case CLUTTER_Z_AXIS:
4321 g_assert (pspec != NULL);
4322 g_assert (scale_p != NULL);
4324 if (_clutter_actor_get_transition (self, pspec) == NULL)
4325 _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4327 _clutter_actor_update_transition (self, pspec, factor);
4329 clutter_actor_queue_redraw (self);
4333 clutter_actor_set_scale_center (ClutterActor *self,
4334 ClutterRotateAxis axis,
4337 GObject *obj = G_OBJECT (self);
4338 ClutterTransformInfo *info;
4339 gfloat center_x, center_y;
4341 info = _clutter_actor_get_transform_info (self);
4343 g_object_freeze_notify (obj);
4345 /* get the current scale center coordinates */
4346 clutter_anchor_coord_get_units (self, &info->scale_center,
4351 /* we need to notify this too, because setting explicit coordinates will
4352 * change the gravity as a side effect
4354 if (info->scale_center.is_fractional)
4355 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4359 case CLUTTER_X_AXIS:
4360 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4361 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4364 case CLUTTER_Y_AXIS:
4365 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4366 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4370 g_assert_not_reached ();
4373 self->priv->transform_valid = FALSE;
4375 clutter_actor_queue_redraw (self);
4377 g_object_thaw_notify (obj);
4381 clutter_actor_set_scale_gravity (ClutterActor *self,
4382 ClutterGravity gravity)
4384 ClutterTransformInfo *info;
4387 info = _clutter_actor_get_transform_info (self);
4388 obj = G_OBJECT (self);
4390 if (gravity == CLUTTER_GRAVITY_NONE)
4391 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4393 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4395 self->priv->transform_valid = FALSE;
4397 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4398 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4399 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4401 clutter_actor_queue_redraw (self);
4405 clutter_actor_set_anchor_coord (ClutterActor *self,
4406 ClutterRotateAxis axis,
4409 GObject *obj = G_OBJECT (self);
4410 ClutterTransformInfo *info;
4411 gfloat anchor_x, anchor_y;
4413 info = _clutter_actor_get_transform_info (self);
4415 g_object_freeze_notify (obj);
4417 clutter_anchor_coord_get_units (self, &info->anchor,
4422 if (info->anchor.is_fractional)
4423 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4427 case CLUTTER_X_AXIS:
4428 clutter_anchor_coord_set_units (&info->anchor,
4432 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4435 case CLUTTER_Y_AXIS:
4436 clutter_anchor_coord_set_units (&info->anchor,
4440 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4444 g_assert_not_reached ();
4447 self->priv->transform_valid = FALSE;
4449 clutter_actor_queue_redraw (self);
4451 g_object_thaw_notify (obj);
4455 clutter_actor_set_property (GObject *object,
4457 const GValue *value,
4460 ClutterActor *actor = CLUTTER_ACTOR (object);
4461 ClutterActorPrivate *priv = actor->priv;
4466 clutter_actor_set_x (actor, g_value_get_float (value));
4470 clutter_actor_set_y (actor, g_value_get_float (value));
4475 const ClutterPoint *pos = g_value_get_boxed (value);
4478 clutter_actor_set_position (actor, pos->x, pos->y);
4480 clutter_actor_set_fixed_position_set (actor, FALSE);
4485 clutter_actor_set_width (actor, g_value_get_float (value));
4489 clutter_actor_set_height (actor, g_value_get_float (value));
4494 const ClutterSize *size = g_value_get_boxed (value);
4497 clutter_actor_set_size (actor, size->width, size->height);
4499 clutter_actor_set_size (actor, -1, -1);
4504 clutter_actor_set_x (actor, g_value_get_float (value));
4508 clutter_actor_set_y (actor, g_value_get_float (value));
4511 case PROP_FIXED_POSITION_SET:
4512 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4515 case PROP_MIN_WIDTH:
4516 clutter_actor_set_min_width (actor, g_value_get_float (value));
4519 case PROP_MIN_HEIGHT:
4520 clutter_actor_set_min_height (actor, g_value_get_float (value));
4523 case PROP_NATURAL_WIDTH:
4524 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4527 case PROP_NATURAL_HEIGHT:
4528 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4531 case PROP_MIN_WIDTH_SET:
4532 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4535 case PROP_MIN_HEIGHT_SET:
4536 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4539 case PROP_NATURAL_WIDTH_SET:
4540 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4543 case PROP_NATURAL_HEIGHT_SET:
4544 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4547 case PROP_REQUEST_MODE:
4548 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4552 clutter_actor_set_depth (actor, g_value_get_float (value));
4556 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4559 case PROP_OFFSCREEN_REDIRECT:
4560 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4564 clutter_actor_set_name (actor, g_value_get_string (value));
4568 if (g_value_get_boolean (value) == TRUE)
4569 clutter_actor_show (actor);
4571 clutter_actor_hide (actor);
4575 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4576 g_value_get_double (value));
4580 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4581 g_value_get_double (value));
4584 case PROP_SCALE_CENTER_X:
4585 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4586 g_value_get_float (value));
4589 case PROP_SCALE_CENTER_Y:
4590 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4591 g_value_get_float (value));
4594 case PROP_SCALE_GRAVITY:
4595 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4600 const ClutterGeometry *geom = g_value_get_boxed (value);
4602 clutter_actor_set_clip (actor,
4604 geom->width, geom->height);
4608 case PROP_CLIP_TO_ALLOCATION:
4609 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4613 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4616 case PROP_ROTATION_ANGLE_X:
4617 clutter_actor_set_rotation_angle (actor,
4619 g_value_get_double (value));
4622 case PROP_ROTATION_ANGLE_Y:
4623 clutter_actor_set_rotation_angle (actor,
4625 g_value_get_double (value));
4628 case PROP_ROTATION_ANGLE_Z:
4629 clutter_actor_set_rotation_angle (actor,
4631 g_value_get_double (value));
4634 case PROP_ROTATION_CENTER_X:
4635 clutter_actor_set_rotation_center_internal (actor,
4637 g_value_get_boxed (value));
4640 case PROP_ROTATION_CENTER_Y:
4641 clutter_actor_set_rotation_center_internal (actor,
4643 g_value_get_boxed (value));
4646 case PROP_ROTATION_CENTER_Z:
4647 clutter_actor_set_rotation_center_internal (actor,
4649 g_value_get_boxed (value));
4652 case PROP_ROTATION_CENTER_Z_GRAVITY:
4654 const ClutterTransformInfo *info;
4656 info = _clutter_actor_get_transform_info_or_defaults (actor);
4657 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4658 g_value_get_enum (value));
4663 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4664 g_value_get_float (value));
4668 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4669 g_value_get_float (value));
4672 case PROP_ANCHOR_GRAVITY:
4673 clutter_actor_set_anchor_point_from_gravity (actor,
4674 g_value_get_enum (value));
4677 case PROP_SHOW_ON_SET_PARENT:
4678 priv->show_on_set_parent = g_value_get_boolean (value);
4681 case PROP_TEXT_DIRECTION:
4682 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4686 clutter_actor_add_action (actor, g_value_get_object (value));
4689 case PROP_CONSTRAINTS:
4690 clutter_actor_add_constraint (actor, g_value_get_object (value));
4694 clutter_actor_add_effect (actor, g_value_get_object (value));
4697 case PROP_LAYOUT_MANAGER:
4698 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4702 clutter_actor_set_x_expand (actor, g_value_get_boolean (value));
4706 clutter_actor_set_y_expand (actor, g_value_get_boolean (value));
4710 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4714 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4717 case PROP_MARGIN_TOP:
4718 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4721 case PROP_MARGIN_BOTTOM:
4722 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4725 case PROP_MARGIN_LEFT:
4726 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4729 case PROP_MARGIN_RIGHT:
4730 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4733 case PROP_BACKGROUND_COLOR:
4734 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4738 clutter_actor_set_content (actor, g_value_get_object (value));
4741 case PROP_CONTENT_GRAVITY:
4742 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4745 case PROP_MINIFICATION_FILTER:
4746 clutter_actor_set_content_scaling_filters (actor,
4747 g_value_get_enum (value),
4748 actor->priv->mag_filter);
4751 case PROP_MAGNIFICATION_FILTER:
4752 clutter_actor_set_content_scaling_filters (actor,
4753 actor->priv->min_filter,
4754 g_value_get_enum (value));
4758 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4764 clutter_actor_get_property (GObject *object,
4769 ClutterActor *actor = CLUTTER_ACTOR (object);
4770 ClutterActorPrivate *priv = actor->priv;
4775 g_value_set_float (value, clutter_actor_get_x (actor));
4779 g_value_set_float (value, clutter_actor_get_y (actor));
4784 ClutterPoint position;
4786 clutter_point_init (&position,
4787 clutter_actor_get_x (actor),
4788 clutter_actor_get_y (actor));
4789 g_value_set_boxed (value, &position);
4794 g_value_set_float (value, clutter_actor_get_width (actor));
4798 g_value_set_float (value, clutter_actor_get_height (actor));
4805 clutter_size_init (&size,
4806 clutter_actor_get_width (actor),
4807 clutter_actor_get_height (actor));
4808 g_value_set_boxed (value, &size);
4814 const ClutterLayoutInfo *info;
4816 info = _clutter_actor_get_layout_info_or_defaults (actor);
4817 g_value_set_float (value, info->fixed_pos.x);
4823 const ClutterLayoutInfo *info;
4825 info = _clutter_actor_get_layout_info_or_defaults (actor);
4826 g_value_set_float (value, info->fixed_pos.y);
4830 case PROP_FIXED_POSITION_SET:
4831 g_value_set_boolean (value, priv->position_set);
4834 case PROP_MIN_WIDTH:
4836 const ClutterLayoutInfo *info;
4838 info = _clutter_actor_get_layout_info_or_defaults (actor);
4839 g_value_set_float (value, info->minimum.width);
4843 case PROP_MIN_HEIGHT:
4845 const ClutterLayoutInfo *info;
4847 info = _clutter_actor_get_layout_info_or_defaults (actor);
4848 g_value_set_float (value, info->minimum.height);
4852 case PROP_NATURAL_WIDTH:
4854 const ClutterLayoutInfo *info;
4856 info = _clutter_actor_get_layout_info_or_defaults (actor);
4857 g_value_set_float (value, info->natural.width);
4861 case PROP_NATURAL_HEIGHT:
4863 const ClutterLayoutInfo *info;
4865 info = _clutter_actor_get_layout_info_or_defaults (actor);
4866 g_value_set_float (value, info->natural.height);
4870 case PROP_MIN_WIDTH_SET:
4871 g_value_set_boolean (value, priv->min_width_set);
4874 case PROP_MIN_HEIGHT_SET:
4875 g_value_set_boolean (value, priv->min_height_set);
4878 case PROP_NATURAL_WIDTH_SET:
4879 g_value_set_boolean (value, priv->natural_width_set);
4882 case PROP_NATURAL_HEIGHT_SET:
4883 g_value_set_boolean (value, priv->natural_height_set);
4886 case PROP_REQUEST_MODE:
4887 g_value_set_enum (value, priv->request_mode);
4890 case PROP_ALLOCATION:
4891 g_value_set_boxed (value, &priv->allocation);
4895 g_value_set_float (value, clutter_actor_get_depth (actor));
4899 g_value_set_uint (value, priv->opacity);
4902 case PROP_OFFSCREEN_REDIRECT:
4903 g_value_set_enum (value, priv->offscreen_redirect);
4907 g_value_set_string (value, priv->name);
4911 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4915 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4919 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4923 g_value_set_boolean (value, priv->has_clip);
4928 ClutterGeometry clip;
4930 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4931 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4932 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4933 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4935 g_value_set_boxed (value, &clip);
4939 case PROP_CLIP_TO_ALLOCATION:
4940 g_value_set_boolean (value, priv->clip_to_allocation);
4945 const ClutterTransformInfo *info;
4947 info = _clutter_actor_get_transform_info_or_defaults (actor);
4948 g_value_set_double (value, info->scale_x);
4954 const ClutterTransformInfo *info;
4956 info = _clutter_actor_get_transform_info_or_defaults (actor);
4957 g_value_set_double (value, info->scale_y);
4961 case PROP_SCALE_CENTER_X:
4965 clutter_actor_get_scale_center (actor, ¢er, NULL);
4967 g_value_set_float (value, center);
4971 case PROP_SCALE_CENTER_Y:
4975 clutter_actor_get_scale_center (actor, NULL, ¢er);
4977 g_value_set_float (value, center);
4981 case PROP_SCALE_GRAVITY:
4982 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4986 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4989 case PROP_ROTATION_ANGLE_X:
4991 const ClutterTransformInfo *info;
4993 info = _clutter_actor_get_transform_info_or_defaults (actor);
4994 g_value_set_double (value, info->rx_angle);
4998 case PROP_ROTATION_ANGLE_Y:
5000 const ClutterTransformInfo *info;
5002 info = _clutter_actor_get_transform_info_or_defaults (actor);
5003 g_value_set_double (value, info->ry_angle);
5007 case PROP_ROTATION_ANGLE_Z:
5009 const ClutterTransformInfo *info;
5011 info = _clutter_actor_get_transform_info_or_defaults (actor);
5012 g_value_set_double (value, info->rz_angle);
5016 case PROP_ROTATION_CENTER_X:
5018 ClutterVertex center;
5020 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
5025 g_value_set_boxed (value, ¢er);
5029 case PROP_ROTATION_CENTER_Y:
5031 ClutterVertex center;
5033 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
5038 g_value_set_boxed (value, ¢er);
5042 case PROP_ROTATION_CENTER_Z:
5044 ClutterVertex center;
5046 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
5051 g_value_set_boxed (value, ¢er);
5055 case PROP_ROTATION_CENTER_Z_GRAVITY:
5056 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
5061 const ClutterTransformInfo *info;
5064 info = _clutter_actor_get_transform_info_or_defaults (actor);
5065 clutter_anchor_coord_get_units (actor, &info->anchor,
5069 g_value_set_float (value, anchor_x);
5075 const ClutterTransformInfo *info;
5078 info = _clutter_actor_get_transform_info_or_defaults (actor);
5079 clutter_anchor_coord_get_units (actor, &info->anchor,
5083 g_value_set_float (value, anchor_y);
5087 case PROP_ANCHOR_GRAVITY:
5088 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
5091 case PROP_SHOW_ON_SET_PARENT:
5092 g_value_set_boolean (value, priv->show_on_set_parent);
5095 case PROP_TEXT_DIRECTION:
5096 g_value_set_enum (value, priv->text_direction);
5099 case PROP_HAS_POINTER:
5100 g_value_set_boolean (value, priv->has_pointer);
5103 case PROP_LAYOUT_MANAGER:
5104 g_value_set_object (value, priv->layout_manager);
5109 const ClutterLayoutInfo *info;
5111 info = _clutter_actor_get_layout_info_or_defaults (actor);
5112 g_value_set_boolean (value, info->x_expand);
5118 const ClutterLayoutInfo *info;
5120 info = _clutter_actor_get_layout_info_or_defaults (actor);
5121 g_value_set_boolean (value, info->y_expand);
5127 const ClutterLayoutInfo *info;
5129 info = _clutter_actor_get_layout_info_or_defaults (actor);
5130 g_value_set_enum (value, info->x_align);
5136 const ClutterLayoutInfo *info;
5138 info = _clutter_actor_get_layout_info_or_defaults (actor);
5139 g_value_set_enum (value, info->y_align);
5143 case PROP_MARGIN_TOP:
5145 const ClutterLayoutInfo *info;
5147 info = _clutter_actor_get_layout_info_or_defaults (actor);
5148 g_value_set_float (value, info->margin.top);
5152 case PROP_MARGIN_BOTTOM:
5154 const ClutterLayoutInfo *info;
5156 info = _clutter_actor_get_layout_info_or_defaults (actor);
5157 g_value_set_float (value, info->margin.bottom);
5161 case PROP_MARGIN_LEFT:
5163 const ClutterLayoutInfo *info;
5165 info = _clutter_actor_get_layout_info_or_defaults (actor);
5166 g_value_set_float (value, info->margin.left);
5170 case PROP_MARGIN_RIGHT:
5172 const ClutterLayoutInfo *info;
5174 info = _clutter_actor_get_layout_info_or_defaults (actor);
5175 g_value_set_float (value, info->margin.right);
5179 case PROP_BACKGROUND_COLOR_SET:
5180 g_value_set_boolean (value, priv->bg_color_set);
5183 case PROP_BACKGROUND_COLOR:
5184 g_value_set_boxed (value, &priv->bg_color);
5187 case PROP_FIRST_CHILD:
5188 g_value_set_object (value, priv->first_child);
5191 case PROP_LAST_CHILD:
5192 g_value_set_object (value, priv->last_child);
5196 g_value_set_object (value, priv->content);
5199 case PROP_CONTENT_GRAVITY:
5200 g_value_set_enum (value, priv->content_gravity);
5203 case PROP_CONTENT_BOX:
5205 ClutterActorBox box = { 0, };
5207 clutter_actor_get_content_box (actor, &box);
5208 g_value_set_boxed (value, &box);
5212 case PROP_MINIFICATION_FILTER:
5213 g_value_set_enum (value, priv->min_filter);
5216 case PROP_MAGNIFICATION_FILTER:
5217 g_value_set_enum (value, priv->mag_filter);
5221 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5227 clutter_actor_dispose (GObject *object)
5229 ClutterActor *self = CLUTTER_ACTOR (object);
5230 ClutterActorPrivate *priv = self->priv;
5232 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5234 g_type_name (G_OBJECT_TYPE (self)),
5237 g_signal_emit (self, actor_signals[DESTROY], 0);
5239 /* avoid recursing when called from clutter_actor_destroy() */
5240 if (priv->parent != NULL)
5242 ClutterActor *parent = priv->parent;
5244 /* go through the Container implementation unless this
5245 * is an internal child and has been marked as such.
5247 * removing the actor from its parent will reset the
5248 * realized and mapped states.
5250 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5251 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5253 clutter_actor_remove_child_internal (parent, self,
5254 REMOVE_CHILD_LEGACY_FLAGS);
5257 /* parent must be gone at this point */
5258 g_assert (priv->parent == NULL);
5260 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5262 /* can't be mapped or realized with no parent */
5263 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5264 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5267 g_clear_object (&priv->pango_context);
5268 g_clear_object (&priv->actions);
5269 g_clear_object (&priv->constraints);
5270 g_clear_object (&priv->effects);
5271 g_clear_object (&priv->flatten_effect);
5273 if (priv->layout_manager != NULL)
5275 clutter_layout_manager_set_container (priv->layout_manager, NULL);
5276 g_clear_object (&priv->layout_manager);
5279 if (priv->content != NULL)
5281 _clutter_content_detached (priv->content, self);
5282 g_clear_object (&priv->content);
5285 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5289 clutter_actor_finalize (GObject *object)
5291 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5293 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5294 priv->name != NULL ? priv->name : "<none>",
5296 g_type_name (G_OBJECT_TYPE (object)));
5298 _clutter_context_release_id (priv->id);
5300 g_free (priv->name);
5302 #ifdef CLUTTER_ENABLE_DEBUG
5303 g_free (priv->debug_name);
5306 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5311 * clutter_actor_get_accessible:
5312 * @self: a #ClutterActor
5314 * Returns the accessible object that describes the actor to an
5315 * assistive technology.
5317 * If no class-specific #AtkObject implementation is available for the
5318 * actor instance in question, it will inherit an #AtkObject
5319 * implementation from the first ancestor class for which such an
5320 * implementation is defined.
5322 * The documentation of the <ulink
5323 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5324 * library contains more information about accessible objects and
5327 * Returns: (transfer none): the #AtkObject associated with @actor
5330 clutter_actor_get_accessible (ClutterActor *self)
5332 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5334 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5338 clutter_actor_real_get_accessible (ClutterActor *actor)
5340 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5344 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5346 AtkObject *accessible;
5348 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5349 if (accessible != NULL)
5350 g_object_ref (accessible);
5356 atk_implementor_iface_init (AtkImplementorIface *iface)
5358 iface->ref_accessible = _clutter_actor_ref_accessible;
5362 clutter_actor_update_default_paint_volume (ClutterActor *self,
5363 ClutterPaintVolume *volume)
5365 ClutterActorPrivate *priv = self->priv;
5366 gboolean res = TRUE;
5368 /* we start from the allocation */
5369 clutter_paint_volume_set_width (volume,
5370 priv->allocation.x2 - priv->allocation.x1);
5371 clutter_paint_volume_set_height (volume,
5372 priv->allocation.y2 - priv->allocation.y1);
5374 /* if the actor has a clip set then we have a pretty definite
5375 * size for the paint volume: the actor cannot possibly paint
5376 * outside the clip region.
5378 if (priv->clip_to_allocation)
5380 /* the allocation has already been set, so we just flip the
5387 ClutterActor *child;
5389 if (priv->has_clip &&
5390 priv->clip.width >= 0 &&
5391 priv->clip.height >= 0)
5393 ClutterVertex origin;
5395 origin.x = priv->clip.x;
5396 origin.y = priv->clip.y;
5399 clutter_paint_volume_set_origin (volume, &origin);
5400 clutter_paint_volume_set_width (volume, priv->clip.width);
5401 clutter_paint_volume_set_height (volume, priv->clip.height);
5406 /* if we don't have children we just bail out here... */
5407 if (priv->n_children == 0)
5410 /* ...but if we have children then we ask for their paint volume in
5411 * our coordinates. if any of our children replies that it doesn't
5412 * have a paint volume, we bail out
5414 for (child = priv->first_child;
5416 child = child->priv->next_sibling)
5418 const ClutterPaintVolume *child_volume;
5420 if (!CLUTTER_ACTOR_IS_MAPPED (child))
5423 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5424 if (child_volume == NULL)
5430 clutter_paint_volume_union (volume, child_volume);
5440 clutter_actor_real_get_paint_volume (ClutterActor *self,
5441 ClutterPaintVolume *volume)
5443 ClutterActorClass *klass;
5446 klass = CLUTTER_ACTOR_GET_CLASS (self);
5448 /* XXX - this thoroughly sucks, but we don't want to penalize users
5449 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5450 * redraw. This should go away in 2.0.
5452 if (klass->paint == clutter_actor_real_paint &&
5453 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5459 /* this is the default return value: we cannot know if a class
5460 * is going to paint outside its allocation, so we take the
5461 * conservative approach.
5466 /* update_default_paint_volume() should only fail if one of the children
5467 * reported an invalid, or no, paint volume
5469 if (!clutter_actor_update_default_paint_volume (self, volume))
5476 * clutter_actor_get_default_paint_volume:
5477 * @self: a #ClutterActor
5479 * Retrieves the default paint volume for @self.
5481 * This function provides the same #ClutterPaintVolume that would be
5482 * computed by the default implementation inside #ClutterActor of the
5483 * #ClutterActorClass.get_paint_volume() virtual function.
5485 * This function should only be used by #ClutterActor subclasses that
5486 * cannot chain up to the parent implementation when computing their
5489 * Return value: (transfer none): a pointer to the default
5490 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5491 * the actor could not compute a valid paint volume. The returned value
5492 * is not guaranteed to be stable across multiple frames, so if you
5493 * want to retain it, you will need to copy it using
5494 * clutter_paint_volume_copy().
5498 const ClutterPaintVolume *
5499 clutter_actor_get_default_paint_volume (ClutterActor *self)
5501 ClutterPaintVolume volume;
5502 ClutterPaintVolume *res;
5504 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5507 _clutter_paint_volume_init_static (&volume, self);
5508 if (clutter_actor_update_default_paint_volume (self, &volume))
5510 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5514 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5515 _clutter_paint_volume_copy_static (&volume, res);
5519 clutter_paint_volume_free (&volume);
5525 clutter_actor_real_has_overlaps (ClutterActor *self)
5527 /* By default we'll assume that all actors need an offscreen redirect to get
5528 * the correct opacity. Actors such as ClutterTexture that would never need
5529 * an offscreen redirect can override this to return FALSE. */
5534 clutter_actor_real_destroy (ClutterActor *actor)
5536 ClutterActorIter iter;
5538 g_object_freeze_notify (G_OBJECT (actor));
5540 clutter_actor_iter_init (&iter, actor);
5541 while (clutter_actor_iter_next (&iter, NULL))
5542 clutter_actor_iter_destroy (&iter);
5544 g_object_thaw_notify (G_OBJECT (actor));
5548 clutter_actor_constructor (GType gtype,
5550 GObjectConstructParam *props)
5552 GObjectClass *gobject_class;
5556 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5557 retval = gobject_class->constructor (gtype, n_props, props);
5558 self = CLUTTER_ACTOR (retval);
5560 if (self->priv->layout_manager == NULL)
5562 ClutterLayoutManager *default_layout;
5564 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5566 default_layout = clutter_fixed_layout_new ();
5567 clutter_actor_set_layout_manager (self, default_layout);
5574 clutter_actor_class_init (ClutterActorClass *klass)
5576 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5578 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5579 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5580 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5581 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5583 object_class->constructor = clutter_actor_constructor;
5584 object_class->set_property = clutter_actor_set_property;
5585 object_class->get_property = clutter_actor_get_property;
5586 object_class->dispose = clutter_actor_dispose;
5587 object_class->finalize = clutter_actor_finalize;
5589 klass->show = clutter_actor_real_show;
5590 klass->show_all = clutter_actor_show;
5591 klass->hide = clutter_actor_real_hide;
5592 klass->hide_all = clutter_actor_hide;
5593 klass->map = clutter_actor_real_map;
5594 klass->unmap = clutter_actor_real_unmap;
5595 klass->unrealize = clutter_actor_real_unrealize;
5596 klass->pick = clutter_actor_real_pick;
5597 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5598 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5599 klass->allocate = clutter_actor_real_allocate;
5600 klass->queue_redraw = clutter_actor_real_queue_redraw;
5601 klass->queue_relayout = clutter_actor_real_queue_relayout;
5602 klass->apply_transform = clutter_actor_real_apply_transform;
5603 klass->get_accessible = clutter_actor_real_get_accessible;
5604 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5605 klass->has_overlaps = clutter_actor_real_has_overlaps;
5606 klass->paint = clutter_actor_real_paint;
5607 klass->destroy = clutter_actor_real_destroy;
5609 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5614 * X coordinate of the actor in pixels. If written, forces a fixed
5615 * position for the actor. If read, returns the fixed position if any,
5616 * otherwise the allocation if available, otherwise 0.
5618 * The #ClutterActor:x property is animatable.
5621 g_param_spec_float ("x",
5623 P_("X coordinate of the actor"),
5624 -G_MAXFLOAT, G_MAXFLOAT,
5627 G_PARAM_STATIC_STRINGS |
5628 CLUTTER_PARAM_ANIMATABLE);
5633 * Y coordinate of the actor in pixels. If written, forces a fixed
5634 * position for the actor. If read, returns the fixed position if
5635 * any, otherwise the allocation if available, otherwise 0.
5637 * The #ClutterActor:y property is animatable.
5640 g_param_spec_float ("y",
5642 P_("Y coordinate of the actor"),
5643 -G_MAXFLOAT, G_MAXFLOAT,
5646 G_PARAM_STATIC_STRINGS |
5647 CLUTTER_PARAM_ANIMATABLE);
5650 * ClutterActor:position:
5652 * The position of the origin of the actor.
5654 * This property is a shorthand for setting and getting the
5655 * #ClutterActor:x and #ClutterActor:y properties at the same
5658 * The #ClutterActor:position property is animatable.
5662 obj_props[PROP_POSITION] =
5663 g_param_spec_boxed ("position",
5665 P_("The position of the origin of the actor"),
5668 G_PARAM_STATIC_STRINGS |
5669 CLUTTER_PARAM_ANIMATABLE);
5672 * ClutterActor:width:
5674 * Width of the actor (in pixels). If written, forces the minimum and
5675 * natural size request of the actor to the given width. If read, returns
5676 * the allocated width if available, otherwise the width request.
5678 * The #ClutterActor:width property is animatable.
5680 obj_props[PROP_WIDTH] =
5681 g_param_spec_float ("width",
5683 P_("Width of the actor"),
5687 G_PARAM_STATIC_STRINGS |
5688 CLUTTER_PARAM_ANIMATABLE);
5691 * ClutterActor:height:
5693 * Height of the actor (in pixels). If written, forces the minimum and
5694 * natural size request of the actor to the given height. If read, returns
5695 * the allocated height if available, otherwise the height request.
5697 * The #ClutterActor:height property is animatable.
5699 obj_props[PROP_HEIGHT] =
5700 g_param_spec_float ("height",
5702 P_("Height of the actor"),
5706 G_PARAM_STATIC_STRINGS |
5707 CLUTTER_PARAM_ANIMATABLE);
5710 * ClutterActor:size:
5712 * The size of the actor.
5714 * This property is a shorthand for setting and getting the
5715 * #ClutterActor:width and #ClutterActor:height at the same time.
5717 * The #ClutterActor:size property is animatable.
5721 obj_props[PROP_SIZE] =
5722 g_param_spec_boxed ("size",
5724 P_("The size of the actor"),
5727 G_PARAM_STATIC_STRINGS |
5728 CLUTTER_PARAM_ANIMATABLE);
5731 * ClutterActor:fixed-x:
5733 * The fixed X position of the actor in pixels.
5735 * Writing this property sets #ClutterActor:fixed-position-set
5736 * property as well, as a side effect
5740 obj_props[PROP_FIXED_X] =
5741 g_param_spec_float ("fixed-x",
5743 P_("Forced X position of the actor"),
5744 -G_MAXFLOAT, G_MAXFLOAT,
5746 CLUTTER_PARAM_READWRITE);
5749 * ClutterActor:fixed-y:
5751 * The fixed Y position of the actor in pixels.
5753 * Writing this property sets the #ClutterActor:fixed-position-set
5754 * property as well, as a side effect
5758 obj_props[PROP_FIXED_Y] =
5759 g_param_spec_float ("fixed-y",
5761 P_("Forced Y position of the actor"),
5762 -G_MAXFLOAT, G_MAXFLOAT,
5764 CLUTTER_PARAM_READWRITE);
5767 * ClutterActor:fixed-position-set:
5769 * This flag controls whether the #ClutterActor:fixed-x and
5770 * #ClutterActor:fixed-y properties are used
5774 obj_props[PROP_FIXED_POSITION_SET] =
5775 g_param_spec_boolean ("fixed-position-set",
5776 P_("Fixed position set"),
5777 P_("Whether to use fixed positioning for the actor"),
5779 CLUTTER_PARAM_READWRITE);
5782 * ClutterActor:min-width:
5784 * A forced minimum width request for the actor, in pixels
5786 * Writing this property sets the #ClutterActor:min-width-set property
5787 * as well, as a side effect.
5789 *This property overrides the usual width request of the actor.
5793 obj_props[PROP_MIN_WIDTH] =
5794 g_param_spec_float ("min-width",
5796 P_("Forced minimum width request for the actor"),
5799 CLUTTER_PARAM_READWRITE);
5802 * ClutterActor:min-height:
5804 * A forced minimum height request for the actor, in pixels
5806 * Writing this property sets the #ClutterActor:min-height-set property
5807 * as well, as a side effect. This property overrides the usual height
5808 * request of the actor.
5812 obj_props[PROP_MIN_HEIGHT] =
5813 g_param_spec_float ("min-height",
5815 P_("Forced minimum height request for the actor"),
5818 CLUTTER_PARAM_READWRITE);
5821 * ClutterActor:natural-width:
5823 * A forced natural width request for the actor, in pixels
5825 * Writing this property sets the #ClutterActor:natural-width-set
5826 * property as well, as a side effect. This property overrides the
5827 * usual width request of the actor
5831 obj_props[PROP_NATURAL_WIDTH] =
5832 g_param_spec_float ("natural-width",
5833 P_("Natural Width"),
5834 P_("Forced natural width request for the actor"),
5837 CLUTTER_PARAM_READWRITE);
5840 * ClutterActor:natural-height:
5842 * A forced natural height request for the actor, in pixels
5844 * Writing this property sets the #ClutterActor:natural-height-set
5845 * property as well, as a side effect. This property overrides the
5846 * usual height request of the actor
5850 obj_props[PROP_NATURAL_HEIGHT] =
5851 g_param_spec_float ("natural-height",
5852 P_("Natural Height"),
5853 P_("Forced natural height request for the actor"),
5856 CLUTTER_PARAM_READWRITE);
5859 * ClutterActor:min-width-set:
5861 * This flag controls whether the #ClutterActor:min-width property
5866 obj_props[PROP_MIN_WIDTH_SET] =
5867 g_param_spec_boolean ("min-width-set",
5868 P_("Minimum width set"),
5869 P_("Whether to use the min-width property"),
5871 CLUTTER_PARAM_READWRITE);
5874 * ClutterActor:min-height-set:
5876 * This flag controls whether the #ClutterActor:min-height property
5881 obj_props[PROP_MIN_HEIGHT_SET] =
5882 g_param_spec_boolean ("min-height-set",
5883 P_("Minimum height set"),
5884 P_("Whether to use the min-height property"),
5886 CLUTTER_PARAM_READWRITE);
5889 * ClutterActor:natural-width-set:
5891 * This flag controls whether the #ClutterActor:natural-width property
5896 obj_props[PROP_NATURAL_WIDTH_SET] =
5897 g_param_spec_boolean ("natural-width-set",
5898 P_("Natural width set"),
5899 P_("Whether to use the natural-width property"),
5901 CLUTTER_PARAM_READWRITE);
5904 * ClutterActor:natural-height-set:
5906 * This flag controls whether the #ClutterActor:natural-height property
5911 obj_props[PROP_NATURAL_HEIGHT_SET] =
5912 g_param_spec_boolean ("natural-height-set",
5913 P_("Natural height set"),
5914 P_("Whether to use the natural-height property"),
5916 CLUTTER_PARAM_READWRITE);
5919 * ClutterActor:allocation:
5921 * The allocation for the actor, in pixels
5923 * This is property is read-only, but you might monitor it to know when an
5924 * actor moves or resizes
5928 obj_props[PROP_ALLOCATION] =
5929 g_param_spec_boxed ("allocation",
5931 P_("The actor's allocation"),
5932 CLUTTER_TYPE_ACTOR_BOX,
5934 G_PARAM_STATIC_STRINGS |
5935 CLUTTER_PARAM_ANIMATABLE);
5938 * ClutterActor:request-mode:
5940 * Request mode for the #ClutterActor. The request mode determines the
5941 * type of geometry management used by the actor, either height for width
5942 * (the default) or width for height.
5944 * For actors implementing height for width, the parent container should get
5945 * the preferred width first, and then the preferred height for that width.
5947 * For actors implementing width for height, the parent container should get
5948 * the preferred height first, and then the preferred width for that height.
5953 * ClutterRequestMode mode;
5954 * gfloat natural_width, min_width;
5955 * gfloat natural_height, min_height;
5957 * mode = clutter_actor_get_request_mode (child);
5958 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5960 * clutter_actor_get_preferred_width (child, -1,
5962 * &natural_width);
5963 * clutter_actor_get_preferred_height (child, natural_width,
5965 * &natural_height);
5969 * clutter_actor_get_preferred_height (child, -1,
5971 * &natural_height);
5972 * clutter_actor_get_preferred_width (child, natural_height,
5974 * &natural_width);
5978 * will retrieve the minimum and natural width and height depending on the
5979 * preferred request mode of the #ClutterActor "child".
5981 * The clutter_actor_get_preferred_size() function will implement this
5986 obj_props[PROP_REQUEST_MODE] =
5987 g_param_spec_enum ("request-mode",
5989 P_("The actor's request mode"),
5990 CLUTTER_TYPE_REQUEST_MODE,
5991 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5992 CLUTTER_PARAM_READWRITE);
5995 * ClutterActor:depth:
5997 * The position of the actor on the Z axis.
5999 * The #ClutterActor:depth property is relative to the parent's
6002 * The #ClutterActor:depth property is animatable.
6006 obj_props[PROP_DEPTH] =
6007 g_param_spec_float ("depth",
6009 P_("Position on the Z axis"),
6010 -G_MAXFLOAT, G_MAXFLOAT,
6013 G_PARAM_STATIC_STRINGS |
6014 CLUTTER_PARAM_ANIMATABLE);
6017 * ClutterActor:opacity:
6019 * Opacity of an actor, between 0 (fully transparent) and
6020 * 255 (fully opaque)
6022 * The #ClutterActor:opacity property is animatable.
6024 obj_props[PROP_OPACITY] =
6025 g_param_spec_uint ("opacity",
6027 P_("Opacity of an actor"),
6031 G_PARAM_STATIC_STRINGS |
6032 CLUTTER_PARAM_ANIMATABLE);
6035 * ClutterActor:offscreen-redirect:
6037 * Determines the conditions in which the actor will be redirected
6038 * to an offscreen framebuffer while being painted. For example this
6039 * can be used to cache an actor in a framebuffer or for improved
6040 * handling of transparent actors. See
6041 * clutter_actor_set_offscreen_redirect() for details.
6045 obj_props[PROP_OFFSCREEN_REDIRECT] =
6046 g_param_spec_flags ("offscreen-redirect",
6047 P_("Offscreen redirect"),
6048 P_("Flags controlling when to flatten the actor into a single image"),
6049 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
6051 CLUTTER_PARAM_READWRITE);
6054 * ClutterActor:visible:
6056 * Whether the actor is set to be visible or not
6058 * See also #ClutterActor:mapped
6060 obj_props[PROP_VISIBLE] =
6061 g_param_spec_boolean ("visible",
6063 P_("Whether the actor is visible or not"),
6065 CLUTTER_PARAM_READWRITE);
6068 * ClutterActor:mapped:
6070 * Whether the actor is mapped (will be painted when the stage
6071 * to which it belongs is mapped)
6075 obj_props[PROP_MAPPED] =
6076 g_param_spec_boolean ("mapped",
6078 P_("Whether the actor will be painted"),
6080 CLUTTER_PARAM_READABLE);
6083 * ClutterActor:realized:
6085 * Whether the actor has been realized
6089 obj_props[PROP_REALIZED] =
6090 g_param_spec_boolean ("realized",
6092 P_("Whether the actor has been realized"),
6094 CLUTTER_PARAM_READABLE);
6097 * ClutterActor:reactive:
6099 * Whether the actor is reactive to events or not
6101 * Only reactive actors will emit event-related signals
6105 obj_props[PROP_REACTIVE] =
6106 g_param_spec_boolean ("reactive",
6108 P_("Whether the actor is reactive to events"),
6110 CLUTTER_PARAM_READWRITE);
6113 * ClutterActor:has-clip:
6115 * Whether the actor has the #ClutterActor:clip property set or not
6117 obj_props[PROP_HAS_CLIP] =
6118 g_param_spec_boolean ("has-clip",
6120 P_("Whether the actor has a clip set"),
6122 CLUTTER_PARAM_READABLE);
6125 * ClutterActor:clip:
6127 * The clip region for the actor, in actor-relative coordinates
6129 * Every part of the actor outside the clip region will not be
6132 obj_props[PROP_CLIP] =
6133 g_param_spec_boxed ("clip",
6135 P_("The clip region for the actor"),
6136 CLUTTER_TYPE_GEOMETRY,
6137 CLUTTER_PARAM_READWRITE);
6140 * ClutterActor:name:
6142 * The name of the actor
6146 obj_props[PROP_NAME] =
6147 g_param_spec_string ("name",
6149 P_("Name of the actor"),
6151 CLUTTER_PARAM_READWRITE);
6154 * ClutterActor:scale-x:
6156 * The horizontal scale of the actor.
6158 * The #ClutterActor:scale-x property is animatable.
6162 obj_props[PROP_SCALE_X] =
6163 g_param_spec_double ("scale-x",
6165 P_("Scale factor on the X axis"),
6169 G_PARAM_STATIC_STRINGS |
6170 CLUTTER_PARAM_ANIMATABLE);
6173 * ClutterActor:scale-y:
6175 * The vertical scale of the actor.
6177 * The #ClutterActor:scale-y property is animatable.
6181 obj_props[PROP_SCALE_Y] =
6182 g_param_spec_double ("scale-y",
6184 P_("Scale factor on the Y axis"),
6188 G_PARAM_STATIC_STRINGS |
6189 CLUTTER_PARAM_ANIMATABLE);
6192 * ClutterActor:scale-center-x:
6194 * The horizontal center point for scaling
6198 obj_props[PROP_SCALE_CENTER_X] =
6199 g_param_spec_float ("scale-center-x",
6200 P_("Scale Center X"),
6201 P_("Horizontal scale center"),
6202 -G_MAXFLOAT, G_MAXFLOAT,
6204 CLUTTER_PARAM_READWRITE);
6207 * ClutterActor:scale-center-y:
6209 * The vertical center point for scaling
6213 obj_props[PROP_SCALE_CENTER_Y] =
6214 g_param_spec_float ("scale-center-y",
6215 P_("Scale Center Y"),
6216 P_("Vertical scale center"),
6217 -G_MAXFLOAT, G_MAXFLOAT,
6219 CLUTTER_PARAM_READWRITE);
6222 * ClutterActor:scale-gravity:
6224 * The center point for scaling expressed as a #ClutterGravity
6228 obj_props[PROP_SCALE_GRAVITY] =
6229 g_param_spec_enum ("scale-gravity",
6230 P_("Scale Gravity"),
6231 P_("The center of scaling"),
6232 CLUTTER_TYPE_GRAVITY,
6233 CLUTTER_GRAVITY_NONE,
6234 CLUTTER_PARAM_READWRITE);
6237 * ClutterActor:rotation-angle-x:
6239 * The rotation angle on the X axis.
6241 * The #ClutterActor:rotation-angle-x property is animatable.
6245 obj_props[PROP_ROTATION_ANGLE_X] =
6246 g_param_spec_double ("rotation-angle-x",
6247 P_("Rotation Angle X"),
6248 P_("The rotation angle on the X axis"),
6249 -G_MAXDOUBLE, G_MAXDOUBLE,
6252 G_PARAM_STATIC_STRINGS |
6253 CLUTTER_PARAM_ANIMATABLE);
6256 * ClutterActor:rotation-angle-y:
6258 * The rotation angle on the Y axis
6260 * The #ClutterActor:rotation-angle-y property is animatable.
6264 obj_props[PROP_ROTATION_ANGLE_Y] =
6265 g_param_spec_double ("rotation-angle-y",
6266 P_("Rotation Angle Y"),
6267 P_("The rotation angle on the Y axis"),
6268 -G_MAXDOUBLE, G_MAXDOUBLE,
6271 G_PARAM_STATIC_STRINGS |
6272 CLUTTER_PARAM_ANIMATABLE);
6275 * ClutterActor:rotation-angle-z:
6277 * The rotation angle on the Z axis
6279 * The #ClutterActor:rotation-angle-z property is animatable.
6283 obj_props[PROP_ROTATION_ANGLE_Z] =
6284 g_param_spec_double ("rotation-angle-z",
6285 P_("Rotation Angle Z"),
6286 P_("The rotation angle on the Z axis"),
6287 -G_MAXDOUBLE, G_MAXDOUBLE,
6290 G_PARAM_STATIC_STRINGS |
6291 CLUTTER_PARAM_ANIMATABLE);
6294 * ClutterActor:rotation-center-x:
6296 * The rotation center on the X axis.
6300 obj_props[PROP_ROTATION_CENTER_X] =
6301 g_param_spec_boxed ("rotation-center-x",
6302 P_("Rotation Center X"),
6303 P_("The rotation center on the X axis"),
6304 CLUTTER_TYPE_VERTEX,
6305 CLUTTER_PARAM_READWRITE);
6308 * ClutterActor:rotation-center-y:
6310 * The rotation center on the Y axis.
6314 obj_props[PROP_ROTATION_CENTER_Y] =
6315 g_param_spec_boxed ("rotation-center-y",
6316 P_("Rotation Center Y"),
6317 P_("The rotation center on the Y axis"),
6318 CLUTTER_TYPE_VERTEX,
6319 CLUTTER_PARAM_READWRITE);
6322 * ClutterActor:rotation-center-z:
6324 * The rotation center on the Z axis.
6328 obj_props[PROP_ROTATION_CENTER_Z] =
6329 g_param_spec_boxed ("rotation-center-z",
6330 P_("Rotation Center Z"),
6331 P_("The rotation center on the Z axis"),
6332 CLUTTER_TYPE_VERTEX,
6333 CLUTTER_PARAM_READWRITE);
6336 * ClutterActor:rotation-center-z-gravity:
6338 * The rotation center on the Z axis expressed as a #ClutterGravity.
6342 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6343 g_param_spec_enum ("rotation-center-z-gravity",
6344 P_("Rotation Center Z Gravity"),
6345 P_("Center point for rotation around the Z axis"),
6346 CLUTTER_TYPE_GRAVITY,
6347 CLUTTER_GRAVITY_NONE,
6348 CLUTTER_PARAM_READWRITE);
6351 * ClutterActor:anchor-x:
6353 * The X coordinate of an actor's anchor point, relative to
6354 * the actor coordinate space, in pixels
6358 obj_props[PROP_ANCHOR_X] =
6359 g_param_spec_float ("anchor-x",
6361 P_("X coordinate of the anchor point"),
6362 -G_MAXFLOAT, G_MAXFLOAT,
6364 CLUTTER_PARAM_READWRITE);
6367 * ClutterActor:anchor-y:
6369 * The Y coordinate of an actor's anchor point, relative to
6370 * the actor coordinate space, in pixels
6374 obj_props[PROP_ANCHOR_Y] =
6375 g_param_spec_float ("anchor-y",
6377 P_("Y coordinate of the anchor point"),
6378 -G_MAXFLOAT, G_MAXFLOAT,
6380 CLUTTER_PARAM_READWRITE);
6383 * ClutterActor:anchor-gravity:
6385 * The anchor point expressed as a #ClutterGravity
6389 obj_props[PROP_ANCHOR_GRAVITY] =
6390 g_param_spec_enum ("anchor-gravity",
6391 P_("Anchor Gravity"),
6392 P_("The anchor point as a ClutterGravity"),
6393 CLUTTER_TYPE_GRAVITY,
6394 CLUTTER_GRAVITY_NONE,
6395 CLUTTER_PARAM_READWRITE);
6398 * ClutterActor:show-on-set-parent:
6400 * If %TRUE, the actor is automatically shown when parented.
6402 * Calling clutter_actor_hide() on an actor which has not been
6403 * parented will set this property to %FALSE as a side effect.
6407 obj_props[PROP_SHOW_ON_SET_PARENT] =
6408 g_param_spec_boolean ("show-on-set-parent",
6409 P_("Show on set parent"),
6410 P_("Whether the actor is shown when parented"),
6412 CLUTTER_PARAM_READWRITE);
6415 * ClutterActor:clip-to-allocation:
6417 * Whether the clip region should track the allocated area
6420 * This property is ignored if a clip area has been explicitly
6421 * set using clutter_actor_set_clip().
6425 obj_props[PROP_CLIP_TO_ALLOCATION] =
6426 g_param_spec_boolean ("clip-to-allocation",
6427 P_("Clip to Allocation"),
6428 P_("Sets the clip region to track the actor's allocation"),
6430 CLUTTER_PARAM_READWRITE);
6433 * ClutterActor:text-direction:
6435 * The direction of the text inside a #ClutterActor.
6439 obj_props[PROP_TEXT_DIRECTION] =
6440 g_param_spec_enum ("text-direction",
6441 P_("Text Direction"),
6442 P_("Direction of the text"),
6443 CLUTTER_TYPE_TEXT_DIRECTION,
6444 CLUTTER_TEXT_DIRECTION_LTR,
6445 CLUTTER_PARAM_READWRITE);
6448 * ClutterActor:has-pointer:
6450 * Whether the actor contains the pointer of a #ClutterInputDevice
6455 obj_props[PROP_HAS_POINTER] =
6456 g_param_spec_boolean ("has-pointer",
6458 P_("Whether the actor contains the pointer of an input device"),
6460 CLUTTER_PARAM_READABLE);
6463 * ClutterActor:actions:
6465 * Adds a #ClutterAction to the actor
6469 obj_props[PROP_ACTIONS] =
6470 g_param_spec_object ("actions",
6472 P_("Adds an action to the actor"),
6473 CLUTTER_TYPE_ACTION,
6474 CLUTTER_PARAM_WRITABLE);
6477 * ClutterActor:constraints:
6479 * Adds a #ClutterConstraint to the actor
6483 obj_props[PROP_CONSTRAINTS] =
6484 g_param_spec_object ("constraints",
6486 P_("Adds a constraint to the actor"),
6487 CLUTTER_TYPE_CONSTRAINT,
6488 CLUTTER_PARAM_WRITABLE);
6491 * ClutterActor:effect:
6493 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6497 obj_props[PROP_EFFECT] =
6498 g_param_spec_object ("effect",
6500 P_("Add an effect to be applied on the actor"),
6501 CLUTTER_TYPE_EFFECT,
6502 CLUTTER_PARAM_WRITABLE);
6505 * ClutterActor:layout-manager:
6507 * A delegate object for controlling the layout of the children of
6512 obj_props[PROP_LAYOUT_MANAGER] =
6513 g_param_spec_object ("layout-manager",
6514 P_("Layout Manager"),
6515 P_("The object controlling the layout of an actor's children"),
6516 CLUTTER_TYPE_LAYOUT_MANAGER,
6517 CLUTTER_PARAM_READWRITE);
6520 * ClutterActor:x-expand:
6522 * Whether a layout manager should assign more space to the actor on
6527 obj_props[PROP_X_EXPAND] =
6528 g_param_spec_boolean ("x-expand",
6530 P_("Whether extra horizontal space should be assigned to the actor"),
6533 G_PARAM_STATIC_STRINGS);
6536 * ClutterActor:y-expand:
6538 * Whether a layout manager should assign more space to the actor on
6543 obj_props[PROP_Y_EXPAND] =
6544 g_param_spec_boolean ("y-expand",
6546 P_("Whether extra vertical space should be assigned to the actor"),
6549 G_PARAM_STATIC_STRINGS);
6552 * ClutterActor:x-align:
6554 * The alignment of an actor on the X axis, if the actor has been given
6555 * extra space for its allocation. See also the #ClutterActor:x-expand
6560 obj_props[PROP_X_ALIGN] =
6561 g_param_spec_enum ("x-align",
6563 P_("The alignment of the actor on the X axis within its allocation"),
6564 CLUTTER_TYPE_ACTOR_ALIGN,
6565 CLUTTER_ACTOR_ALIGN_FILL,
6566 CLUTTER_PARAM_READWRITE);
6569 * ClutterActor:y-align:
6571 * The alignment of an actor on the Y axis, if the actor has been given
6572 * extra space for its allocation.
6576 obj_props[PROP_Y_ALIGN] =
6577 g_param_spec_enum ("y-align",
6579 P_("The alignment of the actor on the Y axis within its allocation"),
6580 CLUTTER_TYPE_ACTOR_ALIGN,
6581 CLUTTER_ACTOR_ALIGN_FILL,
6582 CLUTTER_PARAM_READWRITE);
6585 * ClutterActor:margin-top:
6587 * The margin (in pixels) from the top of the actor.
6589 * This property adds a margin to the actor's preferred size; the margin
6590 * will be automatically taken into account when allocating the actor.
6594 obj_props[PROP_MARGIN_TOP] =
6595 g_param_spec_float ("margin-top",
6597 P_("Extra space at the top"),
6600 CLUTTER_PARAM_READWRITE);
6603 * ClutterActor:margin-bottom:
6605 * The margin (in pixels) from the bottom of the actor.
6607 * This property adds a margin to the actor's preferred size; the margin
6608 * will be automatically taken into account when allocating the actor.
6612 obj_props[PROP_MARGIN_BOTTOM] =
6613 g_param_spec_float ("margin-bottom",
6614 P_("Margin Bottom"),
6615 P_("Extra space at the bottom"),
6618 CLUTTER_PARAM_READWRITE);
6621 * ClutterActor:margin-left:
6623 * The margin (in pixels) from the left of the actor.
6625 * This property adds a margin to the actor's preferred size; the margin
6626 * will be automatically taken into account when allocating the actor.
6630 obj_props[PROP_MARGIN_LEFT] =
6631 g_param_spec_float ("margin-left",
6633 P_("Extra space at the left"),
6636 CLUTTER_PARAM_READWRITE);
6639 * ClutterActor:margin-right:
6641 * The margin (in pixels) from the right of the actor.
6643 * This property adds a margin to the actor's preferred size; the margin
6644 * will be automatically taken into account when allocating the actor.
6648 obj_props[PROP_MARGIN_RIGHT] =
6649 g_param_spec_float ("margin-right",
6651 P_("Extra space at the right"),
6654 CLUTTER_PARAM_READWRITE);
6657 * ClutterActor:background-color-set:
6659 * Whether the #ClutterActor:background-color property has been set.
6663 obj_props[PROP_BACKGROUND_COLOR_SET] =
6664 g_param_spec_boolean ("background-color-set",
6665 P_("Background Color Set"),
6666 P_("Whether the background color is set"),
6668 CLUTTER_PARAM_READABLE);
6671 * ClutterActor:background-color:
6673 * Paints a solid fill of the actor's allocation using the specified
6676 * The #ClutterActor:background-color property is animatable.
6680 obj_props[PROP_BACKGROUND_COLOR] =
6681 clutter_param_spec_color ("background-color",
6682 P_("Background color"),
6683 P_("The actor's background color"),
6684 CLUTTER_COLOR_Transparent,
6686 G_PARAM_STATIC_STRINGS |
6687 CLUTTER_PARAM_ANIMATABLE);
6690 * ClutterActor:first-child:
6692 * The actor's first child.
6696 obj_props[PROP_FIRST_CHILD] =
6697 g_param_spec_object ("first-child",
6699 P_("The actor's first child"),
6701 CLUTTER_PARAM_READABLE);
6704 * ClutterActor:last-child:
6706 * The actor's last child.
6710 obj_props[PROP_LAST_CHILD] =
6711 g_param_spec_object ("last-child",
6713 P_("The actor's last child"),
6715 CLUTTER_PARAM_READABLE);
6718 * ClutterActor:content:
6720 * The #ClutterContent implementation that controls the content
6725 obj_props[PROP_CONTENT] =
6726 g_param_spec_object ("content",
6728 P_("Delegate object for painting the actor's content"),
6729 CLUTTER_TYPE_CONTENT,
6730 CLUTTER_PARAM_READWRITE);
6733 * ClutterActor:content-gravity:
6735 * The alignment that should be honoured by the #ClutterContent
6736 * set with the #ClutterActor:content property.
6738 * Changing the value of this property will change the bounding box of
6739 * the content; you can use the #ClutterActor:content-box property to
6740 * get the position and size of the content within the actor's
6743 * This property is meaningful only for #ClutterContent implementations
6744 * that have a preferred size, and if the preferred size is smaller than
6745 * the actor's allocation.
6747 * The #ClutterActor:content-gravity property is animatable.
6751 obj_props[PROP_CONTENT_GRAVITY] =
6752 g_param_spec_enum ("content-gravity",
6753 P_("Content Gravity"),
6754 P_("Alignment of the actor's content"),
6755 CLUTTER_TYPE_CONTENT_GRAVITY,
6756 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6757 CLUTTER_PARAM_READWRITE);
6760 * ClutterActor:content-box:
6762 * The bounding box for the #ClutterContent used by the actor.
6764 * The value of this property is controlled by the #ClutterActor:allocation
6765 * and #ClutterActor:content-gravity properties of #ClutterActor.
6767 * The bounding box for the content is guaranteed to never exceed the
6768 * allocation's of the actor.
6772 obj_props[PROP_CONTENT_BOX] =
6773 g_param_spec_boxed ("content-box",
6775 P_("The bounding box of the actor's content"),
6776 CLUTTER_TYPE_ACTOR_BOX,
6778 G_PARAM_STATIC_STRINGS |
6779 CLUTTER_PARAM_ANIMATABLE);
6781 obj_props[PROP_MINIFICATION_FILTER] =
6782 g_param_spec_enum ("minification-filter",
6783 P_("Minification Filter"),
6784 P_("The filter used when reducing the size of the content"),
6785 CLUTTER_TYPE_SCALING_FILTER,
6786 CLUTTER_SCALING_FILTER_LINEAR,
6787 CLUTTER_PARAM_READWRITE);
6789 obj_props[PROP_MAGNIFICATION_FILTER] =
6790 g_param_spec_enum ("magnification-filter",
6791 P_("Magnification Filter"),
6792 P_("The filter used when increasing the size of the content"),
6793 CLUTTER_TYPE_SCALING_FILTER,
6794 CLUTTER_SCALING_FILTER_LINEAR,
6795 CLUTTER_PARAM_READWRITE);
6797 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6800 * ClutterActor::destroy:
6801 * @actor: the #ClutterActor which emitted the signal
6803 * The ::destroy signal notifies that all references held on the
6804 * actor which emitted it should be released.
6806 * The ::destroy signal should be used by all holders of a reference
6809 * This signal might result in the finalization of the #ClutterActor
6810 * if all references are released.
6812 * Composite actors and actors implementing the #ClutterContainer
6813 * interface should override the default implementation of the
6814 * class handler of this signal and call clutter_actor_destroy() on
6815 * their children. When overriding the default class handler, it is
6816 * required to chain up to the parent's implementation.
6820 actor_signals[DESTROY] =
6821 g_signal_new (I_("destroy"),
6822 G_TYPE_FROM_CLASS (object_class),
6823 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6824 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6826 _clutter_marshal_VOID__VOID,
6829 * ClutterActor::show:
6830 * @actor: the object which received the signal
6832 * The ::show signal is emitted when an actor is visible and
6833 * rendered on the stage.
6837 actor_signals[SHOW] =
6838 g_signal_new (I_("show"),
6839 G_TYPE_FROM_CLASS (object_class),
6841 G_STRUCT_OFFSET (ClutterActorClass, show),
6843 _clutter_marshal_VOID__VOID,
6846 * ClutterActor::hide:
6847 * @actor: the object which received the signal
6849 * The ::hide signal is emitted when an actor is no longer rendered
6854 actor_signals[HIDE] =
6855 g_signal_new (I_("hide"),
6856 G_TYPE_FROM_CLASS (object_class),
6858 G_STRUCT_OFFSET (ClutterActorClass, hide),
6860 _clutter_marshal_VOID__VOID,
6863 * ClutterActor::parent-set:
6864 * @actor: the object which received the signal
6865 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6867 * This signal is emitted when the parent of the actor changes.
6871 actor_signals[PARENT_SET] =
6872 g_signal_new (I_("parent-set"),
6873 G_TYPE_FROM_CLASS (object_class),
6875 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6877 _clutter_marshal_VOID__OBJECT,
6879 CLUTTER_TYPE_ACTOR);
6882 * ClutterActor::queue-redraw:
6883 * @actor: the actor we're bubbling the redraw request through
6884 * @origin: the actor which initiated the redraw request
6886 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6887 * is called on @origin.
6889 * The default implementation for #ClutterActor chains up to the
6890 * parent actor and queues a redraw on the parent, thus "bubbling"
6891 * the redraw queue up through the actor graph. The default
6892 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6893 * in a main loop idle handler.
6895 * Note that the @origin actor may be the stage, or a container; it
6896 * does not have to be a leaf node in the actor graph.
6898 * Toolkits embedding a #ClutterStage which require a redraw and
6899 * relayout cycle can stop the emission of this signal using the
6900 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6905 * on_redraw_complete (gpointer data)
6907 * ClutterStage *stage = data;
6909 * /* execute the Clutter drawing pipeline */
6910 * clutter_stage_ensure_redraw (stage);
6914 * on_stage_queue_redraw (ClutterStage *stage)
6916 * /* this prevents the default handler to run */
6917 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6919 * /* queue a redraw with the host toolkit and call
6920 * * a function when the redraw has been completed
6922 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6926 * <note><para>This signal is emitted before the Clutter paint
6927 * pipeline is executed. If you want to know when the pipeline has
6928 * been completed you should connect to the ::paint signal on the
6929 * Stage with g_signal_connect_after().</para></note>
6933 actor_signals[QUEUE_REDRAW] =
6934 g_signal_new (I_("queue-redraw"),
6935 G_TYPE_FROM_CLASS (object_class),
6938 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6940 _clutter_marshal_VOID__OBJECT,
6942 CLUTTER_TYPE_ACTOR);
6945 * ClutterActor::queue-relayout:
6946 * @actor: the actor being queued for relayout
6948 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6949 * is called on an actor.
6951 * The default implementation for #ClutterActor chains up to the
6952 * parent actor and queues a relayout on the parent, thus "bubbling"
6953 * the relayout queue up through the actor graph.
6955 * The main purpose of this signal is to allow relayout to be propagated
6956 * properly in the procense of #ClutterClone actors. Applications will
6957 * not normally need to connect to this signal.
6961 actor_signals[QUEUE_RELAYOUT] =
6962 g_signal_new (I_("queue-relayout"),
6963 G_TYPE_FROM_CLASS (object_class),
6966 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6968 _clutter_marshal_VOID__VOID,
6972 * ClutterActor::event:
6973 * @actor: the actor which received the event
6974 * @event: a #ClutterEvent
6976 * The ::event signal is emitted each time an event is received
6977 * by the @actor. This signal will be emitted on every actor,
6978 * following the hierarchy chain, until it reaches the top-level
6979 * container (the #ClutterStage).
6981 * Return value: %TRUE if the event has been handled by the actor,
6982 * or %FALSE to continue the emission.
6986 actor_signals[EVENT] =
6987 g_signal_new (I_("event"),
6988 G_TYPE_FROM_CLASS (object_class),
6990 G_STRUCT_OFFSET (ClutterActorClass, event),
6991 _clutter_boolean_handled_accumulator, NULL,
6992 _clutter_marshal_BOOLEAN__BOXED,
6994 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6996 * ClutterActor::button-press-event:
6997 * @actor: the actor which received the event
6998 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
7000 * The ::button-press-event signal is emitted each time a mouse button
7001 * is pressed on @actor.
7003 * Return value: %TRUE if the event has been handled by the actor,
7004 * or %FALSE to continue the emission.
7008 actor_signals[BUTTON_PRESS_EVENT] =
7009 g_signal_new (I_("button-press-event"),
7010 G_TYPE_FROM_CLASS (object_class),
7012 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
7013 _clutter_boolean_handled_accumulator, NULL,
7014 _clutter_marshal_BOOLEAN__BOXED,
7016 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7018 * ClutterActor::button-release-event:
7019 * @actor: the actor which received the event
7020 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
7022 * The ::button-release-event signal is emitted each time a mouse button
7023 * is released on @actor.
7025 * Return value: %TRUE if the event has been handled by the actor,
7026 * or %FALSE to continue the emission.
7030 actor_signals[BUTTON_RELEASE_EVENT] =
7031 g_signal_new (I_("button-release-event"),
7032 G_TYPE_FROM_CLASS (object_class),
7034 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
7035 _clutter_boolean_handled_accumulator, NULL,
7036 _clutter_marshal_BOOLEAN__BOXED,
7038 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7040 * ClutterActor::scroll-event:
7041 * @actor: the actor which received the event
7042 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
7044 * The ::scroll-event signal is emitted each time the mouse is
7045 * scrolled on @actor
7047 * Return value: %TRUE if the event has been handled by the actor,
7048 * or %FALSE to continue the emission.
7052 actor_signals[SCROLL_EVENT] =
7053 g_signal_new (I_("scroll-event"),
7054 G_TYPE_FROM_CLASS (object_class),
7056 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
7057 _clutter_boolean_handled_accumulator, NULL,
7058 _clutter_marshal_BOOLEAN__BOXED,
7060 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7062 * ClutterActor::key-press-event:
7063 * @actor: the actor which received the event
7064 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7066 * The ::key-press-event signal is emitted each time a keyboard button
7067 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
7069 * Return value: %TRUE if the event has been handled by the actor,
7070 * or %FALSE to continue the emission.
7074 actor_signals[KEY_PRESS_EVENT] =
7075 g_signal_new (I_("key-press-event"),
7076 G_TYPE_FROM_CLASS (object_class),
7078 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
7079 _clutter_boolean_handled_accumulator, NULL,
7080 _clutter_marshal_BOOLEAN__BOXED,
7082 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7084 * ClutterActor::key-release-event:
7085 * @actor: the actor which received the event
7086 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7088 * The ::key-release-event signal is emitted each time a keyboard button
7089 * is released while @actor has key focus (see
7090 * clutter_stage_set_key_focus()).
7092 * Return value: %TRUE if the event has been handled by the actor,
7093 * or %FALSE to continue the emission.
7097 actor_signals[KEY_RELEASE_EVENT] =
7098 g_signal_new (I_("key-release-event"),
7099 G_TYPE_FROM_CLASS (object_class),
7101 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
7102 _clutter_boolean_handled_accumulator, NULL,
7103 _clutter_marshal_BOOLEAN__BOXED,
7105 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7107 * ClutterActor::motion-event:
7108 * @actor: the actor which received the event
7109 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
7111 * The ::motion-event signal is emitted each time the mouse pointer is
7112 * moved over @actor.
7114 * Return value: %TRUE if the event has been handled by the actor,
7115 * or %FALSE to continue the emission.
7119 actor_signals[MOTION_EVENT] =
7120 g_signal_new (I_("motion-event"),
7121 G_TYPE_FROM_CLASS (object_class),
7123 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
7124 _clutter_boolean_handled_accumulator, NULL,
7125 _clutter_marshal_BOOLEAN__BOXED,
7127 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7130 * ClutterActor::key-focus-in:
7131 * @actor: the actor which now has key focus
7133 * The ::key-focus-in signal is emitted when @actor receives key focus.
7137 actor_signals[KEY_FOCUS_IN] =
7138 g_signal_new (I_("key-focus-in"),
7139 G_TYPE_FROM_CLASS (object_class),
7141 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
7143 _clutter_marshal_VOID__VOID,
7147 * ClutterActor::key-focus-out:
7148 * @actor: the actor which now has key focus
7150 * The ::key-focus-out signal is emitted when @actor loses key focus.
7154 actor_signals[KEY_FOCUS_OUT] =
7155 g_signal_new (I_("key-focus-out"),
7156 G_TYPE_FROM_CLASS (object_class),
7158 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
7160 _clutter_marshal_VOID__VOID,
7164 * ClutterActor::enter-event:
7165 * @actor: the actor which the pointer has entered.
7166 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7168 * The ::enter-event signal is emitted when the pointer enters the @actor
7170 * Return value: %TRUE if the event has been handled by the actor,
7171 * or %FALSE to continue the emission.
7175 actor_signals[ENTER_EVENT] =
7176 g_signal_new (I_("enter-event"),
7177 G_TYPE_FROM_CLASS (object_class),
7179 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
7180 _clutter_boolean_handled_accumulator, NULL,
7181 _clutter_marshal_BOOLEAN__BOXED,
7183 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7186 * ClutterActor::leave-event:
7187 * @actor: the actor which the pointer has left
7188 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7190 * The ::leave-event signal is emitted when the pointer leaves the @actor.
7192 * Return value: %TRUE if the event has been handled by the actor,
7193 * or %FALSE to continue the emission.
7197 actor_signals[LEAVE_EVENT] =
7198 g_signal_new (I_("leave-event"),
7199 G_TYPE_FROM_CLASS (object_class),
7201 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7202 _clutter_boolean_handled_accumulator, NULL,
7203 _clutter_marshal_BOOLEAN__BOXED,
7205 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7208 * ClutterActor::captured-event:
7209 * @actor: the actor which received the signal
7210 * @event: a #ClutterEvent
7212 * The ::captured-event signal is emitted when an event is captured
7213 * by Clutter. This signal will be emitted starting from the top-level
7214 * container (the #ClutterStage) to the actor which received the event
7215 * going down the hierarchy. This signal can be used to intercept every
7216 * event before the specialized events (like
7217 * ClutterActor::button-press-event or ::key-released-event) are
7220 * Return value: %TRUE if the event has been handled by the actor,
7221 * or %FALSE to continue the emission.
7225 actor_signals[CAPTURED_EVENT] =
7226 g_signal_new (I_("captured-event"),
7227 G_TYPE_FROM_CLASS (object_class),
7229 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7230 _clutter_boolean_handled_accumulator, NULL,
7231 _clutter_marshal_BOOLEAN__BOXED,
7233 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7236 * ClutterActor::paint:
7237 * @actor: the #ClutterActor that received the signal
7239 * The ::paint signal is emitted each time an actor is being painted.
7241 * Subclasses of #ClutterActor should override the class signal handler
7242 * and paint themselves in that function.
7244 * It is possible to connect a handler to the ::paint signal in order
7245 * to set up some custom aspect of a paint.
7249 actor_signals[PAINT] =
7250 g_signal_new (I_("paint"),
7251 G_TYPE_FROM_CLASS (object_class),
7254 G_STRUCT_OFFSET (ClutterActorClass, paint),
7256 _clutter_marshal_VOID__VOID,
7259 * ClutterActor::realize:
7260 * @actor: the #ClutterActor that received the signal
7262 * The ::realize signal is emitted each time an actor is being
7267 actor_signals[REALIZE] =
7268 g_signal_new (I_("realize"),
7269 G_TYPE_FROM_CLASS (object_class),
7271 G_STRUCT_OFFSET (ClutterActorClass, realize),
7273 _clutter_marshal_VOID__VOID,
7276 * ClutterActor::unrealize:
7277 * @actor: the #ClutterActor that received the signal
7279 * The ::unrealize signal is emitted each time an actor is being
7284 actor_signals[UNREALIZE] =
7285 g_signal_new (I_("unrealize"),
7286 G_TYPE_FROM_CLASS (object_class),
7288 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7290 _clutter_marshal_VOID__VOID,
7294 * ClutterActor::pick:
7295 * @actor: the #ClutterActor that received the signal
7296 * @color: the #ClutterColor to be used when picking
7298 * The ::pick signal is emitted each time an actor is being painted
7299 * in "pick mode". The pick mode is used to identify the actor during
7300 * the event handling phase, or by clutter_stage_get_actor_at_pos().
7301 * The actor should paint its shape using the passed @pick_color.
7303 * Subclasses of #ClutterActor should override the class signal handler
7304 * and paint themselves in that function.
7306 * It is possible to connect a handler to the ::pick signal in order
7307 * to set up some custom aspect of a paint in pick mode.
7311 actor_signals[PICK] =
7312 g_signal_new (I_("pick"),
7313 G_TYPE_FROM_CLASS (object_class),
7315 G_STRUCT_OFFSET (ClutterActorClass, pick),
7317 _clutter_marshal_VOID__BOXED,
7319 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7322 * ClutterActor::allocation-changed:
7323 * @actor: the #ClutterActor that emitted the signal
7324 * @box: a #ClutterActorBox with the new allocation
7325 * @flags: #ClutterAllocationFlags for the allocation
7327 * The ::allocation-changed signal is emitted when the
7328 * #ClutterActor:allocation property changes. Usually, application
7329 * code should just use the notifications for the :allocation property
7330 * but if you want to track the allocation flags as well, for instance
7331 * to know whether the absolute origin of @actor changed, then you might
7332 * want use this signal instead.
7336 actor_signals[ALLOCATION_CHANGED] =
7337 g_signal_new (I_("allocation-changed"),
7338 G_TYPE_FROM_CLASS (object_class),
7342 _clutter_marshal_VOID__BOXED_FLAGS,
7344 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7345 CLUTTER_TYPE_ALLOCATION_FLAGS);
7348 * ClutterActor::transitions-completed:
7349 * @actor: a #ClutterActor
7351 * The ::transitions-completed signal is emitted once all transitions
7352 * involving @actor are complete.
7356 actor_signals[TRANSITIONS_COMPLETED] =
7357 g_signal_new (I_("transitions-completed"),
7358 G_TYPE_FROM_CLASS (object_class),
7362 _clutter_marshal_VOID__VOID,
7367 clutter_actor_init (ClutterActor *self)
7369 ClutterActorPrivate *priv;
7371 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7373 priv->id = _clutter_context_acquire_id (self);
7376 priv->opacity = 0xff;
7377 priv->show_on_set_parent = TRUE;
7379 priv->needs_width_request = TRUE;
7380 priv->needs_height_request = TRUE;
7381 priv->needs_allocation = TRUE;
7383 priv->cached_width_age = 1;
7384 priv->cached_height_age = 1;
7386 priv->opacity_override = -1;
7387 priv->enable_model_view_transform = TRUE;
7389 /* Initialize an empty paint volume to start with */
7390 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7391 priv->last_paint_volume_valid = TRUE;
7393 priv->transform_valid = FALSE;
7395 /* the default is to stretch the content, to match the
7396 * current behaviour of basically all actors. also, it's
7397 * the easiest thing to compute.
7399 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7400 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7401 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7403 /* this flag will be set to TRUE if the actor gets a child
7404 * or if the [xy]-expand flags are explicitly set; until
7405 * then, the actor does not need to expand.
7407 * this also allows us to avoid computing the expand flag
7408 * when building up a scene.
7410 priv->needs_compute_expand = FALSE;
7414 * clutter_actor_new:
7416 * Creates a new #ClutterActor.
7418 * A newly created actor has a floating reference, which will be sunk
7419 * when it is added to another actor.
7421 * Return value: (transfer full): the newly created #ClutterActor
7426 clutter_actor_new (void)
7428 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7432 * clutter_actor_destroy:
7433 * @self: a #ClutterActor
7435 * Destroys an actor. When an actor is destroyed, it will break any
7436 * references it holds to other objects. If the actor is inside a
7437 * container, the actor will be removed.
7439 * When you destroy a container, its children will be destroyed as well.
7441 * Note: you cannot destroy the #ClutterStage returned by
7442 * clutter_stage_get_default().
7445 clutter_actor_destroy (ClutterActor *self)
7447 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7449 g_object_ref (self);
7451 /* avoid recursion while destroying */
7452 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7454 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7456 g_object_run_dispose (G_OBJECT (self));
7458 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7461 g_object_unref (self);
7465 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7466 ClutterPaintVolume *clip)
7468 ClutterActorPrivate *priv = self->priv;
7469 ClutterPaintVolume *pv;
7472 /* Remove queue entry early in the process, otherwise a new
7473 queue_redraw() during signal handling could put back this
7474 object in the stage redraw list (but the entry is freed as
7475 soon as we return from this function, causing a segfault
7478 priv->queue_redraw_entry = NULL;
7480 /* If we've been explicitly passed a clip volume then there's
7481 * nothing more to calculate, but otherwise the only thing we know
7482 * is that the change is constrained to the given actor.
7484 * The idea is that if we know the paint volume for where the actor
7485 * was last drawn (in eye coordinates) and we also have the paint
7486 * volume for where it will be drawn next (in actor coordinates)
7487 * then if we queue a redraw for both these volumes that will cover
7488 * everything that needs to be redrawn to clear the old view and
7489 * show the latest view of the actor.
7491 * Don't clip this redraw if we don't know what position we had for
7492 * the previous redraw since we don't know where to set the clip so
7493 * it will clear the actor as it is currently.
7497 _clutter_actor_set_queue_redraw_clip (self, clip);
7500 else if (G_LIKELY (priv->last_paint_volume_valid))
7502 pv = _clutter_actor_get_paint_volume_mutable (self);
7505 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7507 /* make sure we redraw the actors old position... */
7508 _clutter_actor_set_queue_redraw_clip (stage,
7509 &priv->last_paint_volume);
7510 _clutter_actor_signal_queue_redraw (stage, stage);
7511 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7513 /* XXX: Ideally the redraw signal would take a clip volume
7514 * argument, but that would be an ABI break. Until we can
7515 * break the ABI we pass the argument out-of-band
7518 /* setup the clip for the actors new position... */
7519 _clutter_actor_set_queue_redraw_clip (self, pv);
7528 _clutter_actor_signal_queue_redraw (self, self);
7530 /* Just in case anyone is manually firing redraw signals without
7531 * using the public queue_redraw() API we are careful to ensure that
7532 * our out-of-band clip member is cleared before returning...
7534 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7536 if (G_LIKELY (clipped))
7537 _clutter_actor_set_queue_redraw_clip (self, NULL);
7541 _clutter_actor_get_allocation_clip (ClutterActor *self,
7542 ClutterActorBox *clip)
7544 ClutterActorBox allocation;
7546 /* XXX: we don't care if we get an out of date allocation here
7547 * because clutter_actor_queue_redraw_with_clip knows to ignore
7548 * the clip if the actor's allocation is invalid.
7550 * This is noted because clutter_actor_get_allocation_box does some
7551 * unnecessary work to support buggy code with a comment suggesting
7552 * that it could be changed later which would be good for this use
7555 clutter_actor_get_allocation_box (self, &allocation);
7557 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7558 * actor's own coordinate space but the allocation is in parent
7562 clip->x2 = allocation.x2 - allocation.x1;
7563 clip->y2 = allocation.y2 - allocation.y1;
7567 _clutter_actor_queue_redraw_full (ClutterActor *self,
7568 ClutterRedrawFlags flags,
7569 ClutterPaintVolume *volume,
7570 ClutterEffect *effect)
7572 ClutterActorPrivate *priv = self->priv;
7573 ClutterPaintVolume allocation_pv;
7574 ClutterPaintVolume *pv;
7575 gboolean should_free_pv;
7576 ClutterActor *stage;
7578 /* Here's an outline of the actor queue redraw mechanism:
7580 * The process starts in one of the following two functions which
7581 * are wrappers for this function:
7582 * clutter_actor_queue_redraw
7583 * _clutter_actor_queue_redraw_with_clip
7585 * additionally, an effect can queue a redraw by wrapping this
7586 * function in clutter_effect_queue_rerun
7588 * This functions queues an entry in a list associated with the
7589 * stage which is a list of actors that queued a redraw while
7590 * updating the timelines, performing layouting and processing other
7591 * mainloop sources before the next paint starts.
7593 * We aim to minimize the processing done at this point because
7594 * there is a good chance other events will happen while updating
7595 * the scenegraph that would invalidate any expensive work we might
7596 * otherwise try to do here. For example we don't try and resolve
7597 * the screen space bounding box of an actor at this stage so as to
7598 * minimize how much of the screen redraw because it's possible
7599 * something else will happen which will force a full redraw anyway.
7601 * When all updates are complete and we come to paint the stage then
7602 * we iterate this list and actually emit the "queue-redraw" signals
7603 * for each of the listed actors which will bubble up to the stage
7604 * for each actor and at that point we will transform the actors
7605 * paint volume into screen coordinates to determine the clip region
7606 * for what needs to be redrawn in the next paint.
7608 * Besides minimizing redundant work another reason for this
7609 * deferred design is that it's more likely we will be able to
7610 * determine the paint volume of an actor once we've finished
7611 * updating the scenegraph because its allocation should be up to
7612 * date. NB: If we can't determine an actors paint volume then we
7613 * can't automatically queue a clipped redraw which can make a big
7614 * difference to performance.
7616 * So the control flow goes like this:
7617 * One of clutter_actor_queue_redraw,
7618 * _clutter_actor_queue_redraw_with_clip
7619 * or clutter_effect_queue_rerun
7621 * then control moves to:
7622 * _clutter_stage_queue_actor_redraw
7624 * later during _clutter_stage_do_update, once relayouting is done
7625 * and the scenegraph has been updated we will call:
7626 * _clutter_stage_finish_queue_redraws
7628 * _clutter_stage_finish_queue_redraws will call
7629 * _clutter_actor_finish_queue_redraw for each listed actor.
7630 * Note: actors *are* allowed to queue further redraws during this
7631 * process (considering clone actors or texture_new_from_actor which
7632 * respond to their source queueing a redraw by queuing a redraw
7633 * themselves). We repeat the process until the list is empty.
7635 * This will result in the "queue-redraw" signal being fired for
7636 * each actor which will pass control to the default signal handler:
7637 * clutter_actor_real_queue_redraw
7639 * This will bubble up to the stages handler:
7640 * clutter_stage_real_queue_redraw
7642 * clutter_stage_real_queue_redraw will transform the actors paint
7643 * volume into screen space and add it as a clip region for the next
7647 /* ignore queueing a redraw for actors being destroyed */
7648 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7651 stage = _clutter_actor_get_stage_internal (self);
7653 /* Ignore queueing a redraw for actors not descended from a stage */
7657 /* ignore queueing a redraw on stages that are being destroyed */
7658 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7661 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7663 ClutterActorBox allocation_clip;
7664 ClutterVertex origin;
7666 /* If the actor doesn't have a valid allocation then we will
7667 * queue a full stage redraw. */
7668 if (priv->needs_allocation)
7670 /* NB: NULL denotes an undefined clip which will result in a
7672 _clutter_actor_set_queue_redraw_clip (self, NULL);
7673 _clutter_actor_signal_queue_redraw (self, self);
7677 _clutter_paint_volume_init_static (&allocation_pv, self);
7678 pv = &allocation_pv;
7680 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7682 origin.x = allocation_clip.x1;
7683 origin.y = allocation_clip.y1;
7685 clutter_paint_volume_set_origin (pv, &origin);
7686 clutter_paint_volume_set_width (pv,
7687 allocation_clip.x2 - allocation_clip.x1);
7688 clutter_paint_volume_set_height (pv,
7689 allocation_clip.y2 -
7690 allocation_clip.y1);
7691 should_free_pv = TRUE;
7696 should_free_pv = FALSE;
7699 self->priv->queue_redraw_entry =
7700 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7701 priv->queue_redraw_entry,
7706 clutter_paint_volume_free (pv);
7708 /* If this is the first redraw queued then we can directly use the
7710 if (!priv->is_dirty)
7711 priv->effect_to_redraw = effect;
7712 /* Otherwise we need to merge it with the existing effect parameter */
7713 else if (effect != NULL)
7715 /* If there's already an effect then we need to use whichever is
7716 later in the chain of actors. Otherwise a full redraw has
7717 already been queued on the actor so we need to ignore the
7719 if (priv->effect_to_redraw != NULL)
7721 if (priv->effects == NULL)
7722 g_warning ("Redraw queued with an effect that is "
7723 "not applied to the actor");
7728 for (l = _clutter_meta_group_peek_metas (priv->effects);
7732 if (l->data == priv->effect_to_redraw ||
7734 priv->effect_to_redraw = l->data;
7741 /* If no effect is specified then we need to redraw the whole
7743 priv->effect_to_redraw = NULL;
7746 priv->is_dirty = TRUE;
7750 * clutter_actor_queue_redraw:
7751 * @self: A #ClutterActor
7753 * Queues up a redraw of an actor and any children. The redraw occurs
7754 * once the main loop becomes idle (after the current batch of events
7755 * has been processed, roughly).
7757 * Applications rarely need to call this, as redraws are handled
7758 * automatically by modification functions.
7760 * This function will not do anything if @self is not visible, or
7761 * if the actor is inside an invisible part of the scenegraph.
7763 * Also be aware that painting is a NOP for actors with an opacity of
7766 * When you are implementing a custom actor you must queue a redraw
7767 * whenever some private state changes that will affect painting or
7768 * picking of your actor.
7771 clutter_actor_queue_redraw (ClutterActor *self)
7773 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7775 _clutter_actor_queue_redraw_full (self,
7777 NULL, /* clip volume */
7782 * _clutter_actor_queue_redraw_with_clip:
7783 * @self: A #ClutterActor
7784 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7785 * this queue redraw.
7786 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7787 * redrawn or %NULL if you are just using a @flag to state your
7790 * Queues up a clipped redraw of an actor and any children. The redraw
7791 * occurs once the main loop becomes idle (after the current batch of
7792 * events has been processed, roughly).
7794 * If no flags are given the clip volume is defined by @volume
7795 * specified in actor coordinates and tells Clutter that only content
7796 * within this volume has been changed so Clutter can optionally
7797 * optimize the redraw.
7799 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7800 * should be %NULL and this tells Clutter to use the actor's current
7801 * allocation as a clip box. This flag can only be used for 2D actors,
7802 * because any actor with depth may be projected outside its
7805 * Applications rarely need to call this, as redraws are handled
7806 * automatically by modification functions.
7808 * This function will not do anything if @self is not visible, or if
7809 * the actor is inside an invisible part of the scenegraph.
7811 * Also be aware that painting is a NOP for actors with an opacity of
7814 * When you are implementing a custom actor you must queue a redraw
7815 * whenever some private state changes that will affect painting or
7816 * picking of your actor.
7819 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7820 ClutterRedrawFlags flags,
7821 ClutterPaintVolume *volume)
7823 _clutter_actor_queue_redraw_full (self,
7825 volume, /* clip volume */
7830 _clutter_actor_queue_only_relayout (ClutterActor *self)
7832 ClutterActorPrivate *priv = self->priv;
7834 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7837 if (priv->needs_width_request &&
7838 priv->needs_height_request &&
7839 priv->needs_allocation)
7840 return; /* save some cpu cycles */
7842 #if CLUTTER_ENABLE_DEBUG
7843 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7845 g_warning ("The actor '%s' is currently inside an allocation "
7846 "cycle; calling clutter_actor_queue_relayout() is "
7848 _clutter_actor_get_debug_name (self));
7850 #endif /* CLUTTER_ENABLE_DEBUG */
7852 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7856 * clutter_actor_queue_redraw_with_clip:
7857 * @self: a #ClutterActor
7858 * @clip: (allow-none): a rectangular clip region, or %NULL
7860 * Queues a redraw on @self limited to a specific, actor-relative
7863 * If @clip is %NULL this function is equivalent to
7864 * clutter_actor_queue_redraw().
7869 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7870 const cairo_rectangle_int_t *clip)
7872 ClutterPaintVolume volume;
7873 ClutterVertex origin;
7875 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7879 clutter_actor_queue_redraw (self);
7883 _clutter_paint_volume_init_static (&volume, self);
7889 clutter_paint_volume_set_origin (&volume, &origin);
7890 clutter_paint_volume_set_width (&volume, clip->width);
7891 clutter_paint_volume_set_height (&volume, clip->height);
7893 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7895 clutter_paint_volume_free (&volume);
7899 * clutter_actor_queue_relayout:
7900 * @self: A #ClutterActor
7902 * Indicates that the actor's size request or other layout-affecting
7903 * properties may have changed. This function is used inside #ClutterActor
7904 * subclass implementations, not by applications directly.
7906 * Queueing a new layout automatically queues a redraw as well.
7911 clutter_actor_queue_relayout (ClutterActor *self)
7913 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7915 _clutter_actor_queue_only_relayout (self);
7916 clutter_actor_queue_redraw (self);
7920 * clutter_actor_get_preferred_size:
7921 * @self: a #ClutterActor
7922 * @min_width_p: (out) (allow-none): return location for the minimum
7924 * @min_height_p: (out) (allow-none): return location for the minimum
7926 * @natural_width_p: (out) (allow-none): return location for the natural
7928 * @natural_height_p: (out) (allow-none): return location for the natural
7931 * Computes the preferred minimum and natural size of an actor, taking into
7932 * account the actor's geometry management (either height-for-width
7933 * or width-for-height).
7935 * The width and height used to compute the preferred height and preferred
7936 * width are the actor's natural ones.
7938 * If you need to control the height for the preferred width, or the width for
7939 * the preferred height, you should use clutter_actor_get_preferred_width()
7940 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7941 * geometry management using the #ClutterActor:request-mode property.
7946 clutter_actor_get_preferred_size (ClutterActor *self,
7947 gfloat *min_width_p,
7948 gfloat *min_height_p,
7949 gfloat *natural_width_p,
7950 gfloat *natural_height_p)
7952 ClutterActorPrivate *priv;
7953 gfloat min_width, min_height;
7954 gfloat natural_width, natural_height;
7956 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7960 min_width = min_height = 0;
7961 natural_width = natural_height = 0;
7963 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7965 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7966 clutter_actor_get_preferred_width (self, -1,
7969 clutter_actor_get_preferred_height (self, natural_width,
7975 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7976 clutter_actor_get_preferred_height (self, -1,
7979 clutter_actor_get_preferred_width (self, natural_height,
7985 *min_width_p = min_width;
7988 *min_height_p = min_height;
7990 if (natural_width_p)
7991 *natural_width_p = natural_width;
7993 if (natural_height_p)
7994 *natural_height_p = natural_height;
7999 * @align: a #ClutterActorAlign
8000 * @direction: a #ClutterTextDirection
8002 * Retrieves the correct alignment depending on the text direction
8004 * Return value: the effective alignment
8006 static ClutterActorAlign
8007 effective_align (ClutterActorAlign align,
8008 ClutterTextDirection direction)
8010 ClutterActorAlign res;
8014 case CLUTTER_ACTOR_ALIGN_START:
8015 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
8016 ? CLUTTER_ACTOR_ALIGN_END
8017 : CLUTTER_ACTOR_ALIGN_START;
8020 case CLUTTER_ACTOR_ALIGN_END:
8021 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
8022 ? CLUTTER_ACTOR_ALIGN_START
8023 : CLUTTER_ACTOR_ALIGN_END;
8035 * _clutter_actor_get_effective_x_align:
8036 * @self: a #ClutterActor
8038 * Retrieves the effective horizontal alignment, taking into
8039 * consideration the text direction of @self.
8041 * Return value: the effective horizontal alignment
8044 _clutter_actor_get_effective_x_align (ClutterActor *self)
8046 return effective_align (clutter_actor_get_x_align (self),
8047 clutter_actor_get_text_direction (self));
8051 adjust_for_margin (float margin_start,
8053 float *minimum_size,
8054 float *natural_size,
8055 float *allocated_start,
8056 float *allocated_end)
8058 *minimum_size -= (margin_start + margin_end);
8059 *natural_size -= (margin_start + margin_end);
8060 *allocated_start += margin_start;
8061 *allocated_end -= margin_end;
8065 adjust_for_alignment (ClutterActorAlign alignment,
8067 float *allocated_start,
8068 float *allocated_end)
8070 float allocated_size = *allocated_end - *allocated_start;
8074 case CLUTTER_ACTOR_ALIGN_FILL:
8078 case CLUTTER_ACTOR_ALIGN_START:
8080 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
8083 case CLUTTER_ACTOR_ALIGN_END:
8084 if (allocated_size > natural_size)
8086 *allocated_start += (allocated_size - natural_size);
8087 *allocated_end = *allocated_start + natural_size;
8091 case CLUTTER_ACTOR_ALIGN_CENTER:
8092 if (allocated_size > natural_size)
8094 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
8095 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
8102 * clutter_actor_adjust_width:
8103 * @self: a #ClutterActor
8104 * @minimum_width: (inout): the actor's preferred minimum width, which
8105 * will be adjusted depending on the margin
8106 * @natural_width: (inout): the actor's preferred natural width, which
8107 * will be adjusted depending on the margin
8108 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
8109 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
8111 * Adjusts the preferred and allocated position and size of an actor,
8112 * depending on the margin and alignment properties.
8115 clutter_actor_adjust_width (ClutterActor *self,
8116 gfloat *minimum_width,
8117 gfloat *natural_width,
8118 gfloat *adjusted_x1,
8119 gfloat *adjusted_x2)
8121 ClutterTextDirection text_dir;
8122 const ClutterLayoutInfo *info;
8124 info = _clutter_actor_get_layout_info_or_defaults (self);
8125 text_dir = clutter_actor_get_text_direction (self);
8127 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
8129 /* this will tweak natural_width to remove the margin, so that
8130 * adjust_for_alignment() will use the correct size
8132 adjust_for_margin (info->margin.left, info->margin.right,
8133 minimum_width, natural_width,
8134 adjusted_x1, adjusted_x2);
8136 adjust_for_alignment (effective_align (info->x_align, text_dir),
8138 adjusted_x1, adjusted_x2);
8142 * clutter_actor_adjust_height:
8143 * @self: a #ClutterActor
8144 * @minimum_height: (inout): the actor's preferred minimum height, which
8145 * will be adjusted depending on the margin
8146 * @natural_height: (inout): the actor's preferred natural height, which
8147 * will be adjusted depending on the margin
8148 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
8149 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
8151 * Adjusts the preferred and allocated position and size of an actor,
8152 * depending on the margin and alignment properties.
8155 clutter_actor_adjust_height (ClutterActor *self,
8156 gfloat *minimum_height,
8157 gfloat *natural_height,
8158 gfloat *adjusted_y1,
8159 gfloat *adjusted_y2)
8161 const ClutterLayoutInfo *info;
8163 info = _clutter_actor_get_layout_info_or_defaults (self);
8165 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
8167 /* this will tweak natural_height to remove the margin, so that
8168 * adjust_for_alignment() will use the correct size
8170 adjust_for_margin (info->margin.top, info->margin.bottom,
8171 minimum_height, natural_height,
8175 /* we don't use effective_align() here, because text direction
8176 * only affects the horizontal axis
8178 adjust_for_alignment (info->y_align,
8185 /* looks for a cached size request for this for_size. If not
8186 * found, returns the oldest entry so it can be overwritten */
8188 _clutter_actor_get_cached_size_request (gfloat for_size,
8189 SizeRequest *cached_size_requests,
8190 SizeRequest **result)
8194 *result = &cached_size_requests[0];
8196 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
8200 sr = &cached_size_requests[i];
8203 sr->for_size == for_size)
8205 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8209 else if (sr->age < (*result)->age)
8215 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8221 * clutter_actor_get_preferred_width:
8222 * @self: A #ClutterActor
8223 * @for_height: available height when computing the preferred width,
8224 * or a negative value to indicate that no height is defined
8225 * @min_width_p: (out) (allow-none): return location for minimum width,
8227 * @natural_width_p: (out) (allow-none): return location for the natural
8230 * Computes the requested minimum and natural widths for an actor,
8231 * optionally depending on the specified height, or if they are
8232 * already computed, returns the cached values.
8234 * An actor may not get its request - depending on the layout
8235 * manager that's in effect.
8237 * A request should not incorporate the actor's scale or anchor point;
8238 * those transformations do not affect layout, only rendering.
8243 clutter_actor_get_preferred_width (ClutterActor *self,
8245 gfloat *min_width_p,
8246 gfloat *natural_width_p)
8248 float request_min_width, request_natural_width;
8249 SizeRequest *cached_size_request;
8250 const ClutterLayoutInfo *info;
8251 ClutterActorPrivate *priv;
8252 gboolean found_in_cache;
8254 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8258 info = _clutter_actor_get_layout_info_or_defaults (self);
8260 /* we shortcircuit the case of a fixed size set using set_width() */
8261 if (priv->min_width_set && priv->natural_width_set)
8263 if (min_width_p != NULL)
8264 *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8266 if (natural_width_p != NULL)
8267 *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8272 /* the remaining cases are:
8274 * - either min_width or natural_width have been set
8275 * - neither min_width or natural_width have been set
8277 * in both cases, we go through the cache (and through the actor in case
8278 * of cache misses) and determine the authoritative value depending on
8282 if (!priv->needs_width_request)
8285 _clutter_actor_get_cached_size_request (for_height,
8286 priv->width_requests,
8287 &cached_size_request);
8291 /* if the actor needs a width request we use the first slot */
8292 found_in_cache = FALSE;
8293 cached_size_request = &priv->width_requests[0];
8296 if (!found_in_cache)
8298 gfloat minimum_width, natural_width;
8299 ClutterActorClass *klass;
8301 minimum_width = natural_width = 0;
8303 /* adjust for the margin */
8304 if (for_height >= 0)
8306 for_height -= (info->margin.top + info->margin.bottom);
8311 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8313 klass = CLUTTER_ACTOR_GET_CLASS (self);
8314 klass->get_preferred_width (self, for_height,
8318 /* adjust for the margin */
8319 minimum_width += (info->margin.left + info->margin.right);
8320 natural_width += (info->margin.left + info->margin.right);
8322 /* Due to accumulated float errors, it's better not to warn
8323 * on this, but just fix it.
8325 if (natural_width < minimum_width)
8326 natural_width = minimum_width;
8328 cached_size_request->min_size = minimum_width;
8329 cached_size_request->natural_size = natural_width;
8330 cached_size_request->for_size = for_height;
8331 cached_size_request->age = priv->cached_width_age;
8333 priv->cached_width_age += 1;
8334 priv->needs_width_request = FALSE;
8337 if (!priv->min_width_set)
8338 request_min_width = cached_size_request->min_size;
8340 request_min_width = info->margin.left
8341 + info->minimum.width
8342 + info->margin.right;
8344 if (!priv->natural_width_set)
8345 request_natural_width = cached_size_request->natural_size;
8347 request_natural_width = info->margin.left
8348 + info->natural.width
8349 + info->margin.right;
8352 *min_width_p = request_min_width;
8354 if (natural_width_p)
8355 *natural_width_p = request_natural_width;
8359 * clutter_actor_get_preferred_height:
8360 * @self: A #ClutterActor
8361 * @for_width: available width to assume in computing desired height,
8362 * or a negative value to indicate that no width is defined
8363 * @min_height_p: (out) (allow-none): return location for minimum height,
8365 * @natural_height_p: (out) (allow-none): return location for natural
8368 * Computes the requested minimum and natural heights for an actor,
8369 * or if they are already computed, returns the cached values.
8371 * An actor may not get its request - depending on the layout
8372 * manager that's in effect.
8374 * A request should not incorporate the actor's scale or anchor point;
8375 * those transformations do not affect layout, only rendering.
8380 clutter_actor_get_preferred_height (ClutterActor *self,
8382 gfloat *min_height_p,
8383 gfloat *natural_height_p)
8385 float request_min_height, request_natural_height;
8386 SizeRequest *cached_size_request;
8387 const ClutterLayoutInfo *info;
8388 ClutterActorPrivate *priv;
8389 gboolean found_in_cache;
8391 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8395 info = _clutter_actor_get_layout_info_or_defaults (self);
8397 /* we shortcircuit the case of a fixed size set using set_height() */
8398 if (priv->min_height_set && priv->natural_height_set)
8400 if (min_height_p != NULL)
8401 *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8403 if (natural_height_p != NULL)
8404 *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8409 /* the remaining cases are:
8411 * - either min_height or natural_height have been set
8412 * - neither min_height or natural_height have been set
8414 * in both cases, we go through the cache (and through the actor in case
8415 * of cache misses) and determine the authoritative value depending on
8419 if (!priv->needs_height_request)
8422 _clutter_actor_get_cached_size_request (for_width,
8423 priv->height_requests,
8424 &cached_size_request);
8428 found_in_cache = FALSE;
8429 cached_size_request = &priv->height_requests[0];
8432 if (!found_in_cache)
8434 gfloat minimum_height, natural_height;
8435 ClutterActorClass *klass;
8437 minimum_height = natural_height = 0;
8439 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8441 /* adjust for margin */
8444 for_width -= (info->margin.left + info->margin.right);
8449 klass = CLUTTER_ACTOR_GET_CLASS (self);
8450 klass->get_preferred_height (self, for_width,
8454 /* adjust for margin */
8455 minimum_height += (info->margin.top + info->margin.bottom);
8456 natural_height += (info->margin.top + info->margin.bottom);
8458 /* Due to accumulated float errors, it's better not to warn
8459 * on this, but just fix it.
8461 if (natural_height < minimum_height)
8462 natural_height = minimum_height;
8464 cached_size_request->min_size = minimum_height;
8465 cached_size_request->natural_size = natural_height;
8466 cached_size_request->for_size = for_width;
8467 cached_size_request->age = priv->cached_height_age;
8469 priv->cached_height_age += 1;
8470 priv->needs_height_request = FALSE;
8473 if (!priv->min_height_set)
8474 request_min_height = cached_size_request->min_size;
8476 request_min_height = info->margin.top
8477 + info->minimum.height
8478 + info->margin.bottom;
8480 if (!priv->natural_height_set)
8481 request_natural_height = cached_size_request->natural_size;
8483 request_natural_height = info->margin.top
8484 + info->natural.height
8485 + info->margin.bottom;
8488 *min_height_p = request_min_height;
8490 if (natural_height_p)
8491 *natural_height_p = request_natural_height;
8495 * clutter_actor_get_allocation_box:
8496 * @self: A #ClutterActor
8497 * @box: (out): the function fills this in with the actor's allocation
8499 * Gets the layout box an actor has been assigned. The allocation can
8500 * only be assumed valid inside a paint() method; anywhere else, it
8501 * may be out-of-date.
8503 * An allocation does not incorporate the actor's scale or anchor point;
8504 * those transformations do not affect layout, only rendering.
8506 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8507 * of functions inside the implementation of the get_preferred_width()
8508 * or get_preferred_height() virtual functions.</note>
8513 clutter_actor_get_allocation_box (ClutterActor *self,
8514 ClutterActorBox *box)
8516 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8518 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8519 * which limits calling get_allocation to inside paint() basically; or
8520 * we can 2) force a layout, which could be expensive if someone calls
8521 * get_allocation somewhere silly; or we can 3) just return the latest
8522 * value, allowing it to be out-of-date, and assume people know what
8525 * The least-surprises approach that keeps existing code working is
8526 * likely to be 2). People can end up doing some inefficient things,
8527 * though, and in general code that requires 2) is probably broken.
8530 /* this implements 2) */
8531 if (G_UNLIKELY (self->priv->needs_allocation))
8533 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8535 /* do not queue a relayout on an unparented actor */
8537 _clutter_stage_maybe_relayout (stage);
8540 /* commenting out the code above and just keeping this assigment
8543 *box = self->priv->allocation;
8547 * clutter_actor_get_allocation_geometry:
8548 * @self: A #ClutterActor
8549 * @geom: (out): allocation geometry in pixels
8551 * Gets the layout box an actor has been assigned. The allocation can
8552 * only be assumed valid inside a paint() method; anywhere else, it
8553 * may be out-of-date.
8555 * An allocation does not incorporate the actor's scale or anchor point;
8556 * those transformations do not affect layout, only rendering.
8558 * The returned rectangle is in pixels.
8563 clutter_actor_get_allocation_geometry (ClutterActor *self,
8564 ClutterGeometry *geom)
8566 ClutterActorBox box;
8568 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8569 g_return_if_fail (geom != NULL);
8571 clutter_actor_get_allocation_box (self, &box);
8573 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8574 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8575 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8576 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8580 clutter_actor_update_constraints (ClutterActor *self,
8581 ClutterActorBox *allocation)
8583 ClutterActorPrivate *priv = self->priv;
8584 const GList *constraints, *l;
8586 if (priv->constraints == NULL)
8589 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8590 for (l = constraints; l != NULL; l = l->next)
8592 ClutterConstraint *constraint = l->data;
8593 ClutterActorMeta *meta = l->data;
8595 if (clutter_actor_meta_get_enabled (meta))
8597 _clutter_constraint_update_allocation (constraint,
8601 CLUTTER_NOTE (LAYOUT,
8602 "Allocation of '%s' after constraint '%s': "
8603 "{ %.2f, %.2f, %.2f, %.2f }",
8604 _clutter_actor_get_debug_name (self),
8605 _clutter_actor_meta_get_debug_name (meta),
8615 * clutter_actor_adjust_allocation:
8616 * @self: a #ClutterActor
8617 * @allocation: (inout): the allocation to adjust
8619 * Adjusts the passed allocation box taking into account the actor's
8620 * layout information, like alignment, expansion, and margin.
8623 clutter_actor_adjust_allocation (ClutterActor *self,
8624 ClutterActorBox *allocation)
8626 ClutterActorBox adj_allocation;
8627 float alloc_width, alloc_height;
8628 float min_width, min_height;
8629 float nat_width, nat_height;
8630 ClutterRequestMode req_mode;
8632 adj_allocation = *allocation;
8634 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8636 /* we want to hit the cache, so we use the public API */
8637 req_mode = clutter_actor_get_request_mode (self);
8639 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8641 clutter_actor_get_preferred_width (self, -1,
8644 clutter_actor_get_preferred_height (self, alloc_width,
8648 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8650 clutter_actor_get_preferred_height (self, -1,
8653 clutter_actor_get_preferred_width (self, alloc_height,
8658 #ifdef CLUTTER_ENABLE_DEBUG
8659 /* warn about underallocations */
8660 if (_clutter_diagnostic_enabled () &&
8661 (floorf (min_width - alloc_width) > 0 ||
8662 floorf (min_height - alloc_height) > 0))
8664 ClutterActor *parent = clutter_actor_get_parent (self);
8666 /* the only actors that are allowed to be underallocated are the Stage,
8667 * as it doesn't have an implicit size, and Actors that specifically
8668 * told us that they want to opt-out from layout control mechanisms
8669 * through the NO_LAYOUT escape hatch.
8671 if (parent != NULL &&
8672 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8674 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8675 "of %.2f x %.2f from its parent actor '%s', but its "
8676 "requested minimum size is of %.2f x %.2f",
8677 _clutter_actor_get_debug_name (self),
8678 alloc_width, alloc_height,
8679 _clutter_actor_get_debug_name (parent),
8680 min_width, min_height);
8685 clutter_actor_adjust_width (self,
8689 &adj_allocation.x2);
8691 clutter_actor_adjust_height (self,
8695 &adj_allocation.y2);
8697 /* we maintain the invariant that an allocation cannot be adjusted
8698 * to be outside the parent-given box
8700 if (adj_allocation.x1 < allocation->x1 ||
8701 adj_allocation.y1 < allocation->y1 ||
8702 adj_allocation.x2 > allocation->x2 ||
8703 adj_allocation.y2 > allocation->y2)
8705 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8706 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8707 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8708 _clutter_actor_get_debug_name (self),
8709 adj_allocation.x1, adj_allocation.y1,
8710 adj_allocation.x2 - adj_allocation.x1,
8711 adj_allocation.y2 - adj_allocation.y1,
8712 allocation->x1, allocation->y1,
8713 allocation->x2 - allocation->x1,
8714 allocation->y2 - allocation->y1);
8718 *allocation = adj_allocation;
8722 clutter_actor_allocate_internal (ClutterActor *self,
8723 const ClutterActorBox *allocation,
8724 ClutterAllocationFlags flags)
8726 ClutterActorClass *klass;
8728 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8730 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8731 _clutter_actor_get_debug_name (self));
8733 klass = CLUTTER_ACTOR_GET_CLASS (self);
8734 klass->allocate (self, allocation, flags);
8736 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8738 clutter_actor_queue_redraw (self);
8742 * clutter_actor_allocate:
8743 * @self: A #ClutterActor
8744 * @box: new allocation of the actor, in parent-relative coordinates
8745 * @flags: flags that control the allocation
8747 * Called by the parent of an actor to assign the actor its size.
8748 * Should never be called by applications (except when implementing
8749 * a container or layout manager).
8751 * Actors can know from their allocation box whether they have moved
8752 * with respect to their parent actor. The @flags parameter describes
8753 * additional information about the allocation, for instance whether
8754 * the parent has moved with respect to the stage, for example because
8755 * a grandparent's origin has moved.
8760 clutter_actor_allocate (ClutterActor *self,
8761 const ClutterActorBox *box,
8762 ClutterAllocationFlags flags)
8764 ClutterActorBox old_allocation, real_allocation;
8765 gboolean origin_changed, child_moved, size_changed;
8766 gboolean stage_allocation_changed;
8767 ClutterActorPrivate *priv;
8769 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8770 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8772 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8773 "which isn't a descendent of the stage!\n",
8774 self, _clutter_actor_get_debug_name (self));
8780 old_allocation = priv->allocation;
8781 real_allocation = *box;
8783 /* constraints are allowed to modify the allocation only here; we do
8784 * this prior to all the other checks so that we can bail out if the
8785 * allocation did not change
8787 clutter_actor_update_constraints (self, &real_allocation);
8789 /* adjust the allocation depending on the align/margin properties */
8790 clutter_actor_adjust_allocation (self, &real_allocation);
8792 if (real_allocation.x2 < real_allocation.x1 ||
8793 real_allocation.y2 < real_allocation.y1)
8795 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8796 _clutter_actor_get_debug_name (self),
8797 real_allocation.x2 - real_allocation.x1,
8798 real_allocation.y2 - real_allocation.y1);
8801 /* we allow 0-sized actors, but not negative-sized ones */
8802 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8803 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8805 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8807 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8808 real_allocation.y1 != old_allocation.y1);
8810 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8811 real_allocation.y2 != old_allocation.y2);
8813 if (origin_changed || child_moved || size_changed)
8814 stage_allocation_changed = TRUE;
8816 stage_allocation_changed = FALSE;
8818 /* If we get an allocation "out of the blue"
8819 * (we did not queue relayout), then we want to
8820 * ignore it. But if we have needs_allocation set,
8821 * we want to guarantee that allocate() virtual
8822 * method is always called, i.e. that queue_relayout()
8823 * always results in an allocate() invocation on
8826 * The optimization here is to avoid re-allocating
8827 * actors that did not queue relayout and were
8830 if (!priv->needs_allocation && !stage_allocation_changed)
8832 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8836 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8837 * clutter_actor_allocate(), it indicates whether the parent has its
8838 * absolute origin moved; when passed in to ClutterActor::allocate()
8839 * virtual method though, it indicates whether the child has its
8840 * absolute origin moved. So we set it when child_moved is TRUE
8843 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8845 /* store the flags here, so that they can be propagated by the
8848 self->priv->allocation_flags = flags;
8850 if (_clutter_actor_get_transition (self, obj_props[PROP_ALLOCATION]) == NULL)
8852 _clutter_actor_create_transition (self, obj_props[PROP_ALLOCATION],
8857 _clutter_actor_update_transition (self, obj_props[PROP_ALLOCATION],
8862 * clutter_actor_set_allocation:
8863 * @self: a #ClutterActor
8864 * @box: a #ClutterActorBox
8865 * @flags: allocation flags
8867 * Stores the allocation of @self as defined by @box.
8869 * This function can only be called from within the implementation of
8870 * the #ClutterActorClass.allocate() virtual function.
8872 * The allocation should have been adjusted to take into account constraints,
8873 * alignment, and margin properties. If you are implementing a #ClutterActor
8874 * subclass that provides its own layout management policy for its children
8875 * instead of using a #ClutterLayoutManager delegate, you should not call
8876 * this function on the children of @self; instead, you should call
8877 * clutter_actor_allocate(), which will adjust the allocation box for
8880 * This function should only be used by subclasses of #ClutterActor
8881 * that wish to store their allocation but cannot chain up to the
8882 * parent's implementation; the default implementation of the
8883 * #ClutterActorClass.allocate() virtual function will call this
8886 * It is important to note that, while chaining up was the recommended
8887 * behaviour for #ClutterActor subclasses prior to the introduction of
8888 * this function, it is recommended to call clutter_actor_set_allocation()
8891 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8892 * to handle the allocation of its children, this function will call
8893 * the clutter_layout_manager_allocate() function only if the
8894 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8895 * expected that the subclass will call clutter_layout_manager_allocate()
8896 * by itself. For instance, the following code:
8900 * my_actor_allocate (ClutterActor *actor,
8901 * const ClutterActorBox *allocation,
8902 * ClutterAllocationFlags flags)
8904 * ClutterActorBox new_alloc;
8905 * ClutterAllocationFlags new_flags;
8907 * adjust_allocation (allocation, &new_alloc);
8909 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8911 * /* this will use the layout manager set on the actor */
8912 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8916 * is equivalent to this:
8920 * my_actor_allocate (ClutterActor *actor,
8921 * const ClutterActorBox *allocation,
8922 * ClutterAllocationFlags flags)
8924 * ClutterLayoutManager *layout;
8925 * ClutterActorBox new_alloc;
8927 * adjust_allocation (allocation, &new_alloc);
8929 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8931 * layout = clutter_actor_get_layout_manager (actor);
8932 * clutter_layout_manager_allocate (layout,
8933 * CLUTTER_CONTAINER (actor),
8942 clutter_actor_set_allocation (ClutterActor *self,
8943 const ClutterActorBox *box,
8944 ClutterAllocationFlags flags)
8946 ClutterActorPrivate *priv;
8949 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8950 g_return_if_fail (box != NULL);
8952 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8954 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8955 "can only be called from within the implementation of "
8956 "the ClutterActor::allocate() virtual function.");
8962 g_object_freeze_notify (G_OBJECT (self));
8964 changed = clutter_actor_set_allocation_internal (self, box, flags);
8966 /* we allocate our children before we notify changes in our geometry,
8967 * so that people connecting to properties will be able to get valid
8968 * data out of the sub-tree of the scene graph that has this actor at
8971 clutter_actor_maybe_layout_children (self, box, flags);
8975 ClutterActorBox signal_box = priv->allocation;
8976 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8978 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8983 g_object_thaw_notify (G_OBJECT (self));
8987 * clutter_actor_set_geometry:
8988 * @self: A #ClutterActor
8989 * @geometry: A #ClutterGeometry
8991 * Sets the actor's fixed position and forces its minimum and natural
8992 * size, in pixels. This means the untransformed actor will have the
8993 * given geometry. This is the same as calling clutter_actor_set_position()
8994 * and clutter_actor_set_size().
8996 * Deprecated: 1.10: Use clutter_actor_set_position() and
8997 * clutter_actor_set_size() instead.
9000 clutter_actor_set_geometry (ClutterActor *self,
9001 const ClutterGeometry *geometry)
9003 g_object_freeze_notify (G_OBJECT (self));
9005 clutter_actor_set_position (self, geometry->x, geometry->y);
9006 clutter_actor_set_size (self, geometry->width, geometry->height);
9008 g_object_thaw_notify (G_OBJECT (self));
9012 * clutter_actor_get_geometry:
9013 * @self: A #ClutterActor
9014 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
9016 * Gets the size and position of an actor relative to its parent
9017 * actor. This is the same as calling clutter_actor_get_position() and
9018 * clutter_actor_get_size(). It tries to "do what you mean" and get the
9019 * requested size and position if the actor's allocation is invalid.
9021 * Deprecated: 1.10: Use clutter_actor_get_position() and
9022 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
9026 clutter_actor_get_geometry (ClutterActor *self,
9027 ClutterGeometry *geometry)
9029 gfloat x, y, width, height;
9031 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9032 g_return_if_fail (geometry != NULL);
9034 clutter_actor_get_position (self, &x, &y);
9035 clutter_actor_get_size (self, &width, &height);
9037 geometry->x = (int) x;
9038 geometry->y = (int) y;
9039 geometry->width = (int) width;
9040 geometry->height = (int) height;
9044 * clutter_actor_set_position:
9045 * @self: A #ClutterActor
9046 * @x: New left position of actor in pixels.
9047 * @y: New top position of actor in pixels.
9049 * Sets the actor's fixed position in pixels relative to any parent
9052 * If a layout manager is in use, this position will override the
9053 * layout manager and force a fixed position.
9056 clutter_actor_set_position (ClutterActor *self,
9060 ClutterPoint new_position;
9062 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9064 clutter_point_init (&new_position, x, y);
9066 if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
9068 ClutterPoint cur_position;
9070 cur_position.x = clutter_actor_get_x (self);
9071 cur_position.y = clutter_actor_get_y (self);
9073 _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
9078 _clutter_actor_update_transition (self,
9079 obj_props[PROP_POSITION],
9082 clutter_actor_queue_relayout (self);
9086 * clutter_actor_get_fixed_position_set:
9087 * @self: A #ClutterActor
9089 * Checks whether an actor has a fixed position set (and will thus be
9090 * unaffected by any layout manager).
9092 * Return value: %TRUE if the fixed position is set on the actor
9097 clutter_actor_get_fixed_position_set (ClutterActor *self)
9099 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9101 return self->priv->position_set;
9105 * clutter_actor_set_fixed_position_set:
9106 * @self: A #ClutterActor
9107 * @is_set: whether to use fixed position
9109 * Sets whether an actor has a fixed position set (and will thus be
9110 * unaffected by any layout manager).
9115 clutter_actor_set_fixed_position_set (ClutterActor *self,
9118 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9120 if (self->priv->position_set == (is_set != FALSE))
9123 self->priv->position_set = is_set != FALSE;
9124 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9126 clutter_actor_queue_relayout (self);
9130 * clutter_actor_move_by:
9131 * @self: A #ClutterActor
9132 * @dx: Distance to move Actor on X axis.
9133 * @dy: Distance to move Actor on Y axis.
9135 * Moves an actor by the specified distance relative to its current
9136 * position in pixels.
9138 * This function modifies the fixed position of an actor and thus removes
9139 * it from any layout management. Another way to move an actor is with an
9140 * anchor point, see clutter_actor_set_anchor_point().
9145 clutter_actor_move_by (ClutterActor *self,
9149 const ClutterLayoutInfo *info;
9152 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9154 info = _clutter_actor_get_layout_info_or_defaults (self);
9155 x = info->fixed_pos.x;
9156 y = info->fixed_pos.y;
9158 clutter_actor_set_position (self, x + dx, y + dy);
9162 clutter_actor_set_min_width (ClutterActor *self,
9165 ClutterActorPrivate *priv = self->priv;
9166 ClutterActorBox old = { 0, };
9167 ClutterLayoutInfo *info;
9169 /* if we are setting the size on a top-level actor and the
9170 * backend only supports static top-levels (e.g. framebuffers)
9171 * then we ignore the passed value and we override it with
9172 * the stage implementation's preferred size.
9174 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9175 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9178 info = _clutter_actor_get_layout_info (self);
9180 if (priv->min_width_set && min_width == info->minimum.width)
9183 g_object_freeze_notify (G_OBJECT (self));
9185 clutter_actor_store_old_geometry (self, &old);
9187 info->minimum.width = min_width;
9188 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9189 clutter_actor_set_min_width_set (self, TRUE);
9191 clutter_actor_notify_if_geometry_changed (self, &old);
9193 g_object_thaw_notify (G_OBJECT (self));
9195 clutter_actor_queue_relayout (self);
9199 clutter_actor_set_min_height (ClutterActor *self,
9203 ClutterActorPrivate *priv = self->priv;
9204 ClutterActorBox old = { 0, };
9205 ClutterLayoutInfo *info;
9207 /* if we are setting the size on a top-level actor and the
9208 * backend only supports static top-levels (e.g. framebuffers)
9209 * then we ignore the passed value and we override it with
9210 * the stage implementation's preferred size.
9212 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9213 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9216 info = _clutter_actor_get_layout_info (self);
9218 if (priv->min_height_set && min_height == info->minimum.height)
9221 g_object_freeze_notify (G_OBJECT (self));
9223 clutter_actor_store_old_geometry (self, &old);
9225 info->minimum.height = min_height;
9226 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9227 clutter_actor_set_min_height_set (self, TRUE);
9229 clutter_actor_notify_if_geometry_changed (self, &old);
9231 g_object_thaw_notify (G_OBJECT (self));
9233 clutter_actor_queue_relayout (self);
9237 clutter_actor_set_natural_width (ClutterActor *self,
9238 gfloat natural_width)
9240 ClutterActorPrivate *priv = self->priv;
9241 ClutterActorBox old = { 0, };
9242 ClutterLayoutInfo *info;
9244 /* if we are setting the size on a top-level actor and the
9245 * backend only supports static top-levels (e.g. framebuffers)
9246 * then we ignore the passed value and we override it with
9247 * the stage implementation's preferred size.
9249 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9250 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9253 info = _clutter_actor_get_layout_info (self);
9255 if (priv->natural_width_set && natural_width == info->natural.width)
9258 g_object_freeze_notify (G_OBJECT (self));
9260 clutter_actor_store_old_geometry (self, &old);
9262 info->natural.width = natural_width;
9263 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9264 clutter_actor_set_natural_width_set (self, TRUE);
9266 clutter_actor_notify_if_geometry_changed (self, &old);
9268 g_object_thaw_notify (G_OBJECT (self));
9270 clutter_actor_queue_relayout (self);
9274 clutter_actor_set_natural_height (ClutterActor *self,
9275 gfloat natural_height)
9277 ClutterActorPrivate *priv = self->priv;
9278 ClutterActorBox old = { 0, };
9279 ClutterLayoutInfo *info;
9281 /* if we are setting the size on a top-level actor and the
9282 * backend only supports static top-levels (e.g. framebuffers)
9283 * then we ignore the passed value and we override it with
9284 * the stage implementation's preferred size.
9286 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9287 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9290 info = _clutter_actor_get_layout_info (self);
9292 if (priv->natural_height_set && natural_height == info->natural.height)
9295 g_object_freeze_notify (G_OBJECT (self));
9297 clutter_actor_store_old_geometry (self, &old);
9299 info->natural.height = natural_height;
9300 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9301 clutter_actor_set_natural_height_set (self, TRUE);
9303 clutter_actor_notify_if_geometry_changed (self, &old);
9305 g_object_thaw_notify (G_OBJECT (self));
9307 clutter_actor_queue_relayout (self);
9311 clutter_actor_set_min_width_set (ClutterActor *self,
9312 gboolean use_min_width)
9314 ClutterActorPrivate *priv = self->priv;
9315 ClutterActorBox old = { 0, };
9317 if (priv->min_width_set == (use_min_width != FALSE))
9320 clutter_actor_store_old_geometry (self, &old);
9322 priv->min_width_set = use_min_width != FALSE;
9323 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9325 clutter_actor_notify_if_geometry_changed (self, &old);
9327 clutter_actor_queue_relayout (self);
9331 clutter_actor_set_min_height_set (ClutterActor *self,
9332 gboolean use_min_height)
9334 ClutterActorPrivate *priv = self->priv;
9335 ClutterActorBox old = { 0, };
9337 if (priv->min_height_set == (use_min_height != FALSE))
9340 clutter_actor_store_old_geometry (self, &old);
9342 priv->min_height_set = use_min_height != FALSE;
9343 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9345 clutter_actor_notify_if_geometry_changed (self, &old);
9347 clutter_actor_queue_relayout (self);
9351 clutter_actor_set_natural_width_set (ClutterActor *self,
9352 gboolean use_natural_width)
9354 ClutterActorPrivate *priv = self->priv;
9355 ClutterActorBox old = { 0, };
9357 if (priv->natural_width_set == (use_natural_width != FALSE))
9360 clutter_actor_store_old_geometry (self, &old);
9362 priv->natural_width_set = use_natural_width != FALSE;
9363 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9365 clutter_actor_notify_if_geometry_changed (self, &old);
9367 clutter_actor_queue_relayout (self);
9371 clutter_actor_set_natural_height_set (ClutterActor *self,
9372 gboolean use_natural_height)
9374 ClutterActorPrivate *priv = self->priv;
9375 ClutterActorBox old = { 0, };
9377 if (priv->natural_height_set == (use_natural_height != FALSE))
9380 clutter_actor_store_old_geometry (self, &old);
9382 priv->natural_height_set = use_natural_height != FALSE;
9383 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9385 clutter_actor_notify_if_geometry_changed (self, &old);
9387 clutter_actor_queue_relayout (self);
9391 * clutter_actor_set_request_mode:
9392 * @self: a #ClutterActor
9393 * @mode: the request mode
9395 * Sets the geometry request mode of @self.
9397 * The @mode determines the order for invoking
9398 * clutter_actor_get_preferred_width() and
9399 * clutter_actor_get_preferred_height()
9404 clutter_actor_set_request_mode (ClutterActor *self,
9405 ClutterRequestMode mode)
9407 ClutterActorPrivate *priv;
9409 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9413 if (priv->request_mode == mode)
9416 priv->request_mode = mode;
9418 priv->needs_width_request = TRUE;
9419 priv->needs_height_request = TRUE;
9421 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9423 clutter_actor_queue_relayout (self);
9427 * clutter_actor_get_request_mode:
9428 * @self: a #ClutterActor
9430 * Retrieves the geometry request mode of @self
9432 * Return value: the request mode for the actor
9437 clutter_actor_get_request_mode (ClutterActor *self)
9439 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9440 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9442 return self->priv->request_mode;
9445 /* variant of set_width() without checks and without notification
9446 * freeze+thaw, for internal usage only
9449 clutter_actor_set_width_internal (ClutterActor *self,
9454 /* the Stage will use the :min-width to control the minimum
9455 * width to be resized to, so we should not be setting it
9456 * along with the :natural-width
9458 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9459 clutter_actor_set_min_width (self, width);
9461 clutter_actor_set_natural_width (self, width);
9465 /* we only unset the :natural-width for the Stage */
9466 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9467 clutter_actor_set_min_width_set (self, FALSE);
9469 clutter_actor_set_natural_width_set (self, FALSE);
9473 /* variant of set_height() without checks and without notification
9474 * freeze+thaw, for internal usage only
9477 clutter_actor_set_height_internal (ClutterActor *self,
9482 /* see the comment above in set_width_internal() */
9483 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9484 clutter_actor_set_min_height (self, height);
9486 clutter_actor_set_natural_height (self, height);
9490 /* see the comment above in set_width_internal() */
9491 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9492 clutter_actor_set_min_height_set (self, FALSE);
9494 clutter_actor_set_natural_height_set (self, FALSE);
9499 clutter_actor_set_size_internal (ClutterActor *self,
9500 const ClutterSize *size)
9504 clutter_actor_set_width_internal (self, size->width);
9505 clutter_actor_set_height_internal (self, size->height);
9509 clutter_actor_set_width_internal (self, -1);
9510 clutter_actor_set_height_internal (self, -1);
9515 * clutter_actor_set_size:
9516 * @self: A #ClutterActor
9517 * @width: New width of actor in pixels, or -1
9518 * @height: New height of actor in pixels, or -1
9520 * Sets the actor's size request in pixels. This overrides any
9521 * "normal" size request the actor would have. For example
9522 * a text actor might normally request the size of the text;
9523 * this function would force a specific size instead.
9525 * If @width and/or @height are -1 the actor will use its
9526 * "normal" size request instead of overriding it, i.e.
9527 * you can "unset" the size with -1.
9529 * This function sets or unsets both the minimum and natural size.
9532 clutter_actor_set_size (ClutterActor *self,
9536 ClutterSize new_size;
9538 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9540 clutter_size_init (&new_size, width, height);
9542 if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9544 /* minor optimization: if we don't have a duration then we can
9545 * skip the get_size() below, to avoid the chance of going through
9546 * get_preferred_width() and get_preferred_height() just to jump to
9547 * a new desired size
9549 if (clutter_actor_get_easing_duration (self) == 0)
9551 g_object_freeze_notify (G_OBJECT (self));
9553 clutter_actor_set_size_internal (self, &new_size);
9555 g_object_thaw_notify (G_OBJECT (self));
9561 ClutterSize cur_size;
9563 clutter_size_init (&cur_size,
9564 clutter_actor_get_width (self),
9565 clutter_actor_get_height (self));
9567 _clutter_actor_create_transition (self,
9568 obj_props[PROP_SIZE],
9574 _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9576 clutter_actor_queue_relayout (self);
9580 * clutter_actor_get_size:
9581 * @self: A #ClutterActor
9582 * @width: (out) (allow-none): return location for the width, or %NULL.
9583 * @height: (out) (allow-none): return location for the height, or %NULL.
9585 * This function tries to "do what you mean" and return
9586 * the size an actor will have. If the actor has a valid
9587 * allocation, the allocation will be returned; otherwise,
9588 * the actors natural size request will be returned.
9590 * If you care whether you get the request vs. the allocation, you
9591 * should probably call a different function like
9592 * clutter_actor_get_allocation_box() or
9593 * clutter_actor_get_preferred_width().
9598 clutter_actor_get_size (ClutterActor *self,
9602 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9605 *width = clutter_actor_get_width (self);
9608 *height = clutter_actor_get_height (self);
9612 * clutter_actor_get_position:
9613 * @self: a #ClutterActor
9614 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9615 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9617 * This function tries to "do what you mean" and tell you where the
9618 * actor is, prior to any transformations. Retrieves the fixed
9619 * position of an actor in pixels, if one has been set; otherwise, if
9620 * the allocation is valid, returns the actor's allocated position;
9621 * otherwise, returns 0,0.
9623 * The returned position is in pixels.
9628 clutter_actor_get_position (ClutterActor *self,
9632 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9635 *x = clutter_actor_get_x (self);
9638 *y = clutter_actor_get_y (self);
9642 * clutter_actor_get_transformed_position:
9643 * @self: A #ClutterActor
9644 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9645 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9647 * Gets the absolute position of an actor, in pixels relative to the stage.
9652 clutter_actor_get_transformed_position (ClutterActor *self,
9659 v1.x = v1.y = v1.z = 0;
9660 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9670 * clutter_actor_get_transformed_size:
9671 * @self: A #ClutterActor
9672 * @width: (out) (allow-none): return location for the width, or %NULL
9673 * @height: (out) (allow-none): return location for the height, or %NULL
9675 * Gets the absolute size of an actor in pixels, taking into account the
9678 * If the actor has a valid allocation, the allocated size will be used.
9679 * If the actor has not a valid allocation then the preferred size will
9680 * be transformed and returned.
9682 * If you want the transformed allocation, see
9683 * clutter_actor_get_abs_allocation_vertices() instead.
9685 * <note>When the actor (or one of its ancestors) is rotated around the
9686 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9687 * as a generic quadrangle; in that case this function returns the size
9688 * of the smallest rectangle that encapsulates the entire quad. Please
9689 * note that in this case no assumptions can be made about the relative
9690 * position of this envelope to the absolute position of the actor, as
9691 * returned by clutter_actor_get_transformed_position(); if you need this
9692 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9693 * to get the coords of the actual quadrangle.</note>
9698 clutter_actor_get_transformed_size (ClutterActor *self,
9702 ClutterActorPrivate *priv;
9704 gfloat x_min, x_max, y_min, y_max;
9707 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9711 /* if the actor hasn't been allocated yet, get the preferred
9712 * size and transform that
9714 if (priv->needs_allocation)
9716 gfloat natural_width, natural_height;
9717 ClutterActorBox box;
9719 /* Make a fake allocation to transform.
9721 * NB: _clutter_actor_transform_and_project_box expects a box in
9722 * the actor's coordinate space... */
9727 natural_width = natural_height = 0;
9728 clutter_actor_get_preferred_size (self, NULL, NULL,
9732 box.x2 = natural_width;
9733 box.y2 = natural_height;
9735 _clutter_actor_transform_and_project_box (self, &box, v);
9738 clutter_actor_get_abs_allocation_vertices (self, v);
9740 x_min = x_max = v[0].x;
9741 y_min = y_max = v[0].y;
9743 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9759 *width = x_max - x_min;
9762 *height = y_max - y_min;
9766 * clutter_actor_get_width:
9767 * @self: A #ClutterActor
9769 * Retrieves the width of a #ClutterActor.
9771 * If the actor has a valid allocation, this function will return the
9772 * width of the allocated area given to the actor.
9774 * If the actor does not have a valid allocation, this function will
9775 * return the actor's natural width, that is the preferred width of
9778 * If you care whether you get the preferred width or the width that
9779 * has been assigned to the actor, you should probably call a different
9780 * function like clutter_actor_get_allocation_box() to retrieve the
9781 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9784 * If an actor has a fixed width, for instance a width that has been
9785 * assigned using clutter_actor_set_width(), the width returned will
9786 * be the same value.
9788 * Return value: the width of the actor, in pixels
9791 clutter_actor_get_width (ClutterActor *self)
9793 ClutterActorPrivate *priv;
9795 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9799 if (priv->needs_allocation)
9801 gfloat natural_width = 0;
9803 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9804 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9807 gfloat natural_height = 0;
9809 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9810 clutter_actor_get_preferred_width (self, natural_height,
9815 return natural_width;
9818 return priv->allocation.x2 - priv->allocation.x1;
9822 * clutter_actor_get_height:
9823 * @self: A #ClutterActor
9825 * Retrieves the height of a #ClutterActor.
9827 * If the actor has a valid allocation, this function will return the
9828 * height of the allocated area given to the actor.
9830 * If the actor does not have a valid allocation, this function will
9831 * return the actor's natural height, that is the preferred height of
9834 * If you care whether you get the preferred height or the height that
9835 * has been assigned to the actor, you should probably call a different
9836 * function like clutter_actor_get_allocation_box() to retrieve the
9837 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9840 * If an actor has a fixed height, for instance a height that has been
9841 * assigned using clutter_actor_set_height(), the height returned will
9842 * be the same value.
9844 * Return value: the height of the actor, in pixels
9847 clutter_actor_get_height (ClutterActor *self)
9849 ClutterActorPrivate *priv;
9851 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9855 if (priv->needs_allocation)
9857 gfloat natural_height = 0;
9859 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9861 gfloat natural_width = 0;
9863 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9864 clutter_actor_get_preferred_height (self, natural_width,
9865 NULL, &natural_height);
9868 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9870 return natural_height;
9873 return priv->allocation.y2 - priv->allocation.y1;
9877 * clutter_actor_set_width:
9878 * @self: A #ClutterActor
9879 * @width: Requested new width for the actor, in pixels, or -1
9881 * Forces a width on an actor, causing the actor's preferred width
9882 * and height (if any) to be ignored.
9884 * If @width is -1 the actor will use its preferred width request
9885 * instead of overriding it, i.e. you can "unset" the width with -1.
9887 * This function sets both the minimum and natural size of the actor.
9892 clutter_actor_set_width (ClutterActor *self,
9895 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9897 if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9901 /* minor optimization: if we don't have a duration
9902 * then we can skip the get_width() below, to avoid
9903 * the chance of going through get_preferred_width()
9904 * just to jump to a new desired width.
9906 if (clutter_actor_get_easing_duration (self) == 0)
9908 g_object_freeze_notify (G_OBJECT (self));
9910 clutter_actor_set_width_internal (self, width);
9912 g_object_thaw_notify (G_OBJECT (self));
9917 cur_size = clutter_actor_get_width (self);
9919 _clutter_actor_create_transition (self,
9920 obj_props[PROP_WIDTH],
9925 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9929 * clutter_actor_set_height:
9930 * @self: A #ClutterActor
9931 * @height: Requested new height for the actor, in pixels, or -1
9933 * Forces a height on an actor, causing the actor's preferred width
9934 * and height (if any) to be ignored.
9936 * If @height is -1 the actor will use its preferred height instead of
9937 * overriding it, i.e. you can "unset" the height with -1.
9939 * This function sets both the minimum and natural size of the actor.
9944 clutter_actor_set_height (ClutterActor *self,
9947 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9949 if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9953 /* see the comment in clutter_actor_set_width() above */
9954 if (clutter_actor_get_easing_duration (self) == 0)
9956 g_object_freeze_notify (G_OBJECT (self));
9958 clutter_actor_set_height_internal (self, height);
9960 g_object_thaw_notify (G_OBJECT (self));
9965 cur_size = clutter_actor_get_height (self);
9967 _clutter_actor_create_transition (self,
9968 obj_props[PROP_HEIGHT],
9973 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9977 clutter_actor_set_x_internal (ClutterActor *self,
9980 ClutterActorPrivate *priv = self->priv;
9981 ClutterLayoutInfo *linfo;
9982 ClutterActorBox old = { 0, };
9984 linfo = _clutter_actor_get_layout_info (self);
9986 if (priv->position_set && linfo->fixed_pos.x == x)
9989 clutter_actor_store_old_geometry (self, &old);
9991 linfo->fixed_pos.x = x;
9992 clutter_actor_set_fixed_position_set (self, TRUE);
9994 clutter_actor_notify_if_geometry_changed (self, &old);
9996 clutter_actor_queue_relayout (self);
10000 clutter_actor_set_y_internal (ClutterActor *self,
10003 ClutterActorPrivate *priv = self->priv;
10004 ClutterLayoutInfo *linfo;
10005 ClutterActorBox old = { 0, };
10007 linfo = _clutter_actor_get_layout_info (self);
10009 if (priv->position_set && linfo->fixed_pos.y == y)
10012 clutter_actor_store_old_geometry (self, &old);
10014 linfo->fixed_pos.y = y;
10015 clutter_actor_set_fixed_position_set (self, TRUE);
10017 clutter_actor_notify_if_geometry_changed (self, &old);
10019 clutter_actor_queue_relayout (self);
10023 clutter_actor_set_position_internal (ClutterActor *self,
10024 const ClutterPoint *position)
10026 ClutterActorPrivate *priv = self->priv;
10027 ClutterLayoutInfo *linfo;
10028 ClutterActorBox old = { 0, };
10030 linfo = _clutter_actor_get_layout_info (self);
10032 if (priv->position_set &&
10033 clutter_point_equals (position, &linfo->fixed_pos))
10036 clutter_actor_store_old_geometry (self, &old);
10038 if (position != NULL)
10040 linfo->fixed_pos = *position;
10041 clutter_actor_set_fixed_position_set (self, TRUE);
10044 clutter_actor_set_fixed_position_set (self, FALSE);
10046 clutter_actor_notify_if_geometry_changed (self, &old);
10048 clutter_actor_queue_relayout (self);
10052 * clutter_actor_set_x:
10053 * @self: a #ClutterActor
10054 * @x: the actor's position on the X axis
10056 * Sets the actor's X coordinate, relative to its parent, in pixels.
10058 * Overrides any layout manager and forces a fixed position for
10061 * The #ClutterActor:x property is animatable.
10066 clutter_actor_set_x (ClutterActor *self,
10069 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10071 if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
10073 float cur_position = clutter_actor_get_x (self);
10075 _clutter_actor_create_transition (self, obj_props[PROP_X],
10080 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
10084 * clutter_actor_set_y:
10085 * @self: a #ClutterActor
10086 * @y: the actor's position on the Y axis
10088 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
10090 * Overrides any layout manager and forces a fixed position for
10093 * The #ClutterActor:y property is animatable.
10098 clutter_actor_set_y (ClutterActor *self,
10101 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10103 if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
10105 float cur_position = clutter_actor_get_y (self);
10107 _clutter_actor_create_transition (self, obj_props[PROP_Y],
10112 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
10116 * clutter_actor_get_x:
10117 * @self: A #ClutterActor
10119 * Retrieves the X coordinate of a #ClutterActor.
10121 * This function tries to "do what you mean", by returning the
10122 * correct value depending on the actor's state.
10124 * If the actor has a valid allocation, this function will return
10125 * the X coordinate of the origin of the allocation box.
10127 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10128 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10129 * function will return that coordinate.
10131 * If both the allocation and a fixed position are missing, this function
10134 * Return value: the X coordinate, in pixels, ignoring any
10135 * transformation (i.e. scaling, rotation)
10138 clutter_actor_get_x (ClutterActor *self)
10140 ClutterActorPrivate *priv;
10142 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10146 if (priv->needs_allocation)
10148 if (priv->position_set)
10150 const ClutterLayoutInfo *info;
10152 info = _clutter_actor_get_layout_info_or_defaults (self);
10154 return info->fixed_pos.x;
10160 return priv->allocation.x1;
10164 * clutter_actor_get_y:
10165 * @self: A #ClutterActor
10167 * Retrieves the Y coordinate of a #ClutterActor.
10169 * This function tries to "do what you mean", by returning the
10170 * correct value depending on the actor's state.
10172 * If the actor has a valid allocation, this function will return
10173 * the Y coordinate of the origin of the allocation box.
10175 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10176 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10177 * function will return that coordinate.
10179 * If both the allocation and a fixed position are missing, this function
10182 * Return value: the Y coordinate, in pixels, ignoring any
10183 * transformation (i.e. scaling, rotation)
10186 clutter_actor_get_y (ClutterActor *self)
10188 ClutterActorPrivate *priv;
10190 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10194 if (priv->needs_allocation)
10196 if (priv->position_set)
10198 const ClutterLayoutInfo *info;
10200 info = _clutter_actor_get_layout_info_or_defaults (self);
10202 return info->fixed_pos.y;
10208 return priv->allocation.y1;
10212 * clutter_actor_set_scale:
10213 * @self: A #ClutterActor
10214 * @scale_x: double factor to scale actor by horizontally.
10215 * @scale_y: double factor to scale actor by vertically.
10217 * Scales an actor with the given factors. The scaling is relative to
10218 * the scale center and the anchor point. The scale center is
10219 * unchanged by this function and defaults to 0,0.
10221 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10227 clutter_actor_set_scale (ClutterActor *self,
10231 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10233 g_object_freeze_notify (G_OBJECT (self));
10235 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10236 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10238 g_object_thaw_notify (G_OBJECT (self));
10242 * clutter_actor_set_scale_full:
10243 * @self: A #ClutterActor
10244 * @scale_x: double factor to scale actor by horizontally.
10245 * @scale_y: double factor to scale actor by vertically.
10246 * @center_x: X coordinate of the center of the scale.
10247 * @center_y: Y coordinate of the center of the scale
10249 * Scales an actor with the given factors around the given center
10250 * point. The center point is specified in pixels relative to the
10251 * anchor point (usually the top left corner of the actor).
10253 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10259 clutter_actor_set_scale_full (ClutterActor *self,
10265 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10267 g_object_freeze_notify (G_OBJECT (self));
10269 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10270 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10271 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10272 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10274 g_object_thaw_notify (G_OBJECT (self));
10278 * clutter_actor_set_scale_with_gravity:
10279 * @self: A #ClutterActor
10280 * @scale_x: double factor to scale actor by horizontally.
10281 * @scale_y: double factor to scale actor by vertically.
10282 * @gravity: the location of the scale center expressed as a compass
10285 * Scales an actor with the given factors around the given
10286 * center point. The center point is specified as one of the compass
10287 * directions in #ClutterGravity. For example, setting it to north
10288 * will cause the top of the actor to remain unchanged and the rest of
10289 * the actor to expand left, right and downwards.
10291 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10297 clutter_actor_set_scale_with_gravity (ClutterActor *self,
10300 ClutterGravity gravity)
10302 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10304 g_object_freeze_notify (G_OBJECT (self));
10306 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10307 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10308 clutter_actor_set_scale_gravity (self, gravity);
10310 g_object_thaw_notify (G_OBJECT (self));
10314 * clutter_actor_get_scale:
10315 * @self: A #ClutterActor
10316 * @scale_x: (out) (allow-none): Location to store horizonal
10317 * scale factor, or %NULL.
10318 * @scale_y: (out) (allow-none): Location to store vertical
10319 * scale factor, or %NULL.
10321 * Retrieves an actors scale factors.
10326 clutter_actor_get_scale (ClutterActor *self,
10330 const ClutterTransformInfo *info;
10332 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10334 info = _clutter_actor_get_transform_info_or_defaults (self);
10337 *scale_x = info->scale_x;
10340 *scale_y = info->scale_y;
10344 * clutter_actor_get_scale_center:
10345 * @self: A #ClutterActor
10346 * @center_x: (out) (allow-none): Location to store the X position
10347 * of the scale center, or %NULL.
10348 * @center_y: (out) (allow-none): Location to store the Y position
10349 * of the scale center, or %NULL.
10351 * Retrieves the scale center coordinate in pixels relative to the top
10352 * left corner of the actor. If the scale center was specified using a
10353 * #ClutterGravity this will calculate the pixel offset using the
10354 * current size of the actor.
10359 clutter_actor_get_scale_center (ClutterActor *self,
10363 const ClutterTransformInfo *info;
10365 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10367 info = _clutter_actor_get_transform_info_or_defaults (self);
10369 clutter_anchor_coord_get_units (self, &info->scale_center,
10376 * clutter_actor_get_scale_gravity:
10377 * @self: A #ClutterActor
10379 * Retrieves the scale center as a compass direction. If the scale
10380 * center was specified in pixels or units this will return
10381 * %CLUTTER_GRAVITY_NONE.
10383 * Return value: the scale gravity
10388 clutter_actor_get_scale_gravity (ClutterActor *self)
10390 const ClutterTransformInfo *info;
10392 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10394 info = _clutter_actor_get_transform_info_or_defaults (self);
10396 return clutter_anchor_coord_get_gravity (&info->scale_center);
10400 clutter_actor_set_opacity_internal (ClutterActor *self,
10403 ClutterActorPrivate *priv = self->priv;
10405 if (priv->opacity != opacity)
10407 priv->opacity = opacity;
10409 /* Queue a redraw from the flatten effect so that it can use
10410 its cached image if available instead of having to redraw the
10411 actual actor. If it doesn't end up using the FBO then the
10412 effect is still able to continue the paint anyway. If there
10413 is no flatten effect yet then this is equivalent to queueing
10415 _clutter_actor_queue_redraw_full (self,
10418 priv->flatten_effect);
10420 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10425 * clutter_actor_set_opacity:
10426 * @self: A #ClutterActor
10427 * @opacity: New opacity value for the actor.
10429 * Sets the actor's opacity, with zero being completely transparent and
10430 * 255 (0xff) being fully opaque.
10432 * The #ClutterActor:opacity property is animatable.
10435 clutter_actor_set_opacity (ClutterActor *self,
10438 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10440 if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10442 _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10443 self->priv->opacity,
10447 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10451 * clutter_actor_get_paint_opacity_internal:
10452 * @self: a #ClutterActor
10454 * Retrieves the absolute opacity of the actor, as it appears on the stage
10456 * This function does not do type checks
10458 * Return value: the absolute opacity of the actor
10461 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10463 ClutterActorPrivate *priv = self->priv;
10464 ClutterActor *parent;
10466 /* override the top-level opacity to always be 255; even in
10467 * case of ClutterStage:use-alpha being TRUE we want the rest
10468 * of the scene to be painted
10470 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10473 if (priv->opacity_override >= 0)
10474 return priv->opacity_override;
10476 parent = priv->parent;
10478 /* Factor in the actual actors opacity with parents */
10479 if (parent != NULL)
10481 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10483 if (opacity != 0xff)
10484 return (opacity * priv->opacity) / 0xff;
10487 return priv->opacity;
10492 * clutter_actor_get_paint_opacity:
10493 * @self: A #ClutterActor
10495 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10497 * This function traverses the hierarchy chain and composites the opacity of
10498 * the actor with that of its parents.
10500 * This function is intended for subclasses to use in the paint virtual
10501 * function, to paint themselves with the correct opacity.
10503 * Return value: The actor opacity value.
10508 clutter_actor_get_paint_opacity (ClutterActor *self)
10510 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10512 return clutter_actor_get_paint_opacity_internal (self);
10516 * clutter_actor_get_opacity:
10517 * @self: a #ClutterActor
10519 * Retrieves the opacity value of an actor, as set by
10520 * clutter_actor_set_opacity().
10522 * For retrieving the absolute opacity of the actor inside a paint
10523 * virtual function, see clutter_actor_get_paint_opacity().
10525 * Return value: the opacity of the actor
10528 clutter_actor_get_opacity (ClutterActor *self)
10530 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10532 return self->priv->opacity;
10536 * clutter_actor_set_offscreen_redirect:
10537 * @self: A #ClutterActor
10538 * @redirect: New offscreen redirect flags for the actor.
10540 * Defines the circumstances where the actor should be redirected into
10541 * an offscreen image. The offscreen image is used to flatten the
10542 * actor into a single image while painting for two main reasons.
10543 * Firstly, when the actor is painted a second time without any of its
10544 * contents changing it can simply repaint the cached image without
10545 * descending further down the actor hierarchy. Secondly, it will make
10546 * the opacity look correct even if there are overlapping primitives
10549 * Caching the actor could in some cases be a performance win and in
10550 * some cases be a performance lose so it is important to determine
10551 * which value is right for an actor before modifying this value. For
10552 * example, there is never any reason to flatten an actor that is just
10553 * a single texture (such as a #ClutterTexture) because it is
10554 * effectively already cached in an image so the offscreen would be
10555 * redundant. Also if the actor contains primitives that are far apart
10556 * with a large transparent area in the middle (such as a large
10557 * CluterGroup with a small actor in the top left and a small actor in
10558 * the bottom right) then the cached image will contain the entire
10559 * image of the large area and the paint will waste time blending all
10560 * of the transparent pixels in the middle.
10562 * The default method of implementing opacity on a container simply
10563 * forwards on the opacity to all of the children. If the children are
10564 * overlapping then it will appear as if they are two separate glassy
10565 * objects and there will be a break in the color where they
10566 * overlap. By redirecting to an offscreen buffer it will be as if the
10567 * two opaque objects are combined into one and then made transparent
10568 * which is usually what is expected.
10570 * The image below demonstrates the difference between redirecting and
10571 * not. The image shows two Clutter groups, each containing a red and
10572 * a green rectangle which overlap. The opacity on the group is set to
10573 * 128 (which is 50%). When the offscreen redirect is not used, the
10574 * red rectangle can be seen through the blue rectangle as if the two
10575 * rectangles were separately transparent. When the redirect is used
10576 * the group as a whole is transparent instead so the red rectangle is
10577 * not visible where they overlap.
10579 * <figure id="offscreen-redirect">
10580 * <title>Sample of using an offscreen redirect for transparency</title>
10581 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10584 * The default value for this property is 0, so we effectively will
10585 * never redirect an actor offscreen by default. This means that there
10586 * are times that transparent actors may look glassy as described
10587 * above. The reason this is the default is because there is a
10588 * performance trade off between quality and performance here. In many
10589 * cases the default form of glassy opacity looks good enough, but if
10590 * it's not you will need to set the
10591 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10592 * redirection for opacity.
10594 * Custom actors that don't contain any overlapping primitives are
10595 * recommended to override the has_overlaps() virtual to return %FALSE
10596 * for maximum efficiency.
10601 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10602 ClutterOffscreenRedirect redirect)
10604 ClutterActorPrivate *priv;
10606 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10610 if (priv->offscreen_redirect != redirect)
10612 priv->offscreen_redirect = redirect;
10614 /* Queue a redraw from the effect so that it can use its cached
10615 image if available instead of having to redraw the actual
10616 actor. If it doesn't end up using the FBO then the effect is
10617 still able to continue the paint anyway. If there is no
10618 effect then this is equivalent to queuing a full redraw */
10619 _clutter_actor_queue_redraw_full (self,
10622 priv->flatten_effect);
10624 g_object_notify_by_pspec (G_OBJECT (self),
10625 obj_props[PROP_OFFSCREEN_REDIRECT]);
10630 * clutter_actor_get_offscreen_redirect:
10631 * @self: a #ClutterActor
10633 * Retrieves whether to redirect the actor to an offscreen buffer, as
10634 * set by clutter_actor_set_offscreen_redirect().
10636 * Return value: the value of the offscreen-redirect property of the actor
10640 ClutterOffscreenRedirect
10641 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10643 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10645 return self->priv->offscreen_redirect;
10649 * clutter_actor_set_name:
10650 * @self: A #ClutterActor
10651 * @name: Textual tag to apply to actor
10653 * Sets the given name to @self. The name can be used to identify
10657 clutter_actor_set_name (ClutterActor *self,
10660 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10662 g_free (self->priv->name);
10663 self->priv->name = g_strdup (name);
10665 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10669 * clutter_actor_get_name:
10670 * @self: A #ClutterActor
10672 * Retrieves the name of @self.
10674 * Return value: the name of the actor, or %NULL. The returned string is
10675 * owned by the actor and should not be modified or freed.
10678 clutter_actor_get_name (ClutterActor *self)
10680 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10682 return self->priv->name;
10686 * clutter_actor_get_gid:
10687 * @self: A #ClutterActor
10689 * Retrieves the unique id for @self.
10691 * Return value: Globally unique value for this object instance.
10695 * Deprecated: 1.8: The id is not used any longer.
10698 clutter_actor_get_gid (ClutterActor *self)
10700 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10702 return self->priv->id;
10706 clutter_actor_set_depth_internal (ClutterActor *self,
10709 ClutterTransformInfo *info;
10711 info = _clutter_actor_get_transform_info (self);
10713 if (info->depth != depth)
10715 /* Sets Z value - XXX 2.0: should we invert? */
10716 info->depth = depth;
10718 self->priv->transform_valid = FALSE;
10720 /* FIXME - remove this crap; sadly, there are still containers
10721 * in Clutter that depend on this utter brain damage
10723 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10725 clutter_actor_queue_redraw (self);
10727 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10732 * clutter_actor_set_depth:
10733 * @self: a #ClutterActor
10736 * Sets the Z coordinate of @self to @depth.
10738 * The unit used by @depth is dependant on the perspective setup. See
10739 * also clutter_stage_set_perspective().
10742 clutter_actor_set_depth (ClutterActor *self,
10745 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10747 if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10749 const ClutterTransformInfo *info;
10751 info = _clutter_actor_get_transform_info_or_defaults (self);
10753 _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10758 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10760 clutter_actor_queue_redraw (self);
10764 * clutter_actor_get_depth:
10765 * @self: a #ClutterActor
10767 * Retrieves the depth of @self.
10769 * Return value: the depth of the actor
10772 clutter_actor_get_depth (ClutterActor *self)
10774 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10776 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10780 * clutter_actor_set_rotation:
10781 * @self: a #ClutterActor
10782 * @axis: the axis of rotation
10783 * @angle: the angle of rotation
10784 * @x: X coordinate of the rotation center
10785 * @y: Y coordinate of the rotation center
10786 * @z: Z coordinate of the rotation center
10788 * Sets the rotation angle of @self around the given axis.
10790 * The rotation center coordinates used depend on the value of @axis:
10792 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10793 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10794 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10797 * The rotation coordinates are relative to the anchor point of the
10798 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10799 * point is set, the upper left corner is assumed as the origin.
10804 clutter_actor_set_rotation (ClutterActor *self,
10805 ClutterRotateAxis axis,
10813 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10819 g_object_freeze_notify (G_OBJECT (self));
10821 clutter_actor_set_rotation_angle (self, axis, angle);
10822 clutter_actor_set_rotation_center_internal (self, axis, &v);
10824 g_object_thaw_notify (G_OBJECT (self));
10828 * clutter_actor_set_z_rotation_from_gravity:
10829 * @self: a #ClutterActor
10830 * @angle: the angle of rotation
10831 * @gravity: the center point of the rotation
10833 * Sets the rotation angle of @self around the Z axis using the center
10834 * point specified as a compass point. For example to rotate such that
10835 * the center of the actor remains static you can use
10836 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10837 * will move accordingly.
10842 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10844 ClutterGravity gravity)
10846 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10848 if (gravity == CLUTTER_GRAVITY_NONE)
10849 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10852 GObject *obj = G_OBJECT (self);
10853 ClutterTransformInfo *info;
10855 info = _clutter_actor_get_transform_info (self);
10857 g_object_freeze_notify (obj);
10859 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10861 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10862 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10863 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10865 g_object_thaw_notify (obj);
10870 * clutter_actor_get_rotation:
10871 * @self: a #ClutterActor
10872 * @axis: the axis of rotation
10873 * @x: (out): return value for the X coordinate of the center of rotation
10874 * @y: (out): return value for the Y coordinate of the center of rotation
10875 * @z: (out): return value for the Z coordinate of the center of rotation
10877 * Retrieves the angle and center of rotation on the given axis,
10878 * set using clutter_actor_set_rotation().
10880 * Return value: the angle of rotation
10885 clutter_actor_get_rotation (ClutterActor *self,
10886 ClutterRotateAxis axis,
10891 const ClutterTransformInfo *info;
10892 const AnchorCoord *anchor_coord;
10893 gdouble retval = 0;
10895 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10897 info = _clutter_actor_get_transform_info_or_defaults (self);
10901 case CLUTTER_X_AXIS:
10902 anchor_coord = &info->rx_center;
10903 retval = info->rx_angle;
10906 case CLUTTER_Y_AXIS:
10907 anchor_coord = &info->ry_center;
10908 retval = info->ry_angle;
10911 case CLUTTER_Z_AXIS:
10912 anchor_coord = &info->rz_center;
10913 retval = info->rz_angle;
10917 anchor_coord = NULL;
10922 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10928 * clutter_actor_get_z_rotation_gravity:
10929 * @self: A #ClutterActor
10931 * Retrieves the center for the rotation around the Z axis as a
10932 * compass direction. If the center was specified in pixels or units
10933 * this will return %CLUTTER_GRAVITY_NONE.
10935 * Return value: the Z rotation center
10940 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10942 const ClutterTransformInfo *info;
10944 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10946 info = _clutter_actor_get_transform_info_or_defaults (self);
10948 return clutter_anchor_coord_get_gravity (&info->rz_center);
10952 * clutter_actor_set_clip:
10953 * @self: A #ClutterActor
10954 * @xoff: X offset of the clip rectangle
10955 * @yoff: Y offset of the clip rectangle
10956 * @width: Width of the clip rectangle
10957 * @height: Height of the clip rectangle
10959 * Sets clip area for @self. The clip area is always computed from the
10960 * upper left corner of the actor, even if the anchor point is set
10966 clutter_actor_set_clip (ClutterActor *self,
10972 ClutterActorPrivate *priv;
10974 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10978 if (priv->has_clip &&
10979 priv->clip.x == xoff &&
10980 priv->clip.y == yoff &&
10981 priv->clip.width == width &&
10982 priv->clip.height == height)
10985 priv->clip.x = xoff;
10986 priv->clip.y = yoff;
10987 priv->clip.width = width;
10988 priv->clip.height = height;
10990 priv->has_clip = TRUE;
10992 clutter_actor_queue_redraw (self);
10994 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10995 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10999 * clutter_actor_remove_clip:
11000 * @self: A #ClutterActor
11002 * Removes clip area from @self.
11005 clutter_actor_remove_clip (ClutterActor *self)
11007 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11009 if (!self->priv->has_clip)
11012 self->priv->has_clip = FALSE;
11014 clutter_actor_queue_redraw (self);
11016 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
11020 * clutter_actor_has_clip:
11021 * @self: a #ClutterActor
11023 * Determines whether the actor has a clip area set or not.
11025 * Return value: %TRUE if the actor has a clip area set.
11030 clutter_actor_has_clip (ClutterActor *self)
11032 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11034 return self->priv->has_clip;
11038 * clutter_actor_get_clip:
11039 * @self: a #ClutterActor
11040 * @xoff: (out) (allow-none): return location for the X offset of
11041 * the clip rectangle, or %NULL
11042 * @yoff: (out) (allow-none): return location for the Y offset of
11043 * the clip rectangle, or %NULL
11044 * @width: (out) (allow-none): return location for the width of
11045 * the clip rectangle, or %NULL
11046 * @height: (out) (allow-none): return location for the height of
11047 * the clip rectangle, or %NULL
11049 * Gets the clip area for @self, if any is set
11054 clutter_actor_get_clip (ClutterActor *self,
11060 ClutterActorPrivate *priv;
11062 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11066 if (!priv->has_clip)
11070 *xoff = priv->clip.x;
11073 *yoff = priv->clip.y;
11076 *width = priv->clip.width;
11078 if (height != NULL)
11079 *height = priv->clip.height;
11083 * clutter_actor_get_children:
11084 * @self: a #ClutterActor
11086 * Retrieves the list of children of @self.
11088 * Return value: (transfer container) (element-type ClutterActor): A newly
11089 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
11095 clutter_actor_get_children (ClutterActor *self)
11097 ClutterActor *iter;
11100 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11102 /* we walk the list backward so that we can use prepend(),
11105 for (iter = self->priv->last_child, res = NULL;
11107 iter = iter->priv->prev_sibling)
11109 res = g_list_prepend (res, iter);
11116 * insert_child_at_depth:
11117 * @self: a #ClutterActor
11118 * @child: a #ClutterActor
11120 * Inserts @child inside the list of children held by @self, using
11121 * the depth as the insertion criteria.
11123 * This sadly makes the insertion not O(1), but we can keep the
11124 * list sorted so that the painters algorithm we use for painting
11125 * the children will work correctly.
11128 insert_child_at_depth (ClutterActor *self,
11129 ClutterActor *child,
11130 gpointer dummy G_GNUC_UNUSED)
11132 ClutterActor *iter;
11135 child->priv->parent = self;
11138 _clutter_actor_get_transform_info_or_defaults (child)->depth;
11140 /* special-case the first child */
11141 if (self->priv->n_children == 0)
11143 self->priv->first_child = child;
11144 self->priv->last_child = child;
11146 child->priv->next_sibling = NULL;
11147 child->priv->prev_sibling = NULL;
11152 /* Find the right place to insert the child so that it will still be
11153 sorted and the child will be after all of the actors at the same
11155 for (iter = self->priv->first_child;
11157 iter = iter->priv->next_sibling)
11162 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11164 if (iter_depth > child_depth)
11170 ClutterActor *tmp = iter->priv->prev_sibling;
11173 tmp->priv->next_sibling = child;
11175 /* Insert the node before the found one */
11176 child->priv->prev_sibling = iter->priv->prev_sibling;
11177 child->priv->next_sibling = iter;
11178 iter->priv->prev_sibling = child;
11182 ClutterActor *tmp = self->priv->last_child;
11185 tmp->priv->next_sibling = child;
11187 /* insert the node at the end of the list */
11188 child->priv->prev_sibling = self->priv->last_child;
11189 child->priv->next_sibling = NULL;
11192 if (child->priv->prev_sibling == NULL)
11193 self->priv->first_child = child;
11195 if (child->priv->next_sibling == NULL)
11196 self->priv->last_child = child;
11200 insert_child_at_index (ClutterActor *self,
11201 ClutterActor *child,
11204 gint index_ = GPOINTER_TO_INT (data_);
11206 child->priv->parent = self;
11210 ClutterActor *tmp = self->priv->first_child;
11213 tmp->priv->prev_sibling = child;
11215 child->priv->prev_sibling = NULL;
11216 child->priv->next_sibling = tmp;
11218 else if (index_ < 0 || index_ >= self->priv->n_children)
11220 ClutterActor *tmp = self->priv->last_child;
11223 tmp->priv->next_sibling = child;
11225 child->priv->prev_sibling = tmp;
11226 child->priv->next_sibling = NULL;
11230 ClutterActor *iter;
11233 for (iter = self->priv->first_child, i = 0;
11235 iter = iter->priv->next_sibling, i += 1)
11239 ClutterActor *tmp = iter->priv->prev_sibling;
11241 child->priv->prev_sibling = tmp;
11242 child->priv->next_sibling = iter;
11244 iter->priv->prev_sibling = child;
11247 tmp->priv->next_sibling = child;
11254 if (child->priv->prev_sibling == NULL)
11255 self->priv->first_child = child;
11257 if (child->priv->next_sibling == NULL)
11258 self->priv->last_child = child;
11262 insert_child_above (ClutterActor *self,
11263 ClutterActor *child,
11266 ClutterActor *sibling = data;
11268 child->priv->parent = self;
11270 if (sibling == NULL)
11271 sibling = self->priv->last_child;
11273 child->priv->prev_sibling = sibling;
11275 if (sibling != NULL)
11277 ClutterActor *tmp = sibling->priv->next_sibling;
11279 child->priv->next_sibling = tmp;
11282 tmp->priv->prev_sibling = child;
11284 sibling->priv->next_sibling = child;
11287 child->priv->next_sibling = NULL;
11289 if (child->priv->prev_sibling == NULL)
11290 self->priv->first_child = child;
11292 if (child->priv->next_sibling == NULL)
11293 self->priv->last_child = child;
11297 insert_child_below (ClutterActor *self,
11298 ClutterActor *child,
11301 ClutterActor *sibling = data;
11303 child->priv->parent = self;
11305 if (sibling == NULL)
11306 sibling = self->priv->first_child;
11308 child->priv->next_sibling = sibling;
11310 if (sibling != NULL)
11312 ClutterActor *tmp = sibling->priv->prev_sibling;
11314 child->priv->prev_sibling = tmp;
11317 tmp->priv->next_sibling = child;
11319 sibling->priv->prev_sibling = child;
11322 child->priv->prev_sibling = NULL;
11324 if (child->priv->prev_sibling == NULL)
11325 self->priv->first_child = child;
11327 if (child->priv->next_sibling == NULL)
11328 self->priv->last_child = child;
11331 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11332 ClutterActor *child,
11336 ADD_CHILD_CREATE_META = 1 << 0,
11337 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
11338 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
11339 ADD_CHILD_CHECK_STATE = 1 << 3,
11340 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
11341 ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11343 /* default flags for public API */
11344 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
11345 ADD_CHILD_EMIT_PARENT_SET |
11346 ADD_CHILD_EMIT_ACTOR_ADDED |
11347 ADD_CHILD_CHECK_STATE |
11348 ADD_CHILD_NOTIFY_FIRST_LAST |
11349 ADD_CHILD_SHOW_ON_SET_PARENT,
11351 /* flags for legacy/deprecated API */
11352 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
11353 ADD_CHILD_CHECK_STATE |
11354 ADD_CHILD_NOTIFY_FIRST_LAST |
11355 ADD_CHILD_SHOW_ON_SET_PARENT
11356 } ClutterActorAddChildFlags;
11359 * clutter_actor_add_child_internal:
11360 * @self: a #ClutterActor
11361 * @child: a #ClutterActor
11362 * @flags: control flags for actions
11363 * @add_func: delegate function
11364 * @data: (closure): data to pass to @add_func
11366 * Adds @child to the list of children of @self.
11368 * The actual insertion inside the list is delegated to @add_func: this
11369 * function will just set up the state, perform basic checks, and emit
11372 * The @flags argument is used to perform additional operations.
11375 clutter_actor_add_child_internal (ClutterActor *self,
11376 ClutterActor *child,
11377 ClutterActorAddChildFlags flags,
11378 ClutterActorAddChildFunc add_func,
11381 ClutterTextDirection text_dir;
11382 gboolean create_meta;
11383 gboolean emit_parent_set, emit_actor_added;
11384 gboolean check_state;
11385 gboolean notify_first_last;
11386 gboolean show_on_set_parent;
11387 ClutterActor *old_first_child, *old_last_child;
11389 if (child->priv->parent != NULL)
11391 g_warning ("The actor '%s' already has a parent, '%s'. You must "
11392 "use clutter_actor_remove_child() first.",
11393 _clutter_actor_get_debug_name (child),
11394 _clutter_actor_get_debug_name (child->priv->parent));
11398 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11400 g_warning ("The actor '%s' is a top-level actor, and cannot be "
11401 "a child of another actor.",
11402 _clutter_actor_get_debug_name (child));
11407 /* XXX - this check disallows calling methods that change the stacking
11408 * order within the destruction sequence, by triggering a critical
11409 * warning first, and leaving the actor in an undefined state, which
11410 * then ends up being caught by an assertion.
11412 * the reproducible sequence is:
11414 * - actor gets destroyed;
11415 * - another actor, linked to the first, will try to change the
11416 * stacking order of the first actor;
11417 * - changing the stacking order is a composite operation composed
11418 * by the following steps:
11419 * 1. ref() the child;
11420 * 2. remove_child_internal(), which removes the reference;
11421 * 3. add_child_internal(), which adds a reference;
11422 * - the state of the actor is not changed between (2) and (3), as
11423 * it could be an expensive recomputation;
11424 * - if (3) bails out, then the actor is in an undefined state, but
11426 * - the destruction sequence terminates, but the actor is unparented
11427 * while its state indicates being parented instead.
11428 * - assertion failure.
11430 * the obvious fix would be to decompose each set_child_*_sibling()
11431 * method into proper remove_child()/add_child(), with state validation;
11432 * this may cause excessive work, though, and trigger a cascade of other
11433 * bugs in code that assumes that a change in the stacking order is an
11434 * atomic operation.
11436 * another potential fix is to just remove this check here, and let
11437 * code doing stacking order changes inside the destruction sequence
11438 * of an actor continue doing the work.
11440 * the third fix is to silently bail out early from every
11441 * set_child_*_sibling() and set_child_at_index() method, and avoid
11444 * I have a preference for the second solution, since it involves the
11445 * least amount of work, and the least amount of code duplication.
11447 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11449 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11451 g_warning ("The actor '%s' is currently being destroyed, and "
11452 "cannot be added as a child of another actor.",
11453 _clutter_actor_get_debug_name (child));
11458 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11459 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11460 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11461 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11462 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11463 show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11465 old_first_child = self->priv->first_child;
11466 old_last_child = self->priv->last_child;
11468 g_object_freeze_notify (G_OBJECT (self));
11471 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11473 g_object_ref_sink (child);
11474 child->priv->parent = NULL;
11475 child->priv->next_sibling = NULL;
11476 child->priv->prev_sibling = NULL;
11478 /* delegate the actual insertion */
11479 add_func (self, child, data);
11481 g_assert (child->priv->parent == self);
11483 self->priv->n_children += 1;
11485 self->priv->age += 1;
11487 /* if push_internal() has been called then we automatically set
11488 * the flag on the actor
11490 if (self->priv->internal_child)
11491 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11493 /* children may cause their parent to expand, if they are set
11494 * to expand; if a child is not expanded then it cannot change
11495 * its parent's state. any further change later on will queue
11496 * an expand state check.
11498 * this check, with the initial state of the needs_compute_expand
11499 * flag set to FALSE, should avoid recomputing the expand flags
11500 * state while building the actor tree.
11502 if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11503 (child->priv->needs_compute_expand ||
11504 child->priv->needs_x_expand ||
11505 child->priv->needs_y_expand))
11507 clutter_actor_queue_compute_expand (self);
11510 /* clutter_actor_reparent() will emit ::parent-set for us */
11511 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11512 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11516 /* If parent is mapped or realized, we need to also be mapped or
11517 * realized once we're inside the parent.
11519 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11521 /* propagate the parent's text direction to the child */
11522 text_dir = clutter_actor_get_text_direction (self);
11523 clutter_actor_set_text_direction (child, text_dir);
11526 if (show_on_set_parent && child->priv->show_on_set_parent)
11527 clutter_actor_show (child);
11529 if (CLUTTER_ACTOR_IS_MAPPED (child))
11530 clutter_actor_queue_redraw (child);
11532 /* maintain the invariant that if an actor needs layout,
11533 * its parents do as well
11535 if (child->priv->needs_width_request ||
11536 child->priv->needs_height_request ||
11537 child->priv->needs_allocation)
11539 /* we work around the short-circuiting we do
11540 * in clutter_actor_queue_relayout() since we
11541 * want to force a relayout
11543 child->priv->needs_width_request = TRUE;
11544 child->priv->needs_height_request = TRUE;
11545 child->priv->needs_allocation = TRUE;
11547 clutter_actor_queue_relayout (child->priv->parent);
11550 if (emit_actor_added)
11551 g_signal_emit_by_name (self, "actor-added", child);
11553 if (notify_first_last)
11555 if (old_first_child != self->priv->first_child)
11556 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11558 if (old_last_child != self->priv->last_child)
11559 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11562 g_object_thaw_notify (G_OBJECT (self));
11566 * clutter_actor_add_child:
11567 * @self: a #ClutterActor
11568 * @child: a #ClutterActor
11570 * Adds @child to the children of @self.
11572 * This function will acquire a reference on @child that will only
11573 * be released when calling clutter_actor_remove_child().
11575 * This function will take into consideration the #ClutterActor:depth
11576 * of @child, and will keep the list of children sorted.
11578 * This function will emit the #ClutterContainer::actor-added signal
11584 clutter_actor_add_child (ClutterActor *self,
11585 ClutterActor *child)
11587 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11588 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11589 g_return_if_fail (self != child);
11590 g_return_if_fail (child->priv->parent == NULL);
11592 clutter_actor_add_child_internal (self, child,
11593 ADD_CHILD_DEFAULT_FLAGS,
11594 insert_child_at_depth,
11599 * clutter_actor_insert_child_at_index:
11600 * @self: a #ClutterActor
11601 * @child: a #ClutterActor
11602 * @index_: the index
11604 * Inserts @child into the list of children of @self, using the
11605 * given @index_. If @index_ is greater than the number of children
11606 * in @self, or is less than 0, then the new child is added at the end.
11608 * This function will acquire a reference on @child that will only
11609 * be released when calling clutter_actor_remove_child().
11611 * This function will not take into consideration the #ClutterActor:depth
11614 * This function will emit the #ClutterContainer::actor-added signal
11620 clutter_actor_insert_child_at_index (ClutterActor *self,
11621 ClutterActor *child,
11624 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11625 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11626 g_return_if_fail (self != child);
11627 g_return_if_fail (child->priv->parent == NULL);
11629 clutter_actor_add_child_internal (self, child,
11630 ADD_CHILD_DEFAULT_FLAGS,
11631 insert_child_at_index,
11632 GINT_TO_POINTER (index_));
11636 * clutter_actor_insert_child_above:
11637 * @self: a #ClutterActor
11638 * @child: a #ClutterActor
11639 * @sibling: (allow-none): a child of @self, or %NULL
11641 * Inserts @child into the list of children of @self, above another
11642 * child of @self or, if @sibling is %NULL, above all the children
11645 * This function will acquire a reference on @child that will only
11646 * be released when calling clutter_actor_remove_child().
11648 * This function will not take into consideration the #ClutterActor:depth
11651 * This function will emit the #ClutterContainer::actor-added signal
11657 clutter_actor_insert_child_above (ClutterActor *self,
11658 ClutterActor *child,
11659 ClutterActor *sibling)
11661 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11662 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11663 g_return_if_fail (self != child);
11664 g_return_if_fail (child != sibling);
11665 g_return_if_fail (child->priv->parent == NULL);
11666 g_return_if_fail (sibling == NULL ||
11667 (CLUTTER_IS_ACTOR (sibling) &&
11668 sibling->priv->parent == self));
11670 clutter_actor_add_child_internal (self, child,
11671 ADD_CHILD_DEFAULT_FLAGS,
11672 insert_child_above,
11677 * clutter_actor_insert_child_below:
11678 * @self: a #ClutterActor
11679 * @child: a #ClutterActor
11680 * @sibling: (allow-none): a child of @self, or %NULL
11682 * Inserts @child into the list of children of @self, below another
11683 * child of @self or, if @sibling is %NULL, below all the children
11686 * This function will acquire a reference on @child that will only
11687 * be released when calling clutter_actor_remove_child().
11689 * This function will not take into consideration the #ClutterActor:depth
11692 * This function will emit the #ClutterContainer::actor-added signal
11698 clutter_actor_insert_child_below (ClutterActor *self,
11699 ClutterActor *child,
11700 ClutterActor *sibling)
11702 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11703 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11704 g_return_if_fail (self != child);
11705 g_return_if_fail (child != sibling);
11706 g_return_if_fail (child->priv->parent == NULL);
11707 g_return_if_fail (sibling == NULL ||
11708 (CLUTTER_IS_ACTOR (sibling) &&
11709 sibling->priv->parent == self));
11711 clutter_actor_add_child_internal (self, child,
11712 ADD_CHILD_DEFAULT_FLAGS,
11713 insert_child_below,
11718 * clutter_actor_set_parent:
11719 * @self: A #ClutterActor
11720 * @parent: A new #ClutterActor parent
11722 * Sets the parent of @self to @parent.
11724 * This function will result in @parent acquiring a reference on @self,
11725 * eventually by sinking its floating reference first. The reference
11726 * will be released by clutter_actor_unparent().
11728 * This function should only be called by legacy #ClutterActor<!-- -->s
11729 * implementing the #ClutterContainer interface.
11731 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11734 clutter_actor_set_parent (ClutterActor *self,
11735 ClutterActor *parent)
11737 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11738 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11739 g_return_if_fail (self != parent);
11740 g_return_if_fail (self->priv->parent == NULL);
11742 /* as this function will be called inside ClutterContainer::add
11743 * implementations or when building up a composite actor, we have
11744 * to preserve the old behaviour, and not create child meta or
11745 * emit the ::actor-added signal, to avoid recursion or double
11748 clutter_actor_add_child_internal (parent, self,
11749 ADD_CHILD_LEGACY_FLAGS,
11750 insert_child_at_depth,
11755 * clutter_actor_get_parent:
11756 * @self: A #ClutterActor
11758 * Retrieves the parent of @self.
11760 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11761 * if no parent is set
11764 clutter_actor_get_parent (ClutterActor *self)
11766 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11768 return self->priv->parent;
11772 * clutter_actor_get_paint_visibility:
11773 * @self: A #ClutterActor
11775 * Retrieves the 'paint' visibility of an actor recursively checking for non
11778 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11780 * Return Value: %TRUE if the actor is visibile and will be painted.
11785 clutter_actor_get_paint_visibility (ClutterActor *actor)
11787 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11789 return CLUTTER_ACTOR_IS_MAPPED (actor);
11793 * clutter_actor_remove_child:
11794 * @self: a #ClutterActor
11795 * @child: a #ClutterActor
11797 * Removes @child from the children of @self.
11799 * This function will release the reference added by
11800 * clutter_actor_add_child(), so if you want to keep using @child
11801 * you will have to acquire a referenced on it before calling this
11804 * This function will emit the #ClutterContainer::actor-removed
11810 clutter_actor_remove_child (ClutterActor *self,
11811 ClutterActor *child)
11813 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11814 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11815 g_return_if_fail (self != child);
11816 g_return_if_fail (child->priv->parent != NULL);
11817 g_return_if_fail (child->priv->parent == self);
11819 clutter_actor_remove_child_internal (self, child,
11820 REMOVE_CHILD_DEFAULT_FLAGS);
11824 * clutter_actor_remove_all_children:
11825 * @self: a #ClutterActor
11827 * Removes all children of @self.
11829 * This function releases the reference added by inserting a child actor
11830 * in the list of children of @self.
11832 * If the reference count of a child drops to zero, the child will be
11833 * destroyed. If you want to ensure the destruction of all the children
11834 * of @self, use clutter_actor_destroy_all_children().
11839 clutter_actor_remove_all_children (ClutterActor *self)
11841 ClutterActorIter iter;
11843 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11845 if (self->priv->n_children == 0)
11848 g_object_freeze_notify (G_OBJECT (self));
11850 clutter_actor_iter_init (&iter, self);
11851 while (clutter_actor_iter_next (&iter, NULL))
11852 clutter_actor_iter_remove (&iter);
11854 g_object_thaw_notify (G_OBJECT (self));
11857 g_assert (self->priv->first_child == NULL);
11858 g_assert (self->priv->last_child == NULL);
11859 g_assert (self->priv->n_children == 0);
11863 * clutter_actor_destroy_all_children:
11864 * @self: a #ClutterActor
11866 * Destroys all children of @self.
11868 * This function releases the reference added by inserting a child
11869 * actor in the list of children of @self, and ensures that the
11870 * #ClutterActor::destroy signal is emitted on each child of the
11873 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11874 * when its reference count drops to 0; the default handler of the
11875 * #ClutterActor::destroy signal will destroy all the children of an
11876 * actor. This function ensures that all children are destroyed, instead
11877 * of just removed from @self, unlike clutter_actor_remove_all_children()
11878 * which will merely release the reference and remove each child.
11880 * Unless you acquired an additional reference on each child of @self
11881 * prior to calling clutter_actor_remove_all_children() and want to reuse
11882 * the actors, you should use clutter_actor_destroy_all_children() in
11883 * order to make sure that children are destroyed and signal handlers
11884 * are disconnected even in cases where circular references prevent this
11885 * from automatically happening through reference counting alone.
11890 clutter_actor_destroy_all_children (ClutterActor *self)
11892 ClutterActorIter iter;
11894 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11896 if (self->priv->n_children == 0)
11899 g_object_freeze_notify (G_OBJECT (self));
11901 clutter_actor_iter_init (&iter, self);
11902 while (clutter_actor_iter_next (&iter, NULL))
11903 clutter_actor_iter_destroy (&iter);
11905 g_object_thaw_notify (G_OBJECT (self));
11908 g_assert (self->priv->first_child == NULL);
11909 g_assert (self->priv->last_child == NULL);
11910 g_assert (self->priv->n_children == 0);
11913 typedef struct _InsertBetweenData {
11914 ClutterActor *prev_sibling;
11915 ClutterActor *next_sibling;
11916 } InsertBetweenData;
11919 insert_child_between (ClutterActor *self,
11920 ClutterActor *child,
11923 InsertBetweenData *data = data_;
11924 ClutterActor *prev_sibling = data->prev_sibling;
11925 ClutterActor *next_sibling = data->next_sibling;
11927 child->priv->parent = self;
11928 child->priv->prev_sibling = prev_sibling;
11929 child->priv->next_sibling = next_sibling;
11931 if (prev_sibling != NULL)
11932 prev_sibling->priv->next_sibling = child;
11934 if (next_sibling != NULL)
11935 next_sibling->priv->prev_sibling = child;
11937 if (child->priv->prev_sibling == NULL)
11938 self->priv->first_child = child;
11940 if (child->priv->next_sibling == NULL)
11941 self->priv->last_child = child;
11945 * clutter_actor_replace_child:
11946 * @self: a #ClutterActor
11947 * @old_child: the child of @self to replace
11948 * @new_child: the #ClutterActor to replace @old_child
11950 * Replaces @old_child with @new_child in the list of children of @self.
11955 clutter_actor_replace_child (ClutterActor *self,
11956 ClutterActor *old_child,
11957 ClutterActor *new_child)
11959 ClutterActor *prev_sibling, *next_sibling;
11960 InsertBetweenData clos;
11962 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11963 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11964 g_return_if_fail (old_child->priv->parent == self);
11965 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11966 g_return_if_fail (old_child != new_child);
11967 g_return_if_fail (new_child != self);
11968 g_return_if_fail (new_child->priv->parent == NULL);
11970 prev_sibling = old_child->priv->prev_sibling;
11971 next_sibling = old_child->priv->next_sibling;
11972 clutter_actor_remove_child_internal (self, old_child,
11973 REMOVE_CHILD_DEFAULT_FLAGS);
11975 clos.prev_sibling = prev_sibling;
11976 clos.next_sibling = next_sibling;
11977 clutter_actor_add_child_internal (self, new_child,
11978 ADD_CHILD_DEFAULT_FLAGS,
11979 insert_child_between,
11984 * clutter_actor_unparent:
11985 * @self: a #ClutterActor
11987 * Removes the parent of @self.
11989 * This will cause the parent of @self to release the reference
11990 * acquired when calling clutter_actor_set_parent(), so if you
11991 * want to keep @self you will have to acquire a reference of
11992 * your own, through g_object_ref().
11994 * This function should only be called by legacy #ClutterActor<!-- -->s
11995 * implementing the #ClutterContainer interface.
11999 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
12002 clutter_actor_unparent (ClutterActor *self)
12004 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12006 if (self->priv->parent == NULL)
12009 clutter_actor_remove_child_internal (self->priv->parent, self,
12010 REMOVE_CHILD_LEGACY_FLAGS);
12014 * clutter_actor_reparent:
12015 * @self: a #ClutterActor
12016 * @new_parent: the new #ClutterActor parent
12018 * Resets the parent actor of @self.
12020 * This function is logically equivalent to calling clutter_actor_unparent()
12021 * and clutter_actor_set_parent(), but more efficiently implemented, as it
12022 * ensures the child is not finalized when unparented, and emits the
12023 * #ClutterActor::parent-set signal only once.
12025 * In reality, calling this function is less useful than it sounds, as some
12026 * application code may rely on changes in the intermediate state between
12027 * removal and addition of the actor from its old parent to the @new_parent.
12028 * Thus, it is strongly encouraged to avoid using this function in application
12033 * Deprecated: 1.10: Use clutter_actor_remove_child() and
12034 * clutter_actor_add_child() instead; remember to take a reference on
12035 * the actor being removed before calling clutter_actor_remove_child()
12036 * to avoid the reference count dropping to zero and the actor being
12040 clutter_actor_reparent (ClutterActor *self,
12041 ClutterActor *new_parent)
12043 ClutterActorPrivate *priv;
12045 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12046 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
12047 g_return_if_fail (self != new_parent);
12049 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
12051 g_warning ("Cannot set a parent on a toplevel actor");
12055 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
12057 g_warning ("Cannot set a parent currently being destroyed");
12063 if (priv->parent != new_parent)
12065 ClutterActor *old_parent;
12067 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12069 old_parent = priv->parent;
12071 g_object_ref (self);
12073 if (old_parent != NULL)
12075 /* go through the Container implementation if this is a regular
12076 * child and not an internal one
12078 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12080 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
12082 /* this will have to call unparent() */
12083 clutter_container_remove_actor (parent, self);
12086 clutter_actor_remove_child_internal (old_parent, self,
12087 REMOVE_CHILD_LEGACY_FLAGS);
12090 /* Note, will call set_parent() */
12091 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12092 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
12094 clutter_actor_add_child_internal (new_parent, self,
12095 ADD_CHILD_LEGACY_FLAGS,
12096 insert_child_at_depth,
12099 /* we emit the ::parent-set signal once */
12100 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
12102 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12104 /* the IN_REPARENT flag suspends state updates */
12105 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
12107 g_object_unref (self);
12112 * clutter_actor_contains:
12113 * @self: A #ClutterActor
12114 * @descendant: A #ClutterActor, possibly contained in @self
12116 * Determines if @descendant is contained inside @self (either as an
12117 * immediate child, or as a deeper descendant). If @self and
12118 * @descendant point to the same actor then it will also return %TRUE.
12120 * Return value: whether @descendent is contained within @self
12125 clutter_actor_contains (ClutterActor *self,
12126 ClutterActor *descendant)
12128 ClutterActor *actor;
12130 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12131 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12133 for (actor = descendant; actor; actor = actor->priv->parent)
12141 * clutter_actor_set_child_above_sibling:
12142 * @self: a #ClutterActor
12143 * @child: a #ClutterActor child of @self
12144 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12146 * Sets @child to be above @sibling in the list of children of @self.
12148 * If @sibling is %NULL, @child will be the new last child of @self.
12150 * This function is logically equivalent to removing @child and using
12151 * clutter_actor_insert_child_above(), but it will not emit signals
12152 * or change state on @child.
12157 clutter_actor_set_child_above_sibling (ClutterActor *self,
12158 ClutterActor *child,
12159 ClutterActor *sibling)
12161 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12162 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12163 g_return_if_fail (child->priv->parent == self);
12164 g_return_if_fail (child != sibling);
12165 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12167 if (sibling != NULL)
12168 g_return_if_fail (sibling->priv->parent == self);
12170 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12171 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12172 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12175 /* we don't want to change the state of child, or emit signals, or
12176 * regenerate ChildMeta instances here, but we still want to follow
12177 * the correct sequence of steps encoded in remove_child() and
12178 * add_child(), so that correctness is ensured, and we only go
12179 * through one known code path.
12181 g_object_ref (child);
12182 clutter_actor_remove_child_internal (self, child, 0);
12183 clutter_actor_add_child_internal (self, child,
12184 ADD_CHILD_NOTIFY_FIRST_LAST,
12185 insert_child_above,
12188 clutter_actor_queue_relayout (self);
12192 * clutter_actor_set_child_below_sibling:
12193 * @self: a #ClutterActor
12194 * @child: a #ClutterActor child of @self
12195 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12197 * Sets @child to be below @sibling in the list of children of @self.
12199 * If @sibling is %NULL, @child will be the new first child of @self.
12201 * This function is logically equivalent to removing @self and using
12202 * clutter_actor_insert_child_below(), but it will not emit signals
12203 * or change state on @child.
12208 clutter_actor_set_child_below_sibling (ClutterActor *self,
12209 ClutterActor *child,
12210 ClutterActor *sibling)
12212 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12213 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12214 g_return_if_fail (child->priv->parent == self);
12215 g_return_if_fail (child != sibling);
12216 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12218 if (sibling != NULL)
12219 g_return_if_fail (sibling->priv->parent == self);
12221 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12222 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12223 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12226 /* see the comment in set_child_above_sibling() */
12227 g_object_ref (child);
12228 clutter_actor_remove_child_internal (self, child, 0);
12229 clutter_actor_add_child_internal (self, child,
12230 ADD_CHILD_NOTIFY_FIRST_LAST,
12231 insert_child_below,
12234 clutter_actor_queue_relayout (self);
12238 * clutter_actor_set_child_at_index:
12239 * @self: a #ClutterActor
12240 * @child: a #ClutterActor child of @self
12241 * @index_: the new index for @child
12243 * Changes the index of @child in the list of children of @self.
12245 * This function is logically equivalent to removing @child and
12246 * calling clutter_actor_insert_child_at_index(), but it will not
12247 * emit signals or change state on @child.
12252 clutter_actor_set_child_at_index (ClutterActor *self,
12253 ClutterActor *child,
12256 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12257 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12258 g_return_if_fail (child->priv->parent == self);
12259 g_return_if_fail (index_ <= self->priv->n_children);
12261 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12262 CLUTTER_ACTOR_IN_DESTRUCTION (child))
12265 g_object_ref (child);
12266 clutter_actor_remove_child_internal (self, child, 0);
12267 clutter_actor_add_child_internal (self, child,
12268 ADD_CHILD_NOTIFY_FIRST_LAST,
12269 insert_child_at_index,
12270 GINT_TO_POINTER (index_));
12272 clutter_actor_queue_relayout (self);
12276 * clutter_actor_raise:
12277 * @self: A #ClutterActor
12278 * @below: (allow-none): A #ClutterActor to raise above.
12280 * Puts @self above @below.
12282 * Both actors must have the same parent, and the parent must implement
12283 * the #ClutterContainer interface
12285 * This function calls clutter_container_raise_child() internally.
12287 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12290 clutter_actor_raise (ClutterActor *self,
12291 ClutterActor *below)
12293 ClutterActor *parent;
12295 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12297 parent = clutter_actor_get_parent (self);
12298 if (parent == NULL)
12300 g_warning ("%s: Actor '%s' is not inside a container",
12302 _clutter_actor_get_debug_name (self));
12308 if (parent != clutter_actor_get_parent (below))
12310 g_warning ("%s Actor '%s' is not in the same container as "
12313 _clutter_actor_get_debug_name (self),
12314 _clutter_actor_get_debug_name (below));
12319 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12323 * clutter_actor_lower:
12324 * @self: A #ClutterActor
12325 * @above: (allow-none): A #ClutterActor to lower below
12327 * Puts @self below @above.
12329 * Both actors must have the same parent, and the parent must implement
12330 * the #ClutterContainer interface.
12332 * This function calls clutter_container_lower_child() internally.
12334 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12337 clutter_actor_lower (ClutterActor *self,
12338 ClutterActor *above)
12340 ClutterActor *parent;
12342 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12344 parent = clutter_actor_get_parent (self);
12345 if (parent == NULL)
12347 g_warning ("%s: Actor of type %s is not inside a container",
12349 _clutter_actor_get_debug_name (self));
12355 if (parent != clutter_actor_get_parent (above))
12357 g_warning ("%s: Actor '%s' is not in the same container as "
12360 _clutter_actor_get_debug_name (self),
12361 _clutter_actor_get_debug_name (above));
12366 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12370 * clutter_actor_raise_top:
12371 * @self: A #ClutterActor
12373 * Raises @self to the top.
12375 * This function calls clutter_actor_raise() internally.
12377 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12378 * a %NULL sibling, instead.
12381 clutter_actor_raise_top (ClutterActor *self)
12383 clutter_actor_raise (self, NULL);
12387 * clutter_actor_lower_bottom:
12388 * @self: A #ClutterActor
12390 * Lowers @self to the bottom.
12392 * This function calls clutter_actor_lower() internally.
12394 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12395 * a %NULL sibling, instead.
12398 clutter_actor_lower_bottom (ClutterActor *self)
12400 clutter_actor_lower (self, NULL);
12408 * clutter_actor_event:
12409 * @actor: a #ClutterActor
12410 * @event: a #ClutterEvent
12411 * @capture: TRUE if event in in capture phase, FALSE otherwise.
12413 * This function is used to emit an event on the main stage.
12414 * You should rarely need to use this function, except for
12415 * synthetising events.
12417 * Return value: the return value from the signal emission: %TRUE
12418 * if the actor handled the event, or %FALSE if the event was
12424 clutter_actor_event (ClutterActor *actor,
12425 ClutterEvent *event,
12428 gboolean retval = FALSE;
12429 gint signal_num = -1;
12431 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12432 g_return_val_if_fail (event != NULL, FALSE);
12434 g_object_ref (actor);
12438 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12444 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12448 switch (event->type)
12450 case CLUTTER_NOTHING:
12452 case CLUTTER_BUTTON_PRESS:
12453 signal_num = BUTTON_PRESS_EVENT;
12455 case CLUTTER_BUTTON_RELEASE:
12456 signal_num = BUTTON_RELEASE_EVENT;
12458 case CLUTTER_SCROLL:
12459 signal_num = SCROLL_EVENT;
12461 case CLUTTER_KEY_PRESS:
12462 signal_num = KEY_PRESS_EVENT;
12464 case CLUTTER_KEY_RELEASE:
12465 signal_num = KEY_RELEASE_EVENT;
12467 case CLUTTER_MOTION:
12468 signal_num = MOTION_EVENT;
12470 case CLUTTER_ENTER:
12471 signal_num = ENTER_EVENT;
12473 case CLUTTER_LEAVE:
12474 signal_num = LEAVE_EVENT;
12476 case CLUTTER_DELETE:
12477 case CLUTTER_DESTROY_NOTIFY:
12478 case CLUTTER_CLIENT_MESSAGE:
12484 if (signal_num != -1)
12485 g_signal_emit (actor, actor_signals[signal_num], 0,
12490 g_object_unref (actor);
12496 * clutter_actor_set_reactive:
12497 * @actor: a #ClutterActor
12498 * @reactive: whether the actor should be reactive to events
12500 * Sets @actor as reactive. Reactive actors will receive events.
12505 clutter_actor_set_reactive (ClutterActor *actor,
12508 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12510 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12514 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12516 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12518 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12522 * clutter_actor_get_reactive:
12523 * @actor: a #ClutterActor
12525 * Checks whether @actor is marked as reactive.
12527 * Return value: %TRUE if the actor is reactive
12532 clutter_actor_get_reactive (ClutterActor *actor)
12534 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12536 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12540 * clutter_actor_get_anchor_point:
12541 * @self: a #ClutterActor
12542 * @anchor_x: (out): return location for the X coordinate of the anchor point
12543 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12545 * Gets the current anchor point of the @actor in pixels.
12550 clutter_actor_get_anchor_point (ClutterActor *self,
12554 const ClutterTransformInfo *info;
12556 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12558 info = _clutter_actor_get_transform_info_or_defaults (self);
12559 clutter_anchor_coord_get_units (self, &info->anchor,
12566 * clutter_actor_set_anchor_point:
12567 * @self: a #ClutterActor
12568 * @anchor_x: X coordinate of the anchor point
12569 * @anchor_y: Y coordinate of the anchor point
12571 * Sets an anchor point for @self. The anchor point is a point in the
12572 * coordinate space of an actor to which the actor position within its
12573 * parent is relative; the default is (0, 0), i.e. the top-left corner
12579 clutter_actor_set_anchor_point (ClutterActor *self,
12583 ClutterTransformInfo *info;
12584 ClutterActorPrivate *priv;
12585 gboolean changed = FALSE;
12586 gfloat old_anchor_x, old_anchor_y;
12589 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12591 obj = G_OBJECT (self);
12593 info = _clutter_actor_get_transform_info (self);
12595 g_object_freeze_notify (obj);
12597 clutter_anchor_coord_get_units (self, &info->anchor,
12602 if (info->anchor.is_fractional)
12603 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12605 if (old_anchor_x != anchor_x)
12607 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12611 if (old_anchor_y != anchor_y)
12613 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12617 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12621 priv->transform_valid = FALSE;
12622 clutter_actor_queue_redraw (self);
12625 g_object_thaw_notify (obj);
12629 * clutter_actor_get_anchor_point_gravity:
12630 * @self: a #ClutterActor
12632 * Retrieves the anchor position expressed as a #ClutterGravity. If
12633 * the anchor point was specified using pixels or units this will
12634 * return %CLUTTER_GRAVITY_NONE.
12636 * Return value: the #ClutterGravity used by the anchor point
12641 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12643 const ClutterTransformInfo *info;
12645 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12647 info = _clutter_actor_get_transform_info_or_defaults (self);
12649 return clutter_anchor_coord_get_gravity (&info->anchor);
12653 * clutter_actor_move_anchor_point:
12654 * @self: a #ClutterActor
12655 * @anchor_x: X coordinate of the anchor point
12656 * @anchor_y: Y coordinate of the anchor point
12658 * Sets an anchor point for the actor, and adjusts the actor postion so that
12659 * the relative position of the actor toward its parent remains the same.
12664 clutter_actor_move_anchor_point (ClutterActor *self,
12668 gfloat old_anchor_x, old_anchor_y;
12669 const ClutterTransformInfo *info;
12671 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12673 info = _clutter_actor_get_transform_info (self);
12674 clutter_anchor_coord_get_units (self, &info->anchor,
12679 g_object_freeze_notify (G_OBJECT (self));
12681 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12683 if (self->priv->position_set)
12684 clutter_actor_move_by (self,
12685 anchor_x - old_anchor_x,
12686 anchor_y - old_anchor_y);
12688 g_object_thaw_notify (G_OBJECT (self));
12692 * clutter_actor_move_anchor_point_from_gravity:
12693 * @self: a #ClutterActor
12694 * @gravity: #ClutterGravity.
12696 * Sets an anchor point on the actor based on the given gravity, adjusting the
12697 * actor postion so that its relative position within its parent remains
12700 * Since version 1.0 the anchor point will be stored as a gravity so
12701 * that if the actor changes size then the anchor point will move. For
12702 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12703 * and later double the size of the actor, the anchor point will move
12704 * to the bottom right.
12709 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12710 ClutterGravity gravity)
12712 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12713 const ClutterTransformInfo *info;
12714 ClutterActorPrivate *priv;
12716 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12719 info = _clutter_actor_get_transform_info (self);
12721 g_object_freeze_notify (G_OBJECT (self));
12723 clutter_anchor_coord_get_units (self, &info->anchor,
12727 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12728 clutter_anchor_coord_get_units (self, &info->anchor,
12733 if (priv->position_set)
12734 clutter_actor_move_by (self,
12735 new_anchor_x - old_anchor_x,
12736 new_anchor_y - old_anchor_y);
12738 g_object_thaw_notify (G_OBJECT (self));
12742 * clutter_actor_set_anchor_point_from_gravity:
12743 * @self: a #ClutterActor
12744 * @gravity: #ClutterGravity.
12746 * Sets an anchor point on the actor, based on the given gravity (this is a
12747 * convenience function wrapping clutter_actor_set_anchor_point()).
12749 * Since version 1.0 the anchor point will be stored as a gravity so
12750 * that if the actor changes size then the anchor point will move. For
12751 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12752 * and later double the size of the actor, the anchor point will move
12753 * to the bottom right.
12758 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12759 ClutterGravity gravity)
12761 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12763 if (gravity == CLUTTER_GRAVITY_NONE)
12764 clutter_actor_set_anchor_point (self, 0, 0);
12767 GObject *obj = G_OBJECT (self);
12768 ClutterTransformInfo *info;
12770 g_object_freeze_notify (obj);
12772 info = _clutter_actor_get_transform_info (self);
12773 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12775 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12776 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12777 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12779 self->priv->transform_valid = FALSE;
12781 clutter_actor_queue_redraw (self);
12783 g_object_thaw_notify (obj);
12788 clutter_actor_store_content_box (ClutterActor *self,
12789 const ClutterActorBox *box)
12793 self->priv->content_box = *box;
12794 self->priv->content_box_valid = TRUE;
12797 self->priv->content_box_valid = FALSE;
12799 clutter_actor_queue_redraw (self);
12801 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12805 clutter_container_iface_init (ClutterContainerIface *iface)
12807 /* we don't override anything, as ClutterContainer already has a default
12808 * implementation that we can use, and which calls into our own API.
12823 parse_units (ClutterActor *self,
12824 ParseDimension dimension,
12827 GValue value = G_VALUE_INIT;
12830 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12833 json_node_get_value (node, &value);
12835 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12837 retval = (gfloat) g_value_get_int64 (&value);
12839 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12841 retval = g_value_get_double (&value);
12843 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12845 ClutterUnits units;
12848 res = clutter_units_from_string (&units, g_value_get_string (&value));
12850 retval = clutter_units_to_pixels (&units);
12853 g_warning ("Invalid value '%s': integers, strings or floating point "
12854 "values can be used for the x, y, width and height "
12855 "properties. Valid modifiers for strings are 'px', 'mm', "
12857 g_value_get_string (&value));
12863 g_warning ("Invalid value of type '%s': integers, strings of floating "
12864 "point values can be used for the x, y, width, height "
12865 "anchor-x and anchor-y properties.",
12866 g_type_name (G_VALUE_TYPE (&value)));
12869 g_value_unset (&value);
12875 ClutterRotateAxis axis;
12884 static inline gboolean
12885 parse_rotation_array (ClutterActor *actor,
12887 RotationInfo *info)
12891 if (json_array_get_length (array) != 2)
12895 element = json_array_get_element (array, 0);
12896 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12897 info->angle = json_node_get_double (element);
12902 element = json_array_get_element (array, 1);
12903 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12905 JsonArray *center = json_node_get_array (element);
12907 if (json_array_get_length (center) != 2)
12910 switch (info->axis)
12912 case CLUTTER_X_AXIS:
12913 info->center_y = parse_units (actor, PARSE_Y,
12914 json_array_get_element (center, 0));
12915 info->center_z = parse_units (actor, PARSE_Y,
12916 json_array_get_element (center, 1));
12919 case CLUTTER_Y_AXIS:
12920 info->center_x = parse_units (actor, PARSE_X,
12921 json_array_get_element (center, 0));
12922 info->center_z = parse_units (actor, PARSE_X,
12923 json_array_get_element (center, 1));
12926 case CLUTTER_Z_AXIS:
12927 info->center_x = parse_units (actor, PARSE_X,
12928 json_array_get_element (center, 0));
12929 info->center_y = parse_units (actor, PARSE_Y,
12930 json_array_get_element (center, 1));
12939 parse_rotation (ClutterActor *actor,
12941 RotationInfo *info)
12945 gboolean retval = FALSE;
12947 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12949 g_warning ("Invalid node of type '%s' found, expecting an array",
12950 json_node_type_name (node));
12954 array = json_node_get_array (node);
12955 len = json_array_get_length (array);
12957 for (i = 0; i < len; i++)
12959 JsonNode *element = json_array_get_element (array, i);
12960 JsonObject *object;
12963 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12965 g_warning ("Invalid node of type '%s' found, expecting an object",
12966 json_node_type_name (element));
12970 object = json_node_get_object (element);
12972 if (json_object_has_member (object, "x-axis"))
12974 member = json_object_get_member (object, "x-axis");
12976 info->axis = CLUTTER_X_AXIS;
12978 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12980 info->angle = json_node_get_double (member);
12983 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12984 retval = parse_rotation_array (actor,
12985 json_node_get_array (member),
12990 else if (json_object_has_member (object, "y-axis"))
12992 member = json_object_get_member (object, "y-axis");
12994 info->axis = CLUTTER_Y_AXIS;
12996 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12998 info->angle = json_node_get_double (member);
13001 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13002 retval = parse_rotation_array (actor,
13003 json_node_get_array (member),
13008 else if (json_object_has_member (object, "z-axis"))
13010 member = json_object_get_member (object, "z-axis");
13012 info->axis = CLUTTER_Z_AXIS;
13014 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
13016 info->angle = json_node_get_double (member);
13019 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13020 retval = parse_rotation_array (actor,
13021 json_node_get_array (member),
13032 parse_actor_metas (ClutterScript *script,
13033 ClutterActor *actor,
13036 GList *elements, *l;
13037 GSList *retval = NULL;
13039 if (!JSON_NODE_HOLDS_ARRAY (node))
13042 elements = json_array_get_elements (json_node_get_array (node));
13044 for (l = elements; l != NULL; l = l->next)
13046 JsonNode *element = l->data;
13047 const gchar *id_ = _clutter_script_get_id_from_node (element);
13050 if (id_ == NULL || *id_ == '\0')
13053 meta = clutter_script_get_object (script, id_);
13057 retval = g_slist_prepend (retval, meta);
13060 g_list_free (elements);
13062 return g_slist_reverse (retval);
13066 parse_behaviours (ClutterScript *script,
13067 ClutterActor *actor,
13070 GList *elements, *l;
13071 GSList *retval = NULL;
13073 if (!JSON_NODE_HOLDS_ARRAY (node))
13076 elements = json_array_get_elements (json_node_get_array (node));
13078 for (l = elements; l != NULL; l = l->next)
13080 JsonNode *element = l->data;
13081 const gchar *id_ = _clutter_script_get_id_from_node (element);
13082 GObject *behaviour;
13084 if (id_ == NULL || *id_ == '\0')
13087 behaviour = clutter_script_get_object (script, id_);
13088 if (behaviour == NULL)
13091 retval = g_slist_prepend (retval, behaviour);
13094 g_list_free (elements);
13096 return g_slist_reverse (retval);
13099 static ClutterMargin *
13100 parse_margin (ClutterActor *self,
13103 ClutterMargin *margin;
13106 if (!JSON_NODE_HOLDS_ARRAY (node))
13108 g_warning ("The margin property must be an array of 1 to 4 elements");
13112 margin = clutter_margin_new ();
13113 array = json_node_get_array (node);
13114 switch (json_array_get_length (array))
13117 margin->top = margin->right = margin->bottom = margin->left =
13118 parse_units (self, 0, json_array_get_element (array, 0));
13122 margin->top = margin->bottom =
13123 parse_units (self, 0, json_array_get_element (array, 0));
13124 margin->right = margin->left =
13125 parse_units (self, 0, json_array_get_element (array, 1));
13130 parse_units (self, 0, json_array_get_element (array, 0));
13131 margin->right = margin->left =
13132 parse_units (self, 0, json_array_get_element (array, 1));
13134 parse_units (self, 0, json_array_get_element (array, 2));
13139 parse_units (self, 0, json_array_get_element (array, 0));
13141 parse_units (self, 0, json_array_get_element (array, 1));
13143 parse_units (self, 0, json_array_get_element (array, 2));
13145 parse_units (self, 0, json_array_get_element (array, 3));
13149 g_warning ("The margin property must be an array of 1 to 4 elements");
13150 clutter_margin_free (margin);
13157 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
13158 ClutterScript *script,
13163 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13164 gboolean retval = FALSE;
13166 if ((name[0] == 'x' && name[1] == '\0') ||
13167 (name[0] == 'y' && name[1] == '\0') ||
13168 (strcmp (name, "width") == 0) ||
13169 (strcmp (name, "height") == 0) ||
13170 (strcmp (name, "anchor_x") == 0) ||
13171 (strcmp (name, "anchor_y") == 0))
13173 ParseDimension dimension;
13176 if (name[0] == 'x')
13177 dimension = PARSE_X;
13178 else if (name[0] == 'y')
13179 dimension = PARSE_Y;
13180 else if (name[0] == 'w')
13181 dimension = PARSE_WIDTH;
13182 else if (name[0] == 'h')
13183 dimension = PARSE_HEIGHT;
13184 else if (name[0] == 'a' && name[7] == 'x')
13185 dimension = PARSE_ANCHOR_X;
13186 else if (name[0] == 'a' && name[7] == 'y')
13187 dimension = PARSE_ANCHOR_Y;
13191 units = parse_units (actor, dimension, node);
13193 /* convert back to pixels: all properties are pixel-based */
13194 g_value_init (value, G_TYPE_FLOAT);
13195 g_value_set_float (value, units);
13199 else if (strcmp (name, "rotation") == 0)
13201 RotationInfo *info;
13203 info = g_slice_new0 (RotationInfo);
13204 retval = parse_rotation (actor, node, info);
13208 g_value_init (value, G_TYPE_POINTER);
13209 g_value_set_pointer (value, info);
13212 g_slice_free (RotationInfo, info);
13214 else if (strcmp (name, "behaviours") == 0)
13218 #ifdef CLUTTER_ENABLE_DEBUG
13219 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13220 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13221 "and it should not be used in newly "
13222 "written ClutterScript definitions.");
13225 l = parse_behaviours (script, actor, node);
13227 g_value_init (value, G_TYPE_POINTER);
13228 g_value_set_pointer (value, l);
13232 else if (strcmp (name, "actions") == 0 ||
13233 strcmp (name, "constraints") == 0 ||
13234 strcmp (name, "effects") == 0)
13238 l = parse_actor_metas (script, actor, node);
13240 g_value_init (value, G_TYPE_POINTER);
13241 g_value_set_pointer (value, l);
13245 else if (strcmp (name, "margin") == 0)
13247 ClutterMargin *margin = parse_margin (actor, node);
13251 g_value_init (value, CLUTTER_TYPE_MARGIN);
13252 g_value_set_boxed (value, margin);
13261 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13262 ClutterScript *script,
13264 const GValue *value)
13266 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13268 #ifdef CLUTTER_ENABLE_DEBUG
13269 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13271 gchar *tmp = g_strdup_value_contents (value);
13273 CLUTTER_NOTE (SCRIPT,
13274 "in ClutterActor::set_custom_property('%s') = %s",
13280 #endif /* CLUTTER_ENABLE_DEBUG */
13282 if (strcmp (name, "rotation") == 0)
13284 RotationInfo *info;
13286 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13289 info = g_value_get_pointer (value);
13291 clutter_actor_set_rotation (actor,
13292 info->axis, info->angle,
13297 g_slice_free (RotationInfo, info);
13302 if (strcmp (name, "behaviours") == 0)
13304 GSList *behaviours, *l;
13306 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13309 behaviours = g_value_get_pointer (value);
13310 for (l = behaviours; l != NULL; l = l->next)
13312 ClutterBehaviour *behaviour = l->data;
13314 clutter_behaviour_apply (behaviour, actor);
13317 g_slist_free (behaviours);
13322 if (strcmp (name, "actions") == 0 ||
13323 strcmp (name, "constraints") == 0 ||
13324 strcmp (name, "effects") == 0)
13328 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13331 metas = g_value_get_pointer (value);
13332 for (l = metas; l != NULL; l = l->next)
13334 if (name[0] == 'a')
13335 clutter_actor_add_action (actor, l->data);
13337 if (name[0] == 'c')
13338 clutter_actor_add_constraint (actor, l->data);
13340 if (name[0] == 'e')
13341 clutter_actor_add_effect (actor, l->data);
13344 g_slist_free (metas);
13348 if (strcmp (name, "margin") == 0)
13350 clutter_actor_set_margin (actor, g_value_get_boxed (value));
13354 g_object_set_property (G_OBJECT (scriptable), name, value);
13358 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13360 iface->parse_custom_node = clutter_actor_parse_custom_node;
13361 iface->set_custom_property = clutter_actor_set_custom_property;
13364 static ClutterActorMeta *
13365 get_meta_from_animation_property (ClutterActor *actor,
13369 ClutterActorPrivate *priv = actor->priv;
13370 ClutterActorMeta *meta = NULL;
13373 /* if this is not a special property, fall through */
13374 if (name[0] != '@')
13377 /* detect the properties named using the following spec:
13379 * @<section>.<meta-name>.<property-name>
13381 * where <section> can be one of the following:
13387 * and <meta-name> is the name set on a specific ActorMeta
13390 tokens = g_strsplit (name + 1, ".", -1);
13391 if (tokens == NULL || g_strv_length (tokens) != 3)
13393 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13395 g_strfreev (tokens);
13399 if (strcmp (tokens[0], "actions") == 0)
13400 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13402 if (strcmp (tokens[0], "constraints") == 0)
13403 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13405 if (strcmp (tokens[0], "effects") == 0)
13406 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13408 if (name_p != NULL)
13409 *name_p = g_strdup (tokens[2]);
13411 CLUTTER_NOTE (ANIMATION,
13412 "Looking for property '%s' of object '%s' in section '%s'",
13417 g_strfreev (tokens);
13422 static GParamSpec *
13423 clutter_actor_find_property (ClutterAnimatable *animatable,
13424 const gchar *property_name)
13426 ClutterActorMeta *meta = NULL;
13427 GObjectClass *klass = NULL;
13428 GParamSpec *pspec = NULL;
13429 gchar *p_name = NULL;
13431 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13437 klass = G_OBJECT_GET_CLASS (meta);
13439 pspec = g_object_class_find_property (klass, p_name);
13443 klass = G_OBJECT_GET_CLASS (animatable);
13445 pspec = g_object_class_find_property (klass, property_name);
13454 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13455 const gchar *property_name,
13458 ClutterActorMeta *meta = NULL;
13459 gchar *p_name = NULL;
13461 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13466 g_object_get_property (G_OBJECT (meta), p_name, initial);
13468 g_object_get_property (G_OBJECT (animatable), property_name, initial);
13474 * clutter_actor_set_animatable_property:
13475 * @actor: a #ClutterActor
13476 * @prop_id: the paramspec id
13477 * @value: the value to set
13478 * @pspec: the paramspec
13480 * Sets values of animatable properties.
13482 * This is a variant of clutter_actor_set_property() that gets called
13483 * by the #ClutterAnimatable implementation of #ClutterActor for the
13484 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13487 * Unlike the implementation of #GObjectClass.set_property(), this
13488 * function will not update the interval if a transition involving an
13489 * animatable property is in progress - this avoids cycles with the
13490 * transition API calling the public API.
13493 clutter_actor_set_animatable_property (ClutterActor *actor,
13495 const GValue *value,
13498 GObject *obj = G_OBJECT (actor);
13500 g_object_freeze_notify (obj);
13505 clutter_actor_set_x_internal (actor, g_value_get_float (value));
13509 clutter_actor_set_y_internal (actor, g_value_get_float (value));
13512 case PROP_POSITION:
13513 clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13517 clutter_actor_set_width_internal (actor, g_value_get_float (value));
13521 clutter_actor_set_height_internal (actor, g_value_get_float (value));
13525 clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13528 case PROP_ALLOCATION:
13529 clutter_actor_allocate_internal (actor,
13530 g_value_get_boxed (value),
13531 actor->priv->allocation_flags);
13535 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13539 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13542 case PROP_BACKGROUND_COLOR:
13543 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13547 clutter_actor_set_scale_factor_internal (actor,
13548 g_value_get_double (value),
13553 clutter_actor_set_scale_factor_internal (actor,
13554 g_value_get_double (value),
13558 case PROP_ROTATION_ANGLE_X:
13559 clutter_actor_set_rotation_angle_internal (actor,
13561 g_value_get_double (value));
13564 case PROP_ROTATION_ANGLE_Y:
13565 clutter_actor_set_rotation_angle_internal (actor,
13567 g_value_get_double (value));
13570 case PROP_ROTATION_ANGLE_Z:
13571 clutter_actor_set_rotation_angle_internal (actor,
13573 g_value_get_double (value));
13576 case PROP_CONTENT_BOX:
13577 clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13581 g_object_set_property (obj, pspec->name, value);
13585 g_object_thaw_notify (obj);
13589 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13590 const gchar *property_name,
13591 const GValue *final)
13593 ClutterActor *actor = CLUTTER_ACTOR (animatable);
13594 ClutterActorMeta *meta = NULL;
13595 gchar *p_name = NULL;
13597 meta = get_meta_from_animation_property (actor,
13601 g_object_set_property (G_OBJECT (meta), p_name, final);
13604 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13607 pspec = g_object_class_find_property (obj_class, property_name);
13609 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13611 /* XXX - I'm going to the special hell for this */
13612 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13615 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13622 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13624 iface->find_property = clutter_actor_find_property;
13625 iface->get_initial_state = clutter_actor_get_initial_state;
13626 iface->set_final_state = clutter_actor_set_final_state;
13630 * clutter_actor_transform_stage_point:
13631 * @self: A #ClutterActor
13632 * @x: (in): x screen coordinate of the point to unproject
13633 * @y: (in): y screen coordinate of the point to unproject
13634 * @x_out: (out): return location for the unprojected x coordinance
13635 * @y_out: (out): return location for the unprojected y coordinance
13637 * This function translates screen coordinates (@x, @y) to
13638 * coordinates relative to the actor. For example, it can be used to translate
13639 * screen events from global screen coordinates into actor-local coordinates.
13641 * The conversion can fail, notably if the transform stack results in the
13642 * actor being projected on the screen as a mere line.
13644 * The conversion should not be expected to be pixel-perfect due to the
13645 * nature of the operation. In general the error grows when the skewing
13646 * of the actor rectangle on screen increases.
13648 * <note><para>This function can be computationally intensive.</para></note>
13650 * <note><para>This function only works when the allocation is up-to-date,
13651 * i.e. inside of paint().</para></note>
13653 * Return value: %TRUE if conversion was successful.
13658 clutter_actor_transform_stage_point (ClutterActor *self,
13664 ClutterVertex v[4];
13667 int du, dv, xi, yi;
13669 float xf, yf, wf, det;
13670 ClutterActorPrivate *priv;
13672 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13676 /* This implementation is based on the quad -> quad projection algorithm
13677 * described by Paul Heckbert in:
13679 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13681 * and the sample implementation at:
13683 * http://www.cs.cmu.edu/~ph/src/texfund/
13685 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13686 * quad to rectangle only, which significantly simplifies things; the
13687 * function calls have been unrolled, and most of the math is done in fixed
13691 clutter_actor_get_abs_allocation_vertices (self, v);
13693 /* Keeping these as ints simplifies the multiplication (no significant
13694 * loss of precision here).
13696 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13697 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13702 #define UX2FP(x) (x)
13703 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13705 /* First, find mapping from unit uv square to xy quadrilateral; this
13706 * equivalent to the pmap_square_quad() functions in the sample
13707 * implementation, which we can simplify, since our target is always
13710 px = v[0].x - v[1].x + v[3].x - v[2].x;
13711 py = v[0].y - v[1].y + v[3].y - v[2].y;
13715 /* affine transform */
13716 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13717 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13718 RQ[2][0] = UX2FP (v[0].x);
13719 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13720 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13721 RQ[2][1] = UX2FP (v[0].y);
13728 /* projective transform */
13729 double dx1, dx2, dy1, dy2, del;
13731 dx1 = UX2FP (v[1].x - v[3].x);
13732 dx2 = UX2FP (v[2].x - v[3].x);
13733 dy1 = UX2FP (v[1].y - v[3].y);
13734 dy2 = UX2FP (v[2].y - v[3].y);
13736 del = DET2FP (dx1, dx2, dy1, dy2);
13741 * The division here needs to be done in floating point for
13742 * precisions reasons.
13744 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13745 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13746 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13748 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13749 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13750 RQ[2][0] = UX2FP (v[0].x);
13751 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13752 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13753 RQ[2][1] = UX2FP (v[0].y);
13757 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13758 * square. Since our rectangle is based at 0,0 we only need to scale.
13768 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13771 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13772 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13773 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13774 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13775 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13776 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13777 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13778 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13779 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13782 * Check the resulting matrix is OK.
13784 det = (RQ[0][0] * ST[0][0])
13785 + (RQ[0][1] * ST[0][1])
13786 + (RQ[0][2] * ST[0][2]);
13791 * Now transform our point with the ST matrix; the notional w
13792 * coordinate is 1, hence the last part is simply added.
13797 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13798 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13799 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13814 * clutter_actor_is_rotated:
13815 * @self: a #ClutterActor
13817 * Checks whether any rotation is applied to the actor.
13819 * Return value: %TRUE if the actor is rotated.
13824 clutter_actor_is_rotated (ClutterActor *self)
13826 const ClutterTransformInfo *info;
13828 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13830 info = _clutter_actor_get_transform_info_or_defaults (self);
13832 if (info->rx_angle || info->ry_angle || info->rz_angle)
13839 * clutter_actor_is_scaled:
13840 * @self: a #ClutterActor
13842 * Checks whether the actor is scaled in either dimension.
13844 * Return value: %TRUE if the actor is scaled.
13849 clutter_actor_is_scaled (ClutterActor *self)
13851 const ClutterTransformInfo *info;
13853 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13855 info = _clutter_actor_get_transform_info_or_defaults (self);
13857 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13864 _clutter_actor_get_stage_internal (ClutterActor *actor)
13866 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13867 actor = actor->priv->parent;
13873 * clutter_actor_get_stage:
13874 * @actor: a #ClutterActor
13876 * Retrieves the #ClutterStage where @actor is contained.
13878 * Return value: (transfer none) (type Clutter.Stage): the stage
13879 * containing the actor, or %NULL
13884 clutter_actor_get_stage (ClutterActor *actor)
13886 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13888 return _clutter_actor_get_stage_internal (actor);
13892 * clutter_actor_allocate_available_size:
13893 * @self: a #ClutterActor
13894 * @x: the actor's X coordinate
13895 * @y: the actor's Y coordinate
13896 * @available_width: the maximum available width, or -1 to use the
13897 * actor's natural width
13898 * @available_height: the maximum available height, or -1 to use the
13899 * actor's natural height
13900 * @flags: flags controlling the allocation
13902 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13903 * preferred size, but limiting it to the maximum available width
13904 * and height provided.
13906 * This function will do the right thing when dealing with the
13907 * actor's request mode.
13909 * The implementation of this function is equivalent to:
13912 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13914 * clutter_actor_get_preferred_width (self, available_height,
13916 * &natural_width);
13917 * width = CLAMP (natural_width, min_width, available_width);
13919 * clutter_actor_get_preferred_height (self, width,
13921 * &natural_height);
13922 * height = CLAMP (natural_height, min_height, available_height);
13926 * clutter_actor_get_preferred_height (self, available_width,
13928 * &natural_height);
13929 * height = CLAMP (natural_height, min_height, available_height);
13931 * clutter_actor_get_preferred_width (self, height,
13933 * &natural_width);
13934 * width = CLAMP (natural_width, min_width, available_width);
13937 * box.x1 = x; box.y1 = y;
13938 * box.x2 = box.x1 + available_width;
13939 * box.y2 = box.y1 + available_height;
13940 * clutter_actor_allocate (self, &box, flags);
13943 * This function can be used by fluid layout managers to allocate
13944 * an actor's preferred size without making it bigger than the area
13945 * available for the container.
13950 clutter_actor_allocate_available_size (ClutterActor *self,
13953 gfloat available_width,
13954 gfloat available_height,
13955 ClutterAllocationFlags flags)
13957 ClutterActorPrivate *priv;
13958 gfloat width, height;
13959 gfloat min_width, min_height;
13960 gfloat natural_width, natural_height;
13961 ClutterActorBox box;
13963 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13967 width = height = 0.0;
13969 switch (priv->request_mode)
13971 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13972 clutter_actor_get_preferred_width (self, available_height,
13975 width = CLAMP (natural_width, min_width, available_width);
13977 clutter_actor_get_preferred_height (self, width,
13980 height = CLAMP (natural_height, min_height, available_height);
13983 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13984 clutter_actor_get_preferred_height (self, available_width,
13987 height = CLAMP (natural_height, min_height, available_height);
13989 clutter_actor_get_preferred_width (self, height,
13992 width = CLAMP (natural_width, min_width, available_width);
13999 box.x2 = box.x1 + width;
14000 box.y2 = box.y1 + height;
14001 clutter_actor_allocate (self, &box, flags);
14005 * clutter_actor_allocate_preferred_size:
14006 * @self: a #ClutterActor
14007 * @flags: flags controlling the allocation
14009 * Allocates the natural size of @self.
14011 * This function is a utility call for #ClutterActor implementations
14012 * that allocates the actor's preferred natural size. It can be used
14013 * by fixed layout managers (like #ClutterGroup or so called
14014 * 'composite actors') inside the ClutterActor::allocate
14015 * implementation to give each child exactly how much space it
14018 * This function is not meant to be used by applications. It is also
14019 * not meant to be used outside the implementation of the
14020 * ClutterActor::allocate virtual function.
14025 clutter_actor_allocate_preferred_size (ClutterActor *self,
14026 ClutterAllocationFlags flags)
14028 gfloat actor_x, actor_y;
14029 gfloat natural_width, natural_height;
14030 ClutterActorBox actor_box;
14032 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14034 actor_x = clutter_actor_get_x (self);
14035 actor_y = clutter_actor_get_y (self);
14037 clutter_actor_get_preferred_size (self,
14042 actor_box.x1 = actor_x;
14043 actor_box.y1 = actor_y;
14044 actor_box.x2 = actor_box.x1 + natural_width;
14045 actor_box.y2 = actor_box.y1 + natural_height;
14047 clutter_actor_allocate (self, &actor_box, flags);
14051 * clutter_actor_allocate_align_fill:
14052 * @self: a #ClutterActor
14053 * @box: a #ClutterActorBox, containing the available width and height
14054 * @x_align: the horizontal alignment, between 0 and 1
14055 * @y_align: the vertical alignment, between 0 and 1
14056 * @x_fill: whether the actor should fill horizontally
14057 * @y_fill: whether the actor should fill vertically
14058 * @flags: allocation flags to be passed to clutter_actor_allocate()
14060 * Allocates @self by taking into consideration the available allocation
14061 * area; an alignment factor on either axis; and whether the actor should
14062 * fill the allocation on either axis.
14064 * The @box should contain the available allocation width and height;
14065 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
14066 * allocation will be offset by their value.
14068 * This function takes into consideration the geometry request specified by
14069 * the #ClutterActor:request-mode property, and the text direction.
14071 * This function is useful for fluid layout managers, like #ClutterBinLayout
14072 * or #ClutterTableLayout
14077 clutter_actor_allocate_align_fill (ClutterActor *self,
14078 const ClutterActorBox *box,
14083 ClutterAllocationFlags flags)
14085 ClutterActorPrivate *priv;
14086 ClutterActorBox allocation = { 0, };
14087 gfloat x_offset, y_offset;
14088 gfloat available_width, available_height;
14089 gfloat child_width, child_height;
14091 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14092 g_return_if_fail (box != NULL);
14093 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
14094 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
14098 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
14099 clutter_actor_box_get_size (box, &available_width, &available_height);
14101 if (available_width < 0)
14102 available_width = 0;
14104 if (available_height < 0)
14105 available_height = 0;
14109 allocation.x1 = x_offset;
14110 allocation.x2 = allocation.x1 + available_width;
14115 allocation.y1 = y_offset;
14116 allocation.y2 = allocation.y1 + available_height;
14119 /* if we are filling horizontally and vertically then we're done */
14120 if (x_fill && y_fill)
14123 child_width = child_height = 0.0f;
14125 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
14127 gfloat min_width, natural_width;
14128 gfloat min_height, natural_height;
14130 clutter_actor_get_preferred_width (self, available_height,
14134 child_width = CLAMP (natural_width, min_width, available_width);
14138 clutter_actor_get_preferred_height (self, child_width,
14142 child_height = CLAMP (natural_height, min_height, available_height);
14147 gfloat min_width, natural_width;
14148 gfloat min_height, natural_height;
14150 clutter_actor_get_preferred_height (self, available_width,
14154 child_height = CLAMP (natural_height, min_height, available_height);
14158 clutter_actor_get_preferred_width (self, child_height,
14162 child_width = CLAMP (natural_width, min_width, available_width);
14166 /* invert the horizontal alignment for RTL languages */
14167 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
14168 x_align = 1.0 - x_align;
14172 allocation.x1 = x_offset
14173 + ((available_width - child_width) * x_align);
14174 allocation.x2 = allocation.x1 + child_width;
14179 allocation.y1 = y_offset
14180 + ((available_height - child_height) * y_align);
14181 allocation.y2 = allocation.y1 + child_height;
14185 clutter_actor_box_clamp_to_pixel (&allocation);
14186 clutter_actor_allocate (self, &allocation, flags);
14190 * clutter_actor_grab_key_focus:
14191 * @self: a #ClutterActor
14193 * Sets the key focus of the #ClutterStage including @self
14194 * to this #ClutterActor.
14199 clutter_actor_grab_key_focus (ClutterActor *self)
14201 ClutterActor *stage;
14203 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14205 stage = _clutter_actor_get_stage_internal (self);
14207 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14211 * clutter_actor_get_pango_context:
14212 * @self: a #ClutterActor
14214 * Retrieves the #PangoContext for @self. The actor's #PangoContext
14215 * is already configured using the appropriate font map, resolution
14216 * and font options.
14218 * Unlike clutter_actor_create_pango_context(), this context is owend
14219 * by the #ClutterActor and it will be updated each time the options
14220 * stored by the #ClutterBackend change.
14222 * You can use the returned #PangoContext to create a #PangoLayout
14223 * and render text using cogl_pango_render_layout() to reuse the
14224 * glyphs cache also used by Clutter.
14226 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14227 * The returned #PangoContext is owned by the actor and should not be
14228 * unreferenced by the application code
14233 clutter_actor_get_pango_context (ClutterActor *self)
14235 ClutterActorPrivate *priv;
14237 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14241 if (priv->pango_context != NULL)
14242 return priv->pango_context;
14244 priv->pango_context = _clutter_context_get_pango_context ();
14245 g_object_ref (priv->pango_context);
14247 return priv->pango_context;
14251 * clutter_actor_create_pango_context:
14252 * @self: a #ClutterActor
14254 * Creates a #PangoContext for the given actor. The #PangoContext
14255 * is already configured using the appropriate font map, resolution
14256 * and font options.
14258 * See also clutter_actor_get_pango_context().
14260 * Return value: (transfer full): the newly created #PangoContext.
14261 * Use g_object_unref() on the returned value to deallocate its
14267 clutter_actor_create_pango_context (ClutterActor *self)
14269 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14271 return _clutter_context_create_pango_context ();
14275 * clutter_actor_create_pango_layout:
14276 * @self: a #ClutterActor
14277 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14279 * Creates a new #PangoLayout from the same #PangoContext used
14280 * by the #ClutterActor. The #PangoLayout is already configured
14281 * with the font map, resolution and font options, and the
14284 * If you want to keep around a #PangoLayout created by this
14285 * function you will have to connect to the #ClutterBackend::font-changed
14286 * and #ClutterBackend::resolution-changed signals, and call
14287 * pango_layout_context_changed() in response to them.
14289 * Return value: (transfer full): the newly created #PangoLayout.
14290 * Use g_object_unref() when done
14295 clutter_actor_create_pango_layout (ClutterActor *self,
14298 PangoContext *context;
14299 PangoLayout *layout;
14301 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14303 context = clutter_actor_get_pango_context (self);
14304 layout = pango_layout_new (context);
14307 pango_layout_set_text (layout, text, -1);
14312 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14313 * ClutterOffscreenEffect.
14316 _clutter_actor_set_opacity_override (ClutterActor *self,
14319 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14321 self->priv->opacity_override = opacity;
14325 _clutter_actor_get_opacity_override (ClutterActor *self)
14327 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14329 return self->priv->opacity_override;
14332 /* Allows you to disable applying the actors model view transform during
14333 * a paint. Used by ClutterClone. */
14335 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14338 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14340 self->priv->enable_model_view_transform = enable;
14344 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14347 ClutterActorPrivate *priv;
14349 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14353 priv->enable_paint_unmapped = enable;
14355 if (priv->enable_paint_unmapped)
14357 /* Make sure that the parents of the widget are realized first;
14358 * otherwise checks in clutter_actor_update_map_state() will
14361 clutter_actor_realize (self);
14363 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14367 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14372 clutter_anchor_coord_get_units (ClutterActor *self,
14373 const AnchorCoord *coord,
14378 if (coord->is_fractional)
14380 gfloat actor_width, actor_height;
14382 clutter_actor_get_size (self, &actor_width, &actor_height);
14385 *x = actor_width * coord->v.fraction.x;
14388 *y = actor_height * coord->v.fraction.y;
14396 *x = coord->v.units.x;
14399 *y = coord->v.units.y;
14402 *z = coord->v.units.z;
14407 clutter_anchor_coord_set_units (AnchorCoord *coord,
14412 coord->is_fractional = FALSE;
14413 coord->v.units.x = x;
14414 coord->v.units.y = y;
14415 coord->v.units.z = z;
14418 static ClutterGravity
14419 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14421 if (coord->is_fractional)
14423 if (coord->v.fraction.x == 0.0)
14425 if (coord->v.fraction.y == 0.0)
14426 return CLUTTER_GRAVITY_NORTH_WEST;
14427 else if (coord->v.fraction.y == 0.5)
14428 return CLUTTER_GRAVITY_WEST;
14429 else if (coord->v.fraction.y == 1.0)
14430 return CLUTTER_GRAVITY_SOUTH_WEST;
14432 return CLUTTER_GRAVITY_NONE;
14434 else if (coord->v.fraction.x == 0.5)
14436 if (coord->v.fraction.y == 0.0)
14437 return CLUTTER_GRAVITY_NORTH;
14438 else if (coord->v.fraction.y == 0.5)
14439 return CLUTTER_GRAVITY_CENTER;
14440 else if (coord->v.fraction.y == 1.0)
14441 return CLUTTER_GRAVITY_SOUTH;
14443 return CLUTTER_GRAVITY_NONE;
14445 else if (coord->v.fraction.x == 1.0)
14447 if (coord->v.fraction.y == 0.0)
14448 return CLUTTER_GRAVITY_NORTH_EAST;
14449 else if (coord->v.fraction.y == 0.5)
14450 return CLUTTER_GRAVITY_EAST;
14451 else if (coord->v.fraction.y == 1.0)
14452 return CLUTTER_GRAVITY_SOUTH_EAST;
14454 return CLUTTER_GRAVITY_NONE;
14457 return CLUTTER_GRAVITY_NONE;
14460 return CLUTTER_GRAVITY_NONE;
14464 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14465 ClutterGravity gravity)
14469 case CLUTTER_GRAVITY_NORTH:
14470 coord->v.fraction.x = 0.5;
14471 coord->v.fraction.y = 0.0;
14474 case CLUTTER_GRAVITY_NORTH_EAST:
14475 coord->v.fraction.x = 1.0;
14476 coord->v.fraction.y = 0.0;
14479 case CLUTTER_GRAVITY_EAST:
14480 coord->v.fraction.x = 1.0;
14481 coord->v.fraction.y = 0.5;
14484 case CLUTTER_GRAVITY_SOUTH_EAST:
14485 coord->v.fraction.x = 1.0;
14486 coord->v.fraction.y = 1.0;
14489 case CLUTTER_GRAVITY_SOUTH:
14490 coord->v.fraction.x = 0.5;
14491 coord->v.fraction.y = 1.0;
14494 case CLUTTER_GRAVITY_SOUTH_WEST:
14495 coord->v.fraction.x = 0.0;
14496 coord->v.fraction.y = 1.0;
14499 case CLUTTER_GRAVITY_WEST:
14500 coord->v.fraction.x = 0.0;
14501 coord->v.fraction.y = 0.5;
14504 case CLUTTER_GRAVITY_NORTH_WEST:
14505 coord->v.fraction.x = 0.0;
14506 coord->v.fraction.y = 0.0;
14509 case CLUTTER_GRAVITY_CENTER:
14510 coord->v.fraction.x = 0.5;
14511 coord->v.fraction.y = 0.5;
14515 coord->v.fraction.x = 0.0;
14516 coord->v.fraction.y = 0.0;
14520 coord->is_fractional = TRUE;
14524 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14526 if (coord->is_fractional)
14527 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14529 return (coord->v.units.x == 0.0
14530 && coord->v.units.y == 0.0
14531 && coord->v.units.z == 0.0);
14535 * clutter_actor_get_flags:
14536 * @self: a #ClutterActor
14538 * Retrieves the flags set on @self
14540 * Return value: a bitwise or of #ClutterActorFlags or 0
14545 clutter_actor_get_flags (ClutterActor *self)
14547 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14549 return self->flags;
14553 * clutter_actor_set_flags:
14554 * @self: a #ClutterActor
14555 * @flags: the flags to set
14557 * Sets @flags on @self
14559 * This function will emit notifications for the changed properties
14564 clutter_actor_set_flags (ClutterActor *self,
14565 ClutterActorFlags flags)
14567 ClutterActorFlags old_flags;
14569 gboolean was_reactive_set, reactive_set;
14570 gboolean was_realized_set, realized_set;
14571 gboolean was_mapped_set, mapped_set;
14572 gboolean was_visible_set, visible_set;
14574 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14576 if (self->flags == flags)
14579 obj = G_OBJECT (self);
14580 g_object_ref (obj);
14581 g_object_freeze_notify (obj);
14583 old_flags = self->flags;
14585 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14586 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14587 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14588 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14590 self->flags |= flags;
14592 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14593 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14594 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14595 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14597 if (reactive_set != was_reactive_set)
14598 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14600 if (realized_set != was_realized_set)
14601 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14603 if (mapped_set != was_mapped_set)
14604 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14606 if (visible_set != was_visible_set)
14607 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14609 g_object_thaw_notify (obj);
14610 g_object_unref (obj);
14614 * clutter_actor_unset_flags:
14615 * @self: a #ClutterActor
14616 * @flags: the flags to unset
14618 * Unsets @flags on @self
14620 * This function will emit notifications for the changed properties
14625 clutter_actor_unset_flags (ClutterActor *self,
14626 ClutterActorFlags flags)
14628 ClutterActorFlags old_flags;
14630 gboolean was_reactive_set, reactive_set;
14631 gboolean was_realized_set, realized_set;
14632 gboolean was_mapped_set, mapped_set;
14633 gboolean was_visible_set, visible_set;
14635 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14637 obj = G_OBJECT (self);
14638 g_object_freeze_notify (obj);
14640 old_flags = self->flags;
14642 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14643 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14644 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14645 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14647 self->flags &= ~flags;
14649 if (self->flags == old_flags)
14652 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14653 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14654 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14655 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14657 if (reactive_set != was_reactive_set)
14658 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14660 if (realized_set != was_realized_set)
14661 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14663 if (mapped_set != was_mapped_set)
14664 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14666 if (visible_set != was_visible_set)
14667 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14669 g_object_thaw_notify (obj);
14673 * clutter_actor_get_transformation_matrix:
14674 * @self: a #ClutterActor
14675 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14677 * Retrieves the transformations applied to @self relative to its
14683 clutter_actor_get_transformation_matrix (ClutterActor *self,
14684 CoglMatrix *matrix)
14686 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14688 cogl_matrix_init_identity (matrix);
14690 _clutter_actor_apply_modelview_transform (self, matrix);
14694 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14695 gboolean is_in_clone_paint)
14697 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14698 self->priv->in_clone_paint = is_in_clone_paint;
14702 * clutter_actor_is_in_clone_paint:
14703 * @self: a #ClutterActor
14705 * Checks whether @self is being currently painted by a #ClutterClone
14707 * This function is useful only inside the ::paint virtual function
14708 * implementations or within handlers for the #ClutterActor::paint
14711 * This function should not be used by applications
14713 * Return value: %TRUE if the #ClutterActor is currently being painted
14714 * by a #ClutterClone, and %FALSE otherwise
14719 clutter_actor_is_in_clone_paint (ClutterActor *self)
14721 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14723 return self->priv->in_clone_paint;
14727 set_direction_recursive (ClutterActor *actor,
14728 gpointer user_data)
14730 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14732 clutter_actor_set_text_direction (actor, text_dir);
14738 * clutter_actor_set_text_direction:
14739 * @self: a #ClutterActor
14740 * @text_dir: the text direction for @self
14742 * Sets the #ClutterTextDirection for an actor
14744 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14746 * If @self implements #ClutterContainer then this function will recurse
14747 * inside all the children of @self (including the internal ones).
14749 * Composite actors not implementing #ClutterContainer, or actors requiring
14750 * special handling when the text direction changes, should connect to
14751 * the #GObject::notify signal for the #ClutterActor:text-direction property
14756 clutter_actor_set_text_direction (ClutterActor *self,
14757 ClutterTextDirection text_dir)
14759 ClutterActorPrivate *priv;
14761 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14762 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14766 if (priv->text_direction != text_dir)
14768 priv->text_direction = text_dir;
14770 /* we need to emit the notify::text-direction first, so that
14771 * the sub-classes can catch that and do specific handling of
14772 * the text direction; see clutter_text_direction_changed_cb()
14773 * inside clutter-text.c
14775 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14777 _clutter_actor_foreach_child (self, set_direction_recursive,
14778 GINT_TO_POINTER (text_dir));
14780 clutter_actor_queue_relayout (self);
14785 _clutter_actor_set_has_pointer (ClutterActor *self,
14786 gboolean has_pointer)
14788 ClutterActorPrivate *priv = self->priv;
14790 if (priv->has_pointer != has_pointer)
14792 priv->has_pointer = has_pointer;
14794 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14799 * clutter_actor_get_text_direction:
14800 * @self: a #ClutterActor
14802 * Retrieves the value set using clutter_actor_set_text_direction()
14804 * If no text direction has been previously set, the default text
14805 * direction, as returned by clutter_get_default_text_direction(), will
14806 * be returned instead
14808 * Return value: the #ClutterTextDirection for the actor
14812 ClutterTextDirection
14813 clutter_actor_get_text_direction (ClutterActor *self)
14815 ClutterActorPrivate *priv;
14817 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14818 CLUTTER_TEXT_DIRECTION_LTR);
14822 /* if no direction has been set yet use the default */
14823 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14824 priv->text_direction = clutter_get_default_text_direction ();
14826 return priv->text_direction;
14830 * clutter_actor_push_internal:
14831 * @self: a #ClutterActor
14833 * Should be used by actors implementing the #ClutterContainer and with
14834 * internal children added through clutter_actor_set_parent(), for instance:
14838 * my_actor_init (MyActor *self)
14840 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14842 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14844 * /* calling clutter_actor_set_parent() now will result in
14845 * * the internal flag being set on a child of MyActor
14848 * /* internal child - a background texture */
14849 * self->priv->background_tex = clutter_texture_new ();
14850 * clutter_actor_set_parent (self->priv->background_tex,
14851 * CLUTTER_ACTOR (self));
14853 * /* internal child - a label */
14854 * self->priv->label = clutter_text_new ();
14855 * clutter_actor_set_parent (self->priv->label,
14856 * CLUTTER_ACTOR (self));
14858 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14860 * /* calling clutter_actor_set_parent() now will not result in
14861 * * the internal flag being set on a child of MyActor
14866 * This function will be used by Clutter to toggle an "internal child"
14867 * flag whenever clutter_actor_set_parent() is called; internal children
14868 * are handled differently by Clutter, specifically when destroying their
14871 * Call clutter_actor_pop_internal() when you finished adding internal
14874 * Nested calls to clutter_actor_push_internal() are allowed, but each
14875 * one must by followed by a clutter_actor_pop_internal() call.
14879 * Deprecated: 1.10: All children of an actor are accessible through
14880 * the #ClutterActor API, and #ClutterActor implements the
14881 * #ClutterContainer interface, so this function is only useful
14882 * for legacy containers overriding the default implementation.
14885 clutter_actor_push_internal (ClutterActor *self)
14887 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14889 self->priv->internal_child += 1;
14893 * clutter_actor_pop_internal:
14894 * @self: a #ClutterActor
14896 * Disables the effects of clutter_actor_push_internal().
14900 * Deprecated: 1.10: All children of an actor are accessible through
14901 * the #ClutterActor API. This function is only useful for legacy
14902 * containers overriding the default implementation of the
14903 * #ClutterContainer interface.
14906 clutter_actor_pop_internal (ClutterActor *self)
14908 ClutterActorPrivate *priv;
14910 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14914 if (priv->internal_child == 0)
14916 g_warning ("Mismatched %s: you need to call "
14917 "clutter_actor_push_composite() at least once before "
14918 "calling this function", G_STRFUNC);
14922 priv->internal_child -= 1;
14926 * clutter_actor_has_pointer:
14927 * @self: a #ClutterActor
14929 * Checks whether an actor contains the pointer of a
14930 * #ClutterInputDevice
14932 * Return value: %TRUE if the actor contains the pointer, and
14938 clutter_actor_has_pointer (ClutterActor *self)
14940 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14942 return self->priv->has_pointer;
14945 /* XXX: This is a workaround for not being able to break the ABI of
14946 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14947 * clutter_actor_queue_clipped_redraw() for details.
14949 ClutterPaintVolume *
14950 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14952 return g_object_get_data (G_OBJECT (self),
14953 "-clutter-actor-queue-redraw-clip");
14957 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14958 ClutterPaintVolume *clip)
14960 g_object_set_data (G_OBJECT (self),
14961 "-clutter-actor-queue-redraw-clip",
14966 * clutter_actor_has_allocation:
14967 * @self: a #ClutterActor
14969 * Checks if the actor has an up-to-date allocation assigned to
14970 * it. This means that the actor should have an allocation: it's
14971 * visible and has a parent. It also means that there is no
14972 * outstanding relayout request in progress for the actor or its
14973 * children (There might be other outstanding layout requests in
14974 * progress that will cause the actor to get a new allocation
14975 * when the stage is laid out, however).
14977 * If this function returns %FALSE, then the actor will normally
14978 * be allocated before it is next drawn on the screen.
14980 * Return value: %TRUE if the actor has an up-to-date allocation
14985 clutter_actor_has_allocation (ClutterActor *self)
14987 ClutterActorPrivate *priv;
14989 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14993 return priv->parent != NULL &&
14994 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14995 !priv->needs_allocation;
14999 * clutter_actor_add_action:
15000 * @self: a #ClutterActor
15001 * @action: a #ClutterAction
15003 * Adds @action to the list of actions applied to @self
15005 * A #ClutterAction can only belong to one actor at a time
15007 * The #ClutterActor will hold a reference on @action until either
15008 * clutter_actor_remove_action() or clutter_actor_clear_actions()
15014 clutter_actor_add_action (ClutterActor *self,
15015 ClutterAction *action)
15017 ClutterActorPrivate *priv;
15019 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15020 g_return_if_fail (CLUTTER_IS_ACTION (action));
15024 if (priv->actions == NULL)
15026 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15027 priv->actions->actor = self;
15030 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
15032 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15036 * clutter_actor_add_action_with_name:
15037 * @self: a #ClutterActor
15038 * @name: the name to set on the action
15039 * @action: a #ClutterAction
15041 * A convenience function for setting the name of a #ClutterAction
15042 * while adding it to the list of actions applied to @self
15044 * This function is the logical equivalent of:
15047 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15048 * clutter_actor_add_action (self, action);
15054 clutter_actor_add_action_with_name (ClutterActor *self,
15056 ClutterAction *action)
15058 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15059 g_return_if_fail (name != NULL);
15060 g_return_if_fail (CLUTTER_IS_ACTION (action));
15062 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15063 clutter_actor_add_action (self, action);
15067 * clutter_actor_remove_action:
15068 * @self: a #ClutterActor
15069 * @action: a #ClutterAction
15071 * Removes @action from the list of actions applied to @self
15073 * The reference held by @self on the #ClutterAction will be released
15078 clutter_actor_remove_action (ClutterActor *self,
15079 ClutterAction *action)
15081 ClutterActorPrivate *priv;
15083 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15084 g_return_if_fail (CLUTTER_IS_ACTION (action));
15088 if (priv->actions == NULL)
15091 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
15093 if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
15094 g_clear_object (&priv->actions);
15096 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15100 * clutter_actor_remove_action_by_name:
15101 * @self: a #ClutterActor
15102 * @name: the name of the action to remove
15104 * Removes the #ClutterAction with the given name from the list
15105 * of actions applied to @self
15110 clutter_actor_remove_action_by_name (ClutterActor *self,
15113 ClutterActorPrivate *priv;
15114 ClutterActorMeta *meta;
15116 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15117 g_return_if_fail (name != NULL);
15121 if (priv->actions == NULL)
15124 meta = _clutter_meta_group_get_meta (priv->actions, name);
15128 _clutter_meta_group_remove_meta (priv->actions, meta);
15130 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15134 * clutter_actor_get_actions:
15135 * @self: a #ClutterActor
15137 * Retrieves the list of actions applied to @self
15139 * Return value: (transfer container) (element-type Clutter.Action): a copy
15140 * of the list of #ClutterAction<!-- -->s. The contents of the list are
15141 * owned by the #ClutterActor. Use g_list_free() to free the resources
15142 * allocated by the returned #GList
15147 clutter_actor_get_actions (ClutterActor *self)
15149 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15151 if (self->priv->actions == NULL)
15154 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
15158 * clutter_actor_get_action:
15159 * @self: a #ClutterActor
15160 * @name: the name of the action to retrieve
15162 * Retrieves the #ClutterAction with the given name in the list
15163 * of actions applied to @self
15165 * Return value: (transfer none): a #ClutterAction for the given
15166 * name, or %NULL. The returned #ClutterAction is owned by the
15167 * actor and it should not be unreferenced directly
15172 clutter_actor_get_action (ClutterActor *self,
15175 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15176 g_return_val_if_fail (name != NULL, NULL);
15178 if (self->priv->actions == NULL)
15181 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
15185 * clutter_actor_clear_actions:
15186 * @self: a #ClutterActor
15188 * Clears the list of actions applied to @self
15193 clutter_actor_clear_actions (ClutterActor *self)
15195 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15197 if (self->priv->actions == NULL)
15200 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
15204 * clutter_actor_add_constraint:
15205 * @self: a #ClutterActor
15206 * @constraint: a #ClutterConstraint
15208 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15211 * The #ClutterActor will hold a reference on the @constraint until
15212 * either clutter_actor_remove_constraint() or
15213 * clutter_actor_clear_constraints() is called.
15218 clutter_actor_add_constraint (ClutterActor *self,
15219 ClutterConstraint *constraint)
15221 ClutterActorPrivate *priv;
15223 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15224 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15228 if (priv->constraints == NULL)
15230 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15231 priv->constraints->actor = self;
15234 _clutter_meta_group_add_meta (priv->constraints,
15235 CLUTTER_ACTOR_META (constraint));
15236 clutter_actor_queue_relayout (self);
15238 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15242 * clutter_actor_add_constraint_with_name:
15243 * @self: a #ClutterActor
15244 * @name: the name to set on the constraint
15245 * @constraint: a #ClutterConstraint
15247 * A convenience function for setting the name of a #ClutterConstraint
15248 * while adding it to the list of constraints applied to @self
15250 * This function is the logical equivalent of:
15253 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15254 * clutter_actor_add_constraint (self, constraint);
15260 clutter_actor_add_constraint_with_name (ClutterActor *self,
15262 ClutterConstraint *constraint)
15264 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15265 g_return_if_fail (name != NULL);
15266 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15268 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15269 clutter_actor_add_constraint (self, constraint);
15273 * clutter_actor_remove_constraint:
15274 * @self: a #ClutterActor
15275 * @constraint: a #ClutterConstraint
15277 * Removes @constraint from the list of constraints applied to @self
15279 * The reference held by @self on the #ClutterConstraint will be released
15284 clutter_actor_remove_constraint (ClutterActor *self,
15285 ClutterConstraint *constraint)
15287 ClutterActorPrivate *priv;
15289 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15290 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15294 if (priv->constraints == NULL)
15297 _clutter_meta_group_remove_meta (priv->constraints,
15298 CLUTTER_ACTOR_META (constraint));
15300 if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15301 g_clear_object (&priv->constraints);
15303 clutter_actor_queue_relayout (self);
15305 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15309 * clutter_actor_remove_constraint_by_name:
15310 * @self: a #ClutterActor
15311 * @name: the name of the constraint to remove
15313 * Removes the #ClutterConstraint with the given name from the list
15314 * of constraints applied to @self
15319 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15322 ClutterActorPrivate *priv;
15323 ClutterActorMeta *meta;
15325 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15326 g_return_if_fail (name != NULL);
15330 if (priv->constraints == NULL)
15333 meta = _clutter_meta_group_get_meta (priv->constraints, name);
15337 _clutter_meta_group_remove_meta (priv->constraints, meta);
15338 clutter_actor_queue_relayout (self);
15342 * clutter_actor_get_constraints:
15343 * @self: a #ClutterActor
15345 * Retrieves the list of constraints applied to @self
15347 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15348 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15349 * owned by the #ClutterActor. Use g_list_free() to free the resources
15350 * allocated by the returned #GList
15355 clutter_actor_get_constraints (ClutterActor *self)
15357 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15359 if (self->priv->constraints == NULL)
15362 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15366 * clutter_actor_get_constraint:
15367 * @self: a #ClutterActor
15368 * @name: the name of the constraint to retrieve
15370 * Retrieves the #ClutterConstraint with the given name in the list
15371 * of constraints applied to @self
15373 * Return value: (transfer none): a #ClutterConstraint for the given
15374 * name, or %NULL. The returned #ClutterConstraint is owned by the
15375 * actor and it should not be unreferenced directly
15379 ClutterConstraint *
15380 clutter_actor_get_constraint (ClutterActor *self,
15383 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15384 g_return_val_if_fail (name != NULL, NULL);
15386 if (self->priv->constraints == NULL)
15389 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15393 * clutter_actor_clear_constraints:
15394 * @self: a #ClutterActor
15396 * Clears the list of constraints applied to @self
15401 clutter_actor_clear_constraints (ClutterActor *self)
15403 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15405 if (self->priv->constraints == NULL)
15408 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15410 clutter_actor_queue_relayout (self);
15414 * clutter_actor_set_clip_to_allocation:
15415 * @self: a #ClutterActor
15416 * @clip_set: %TRUE to apply a clip tracking the allocation
15418 * Sets whether @self should be clipped to the same size as its
15424 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15427 ClutterActorPrivate *priv;
15429 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15431 clip_set = !!clip_set;
15435 if (priv->clip_to_allocation != clip_set)
15437 priv->clip_to_allocation = clip_set;
15439 clutter_actor_queue_redraw (self);
15441 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15446 * clutter_actor_get_clip_to_allocation:
15447 * @self: a #ClutterActor
15449 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15451 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15456 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15458 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15460 return self->priv->clip_to_allocation;
15464 * clutter_actor_add_effect:
15465 * @self: a #ClutterActor
15466 * @effect: a #ClutterEffect
15468 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15470 * The #ClutterActor will hold a reference on the @effect until either
15471 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15477 clutter_actor_add_effect (ClutterActor *self,
15478 ClutterEffect *effect)
15480 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15481 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15483 _clutter_actor_add_effect_internal (self, effect);
15485 clutter_actor_queue_redraw (self);
15487 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15491 * clutter_actor_add_effect_with_name:
15492 * @self: a #ClutterActor
15493 * @name: the name to set on the effect
15494 * @effect: a #ClutterEffect
15496 * A convenience function for setting the name of a #ClutterEffect
15497 * while adding it to the list of effectss applied to @self
15499 * This function is the logical equivalent of:
15502 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15503 * clutter_actor_add_effect (self, effect);
15509 clutter_actor_add_effect_with_name (ClutterActor *self,
15511 ClutterEffect *effect)
15513 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15514 g_return_if_fail (name != NULL);
15515 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15517 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15518 clutter_actor_add_effect (self, effect);
15522 * clutter_actor_remove_effect:
15523 * @self: a #ClutterActor
15524 * @effect: a #ClutterEffect
15526 * Removes @effect from the list of effects applied to @self
15528 * The reference held by @self on the #ClutterEffect will be released
15533 clutter_actor_remove_effect (ClutterActor *self,
15534 ClutterEffect *effect)
15536 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15537 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15539 _clutter_actor_remove_effect_internal (self, effect);
15541 clutter_actor_queue_redraw (self);
15543 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15547 * clutter_actor_remove_effect_by_name:
15548 * @self: a #ClutterActor
15549 * @name: the name of the effect to remove
15551 * Removes the #ClutterEffect with the given name from the list
15552 * of effects applied to @self
15557 clutter_actor_remove_effect_by_name (ClutterActor *self,
15560 ClutterActorPrivate *priv;
15561 ClutterActorMeta *meta;
15563 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15564 g_return_if_fail (name != NULL);
15568 if (priv->effects == NULL)
15571 meta = _clutter_meta_group_get_meta (priv->effects, name);
15575 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15579 * clutter_actor_get_effects:
15580 * @self: a #ClutterActor
15582 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15584 * Return value: (transfer container) (element-type Clutter.Effect): a list
15585 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15586 * list are owned by Clutter and they should not be freed. You should
15587 * free the returned list using g_list_free() when done
15592 clutter_actor_get_effects (ClutterActor *self)
15594 ClutterActorPrivate *priv;
15596 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15600 if (priv->effects == NULL)
15603 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15607 * clutter_actor_get_effect:
15608 * @self: a #ClutterActor
15609 * @name: the name of the effect to retrieve
15611 * Retrieves the #ClutterEffect with the given name in the list
15612 * of effects applied to @self
15614 * Return value: (transfer none): a #ClutterEffect for the given
15615 * name, or %NULL. The returned #ClutterEffect is owned by the
15616 * actor and it should not be unreferenced directly
15621 clutter_actor_get_effect (ClutterActor *self,
15624 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15625 g_return_val_if_fail (name != NULL, NULL);
15627 if (self->priv->effects == NULL)
15630 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15634 * clutter_actor_clear_effects:
15635 * @self: a #ClutterActor
15637 * Clears the list of effects applied to @self
15642 clutter_actor_clear_effects (ClutterActor *self)
15644 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15646 if (self->priv->effects == NULL)
15649 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15651 clutter_actor_queue_redraw (self);
15655 * clutter_actor_has_key_focus:
15656 * @self: a #ClutterActor
15658 * Checks whether @self is the #ClutterActor that has key focus
15660 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15665 clutter_actor_has_key_focus (ClutterActor *self)
15667 ClutterActor *stage;
15669 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15671 stage = _clutter_actor_get_stage_internal (self);
15675 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15679 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15680 ClutterPaintVolume *pv)
15682 ClutterActorPrivate *priv = self->priv;
15684 /* Actors are only expected to report a valid paint volume
15685 * while they have a valid allocation. */
15686 if (G_UNLIKELY (priv->needs_allocation))
15688 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15689 "Actor needs allocation",
15690 _clutter_actor_get_debug_name (self));
15694 /* Check if there are any handlers connected to the paint
15695 * signal. If there are then all bets are off for what the paint
15696 * volume for this actor might possibly be!
15698 * XXX: It's expected that this is going to end up being quite a
15699 * costly check to have to do here, but we haven't come up with
15700 * another solution that can reliably catch paint signal handlers at
15701 * the right time to either avoid artefacts due to invalid stage
15702 * clipping or due to incorrect culling.
15704 * Previously we checked in clutter_actor_paint(), but at that time
15705 * we may already be using a stage clip that could be derived from
15706 * an invalid paint-volume. We used to try and handle that by
15707 * queuing a follow up, unclipped, redraw but still the previous
15708 * checking wasn't enough to catch invalid volumes involved in
15709 * culling (considering that containers may derive their volume from
15710 * children that haven't yet been painted)
15712 * Longer term, improved solutions could be:
15713 * - Disallow painting in the paint signal, only allow using it
15714 * for tracking when paints happen. We can add another API that
15715 * allows monkey patching the paint of arbitrary actors but in a
15716 * more controlled way and that also supports modifying the
15718 * - If we could be notified somehow when signal handlers are
15719 * connected we wouldn't have to poll for handlers like this.
15721 if (g_signal_has_handler_pending (self,
15722 actor_signals[PAINT],
15726 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15727 "Actor has \"paint\" signal handlers",
15728 _clutter_actor_get_debug_name (self));
15732 _clutter_paint_volume_init_static (pv, self);
15734 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15736 clutter_paint_volume_free (pv);
15737 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15738 "Actor failed to report a volume",
15739 _clutter_actor_get_debug_name (self));
15743 /* since effects can modify the paint volume, we allow them to actually
15744 * do this by making get_paint_volume() "context sensitive"
15746 if (priv->effects != NULL)
15748 if (priv->current_effect != NULL)
15750 const GList *effects, *l;
15752 /* if we are being called from within the paint sequence of
15753 * an actor, get the paint volume up to the current effect
15755 effects = _clutter_meta_group_peek_metas (priv->effects);
15757 l != NULL || (l != NULL && l->data != priv->current_effect);
15760 if (!_clutter_effect_get_paint_volume (l->data, pv))
15762 clutter_paint_volume_free (pv);
15763 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15764 "Effect (%s) failed to report a volume",
15765 _clutter_actor_get_debug_name (self),
15766 _clutter_actor_meta_get_debug_name (l->data));
15773 const GList *effects, *l;
15775 /* otherwise, get the cumulative volume */
15776 effects = _clutter_meta_group_peek_metas (priv->effects);
15777 for (l = effects; l != NULL; l = l->next)
15778 if (!_clutter_effect_get_paint_volume (l->data, pv))
15780 clutter_paint_volume_free (pv);
15781 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15782 "Effect (%s) failed to report a volume",
15783 _clutter_actor_get_debug_name (self),
15784 _clutter_actor_meta_get_debug_name (l->data));
15793 /* The public clutter_actor_get_paint_volume API returns a const
15794 * pointer since we return a pointer directly to the cached
15795 * PaintVolume associated with the actor and don't want the user to
15796 * inadvertently modify it, but for internal uses we sometimes need
15797 * access to the same PaintVolume but need to apply some book-keeping
15798 * modifications to it so we don't want a const pointer.
15800 static ClutterPaintVolume *
15801 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15803 ClutterActorPrivate *priv;
15807 if (priv->paint_volume_valid)
15808 clutter_paint_volume_free (&priv->paint_volume);
15810 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15812 priv->paint_volume_valid = TRUE;
15813 return &priv->paint_volume;
15817 priv->paint_volume_valid = FALSE;
15823 * clutter_actor_get_paint_volume:
15824 * @self: a #ClutterActor
15826 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15827 * when a paint volume can't be determined.
15829 * The paint volume is defined as the 3D space occupied by an actor
15830 * when being painted.
15832 * This function will call the <function>get_paint_volume()</function>
15833 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15834 * should not usually care about overriding the default implementation,
15835 * unless they are, for instance: painting outside their allocation, or
15836 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15839 * <note>2D actors overriding <function>get_paint_volume()</function>
15840 * ensure their volume has a depth of 0. (This will be true so long as
15841 * you don't call clutter_paint_volume_set_depth().)</note>
15843 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15844 * or %NULL if no volume could be determined. The returned pointer
15845 * is not guaranteed to be valid across multiple frames; if you want
15846 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15850 const ClutterPaintVolume *
15851 clutter_actor_get_paint_volume (ClutterActor *self)
15853 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15855 return _clutter_actor_get_paint_volume_mutable (self);
15859 * clutter_actor_get_transformed_paint_volume:
15860 * @self: a #ClutterActor
15861 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15862 * (or %NULL for the stage)
15864 * Retrieves the 3D paint volume of an actor like
15865 * clutter_actor_get_paint_volume() does (Please refer to the
15866 * documentation of clutter_actor_get_paint_volume() for more
15867 * details.) and it additionally transforms the paint volume into the
15868 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15869 * is passed for @relative_to_ancestor)
15871 * This can be used by containers that base their paint volume on
15872 * the volume of their children. Such containers can query the
15873 * transformed paint volume of all of its children and union them
15874 * together using clutter_paint_volume_union().
15876 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15877 * or %NULL if no volume could be determined. The returned pointer is
15878 * not guaranteed to be valid across multiple frames; if you wish to
15879 * keep it, you will have to copy it using clutter_paint_volume_copy().
15883 const ClutterPaintVolume *
15884 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15885 ClutterActor *relative_to_ancestor)
15887 const ClutterPaintVolume *volume;
15888 ClutterActor *stage;
15889 ClutterPaintVolume *transformed_volume;
15891 stage = _clutter_actor_get_stage_internal (self);
15892 if (G_UNLIKELY (stage == NULL))
15895 if (relative_to_ancestor == NULL)
15896 relative_to_ancestor = stage;
15898 volume = clutter_actor_get_paint_volume (self);
15899 if (volume == NULL)
15902 transformed_volume =
15903 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15905 _clutter_paint_volume_copy_static (volume, transformed_volume);
15907 _clutter_paint_volume_transform_relative (transformed_volume,
15908 relative_to_ancestor);
15910 return transformed_volume;
15914 * clutter_actor_get_paint_box:
15915 * @self: a #ClutterActor
15916 * @box: (out): return location for a #ClutterActorBox
15918 * Retrieves the paint volume of the passed #ClutterActor, and
15919 * transforms it into a 2D bounding box in stage coordinates.
15921 * This function is useful to determine the on screen area occupied by
15922 * the actor. The box is only an approximation and may often be
15923 * considerably larger due to the optimizations used to calculate the
15924 * box. The box is never smaller though, so it can reliably be used
15927 * There are times when a 2D paint box can't be determined, e.g.
15928 * because the actor isn't yet parented under a stage or because
15929 * the actor is unable to determine a paint volume.
15931 * Return value: %TRUE if a 2D paint box could be determined, else
15937 clutter_actor_get_paint_box (ClutterActor *self,
15938 ClutterActorBox *box)
15940 ClutterActor *stage;
15941 ClutterPaintVolume *pv;
15943 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15944 g_return_val_if_fail (box != NULL, FALSE);
15946 stage = _clutter_actor_get_stage_internal (self);
15947 if (G_UNLIKELY (!stage))
15950 pv = _clutter_actor_get_paint_volume_mutable (self);
15951 if (G_UNLIKELY (!pv))
15954 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15960 * clutter_actor_has_overlaps:
15961 * @self: A #ClutterActor
15963 * Asks the actor's implementation whether it may contain overlapping
15966 * For example; Clutter may use this to determine whether the painting
15967 * should be redirected to an offscreen buffer to correctly implement
15968 * the opacity property.
15970 * Custom actors can override the default response by implementing the
15971 * #ClutterActor <function>has_overlaps</function> virtual function. See
15972 * clutter_actor_set_offscreen_redirect() for more information.
15974 * Return value: %TRUE if the actor may have overlapping primitives, and
15980 clutter_actor_has_overlaps (ClutterActor *self)
15982 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15984 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15988 * clutter_actor_has_effects:
15989 * @self: A #ClutterActor
15991 * Returns whether the actor has any effects applied.
15993 * Return value: %TRUE if the actor has any effects,
15999 clutter_actor_has_effects (ClutterActor *self)
16001 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16003 if (self->priv->effects == NULL)
16006 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
16010 * clutter_actor_has_constraints:
16011 * @self: A #ClutterActor
16013 * Returns whether the actor has any constraints applied.
16015 * Return value: %TRUE if the actor has any constraints,
16021 clutter_actor_has_constraints (ClutterActor *self)
16023 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16025 return self->priv->constraints != NULL;
16029 * clutter_actor_has_actions:
16030 * @self: A #ClutterActor
16032 * Returns whether the actor has any actions applied.
16034 * Return value: %TRUE if the actor has any actions,
16040 clutter_actor_has_actions (ClutterActor *self)
16042 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16044 return self->priv->actions != NULL;
16048 * clutter_actor_get_n_children:
16049 * @self: a #ClutterActor
16051 * Retrieves the number of children of @self.
16053 * Return value: the number of children of an actor
16058 clutter_actor_get_n_children (ClutterActor *self)
16060 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
16062 return self->priv->n_children;
16066 * clutter_actor_get_child_at_index:
16067 * @self: a #ClutterActor
16068 * @index_: the position in the list of children
16070 * Retrieves the actor at the given @index_ inside the list of
16071 * children of @self.
16073 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16078 clutter_actor_get_child_at_index (ClutterActor *self,
16081 ClutterActor *iter;
16084 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16085 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
16087 for (iter = self->priv->first_child, i = 0;
16088 iter != NULL && i < index_;
16089 iter = iter->priv->next_sibling, i += 1)
16096 * _clutter_actor_foreach_child:
16097 * @actor: The actor whos children you want to iterate
16098 * @callback: The function to call for each child
16099 * @user_data: Private data to pass to @callback
16101 * Calls a given @callback once for each child of the specified @actor and
16102 * passing the @user_data pointer each time.
16104 * Return value: returns %TRUE if all children were iterated, else
16105 * %FALSE if a callback broke out of iteration early.
16108 _clutter_actor_foreach_child (ClutterActor *self,
16109 ClutterForeachCallback callback,
16110 gpointer user_data)
16112 ClutterActor *iter;
16115 if (self->priv->first_child == NULL)
16119 iter = self->priv->first_child;
16121 /* we use this form so that it's safe to change the children
16122 * list while iterating it
16124 while (cont && iter != NULL)
16126 ClutterActor *next = iter->priv->next_sibling;
16128 cont = callback (iter, user_data);
16137 /* For debugging purposes this gives us a simple way to print out
16138 * the scenegraph e.g in gdb using:
16140 * _clutter_actor_traverse (stage,
16142 * clutter_debug_print_actor_cb,
16147 static ClutterActorTraverseVisitFlags
16148 clutter_debug_print_actor_cb (ClutterActor *actor,
16152 g_print ("%*s%s:%p\n",
16154 _clutter_actor_get_debug_name (actor),
16157 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16162 _clutter_actor_traverse_breadth (ClutterActor *actor,
16163 ClutterTraverseCallback callback,
16164 gpointer user_data)
16166 GQueue *queue = g_queue_new ();
16167 ClutterActor dummy;
16168 int current_depth = 0;
16170 g_queue_push_tail (queue, actor);
16171 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
16173 while ((actor = g_queue_pop_head (queue)))
16175 ClutterActorTraverseVisitFlags flags;
16177 if (actor == &dummy)
16180 g_queue_push_tail (queue, &dummy);
16184 flags = callback (actor, current_depth, user_data);
16185 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16187 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16189 ClutterActor *iter;
16191 for (iter = actor->priv->first_child;
16193 iter = iter->priv->next_sibling)
16195 g_queue_push_tail (queue, iter);
16200 g_queue_free (queue);
16203 static ClutterActorTraverseVisitFlags
16204 _clutter_actor_traverse_depth (ClutterActor *actor,
16205 ClutterTraverseCallback before_children_callback,
16206 ClutterTraverseCallback after_children_callback,
16208 gpointer user_data)
16210 ClutterActorTraverseVisitFlags flags;
16212 flags = before_children_callback (actor, current_depth, user_data);
16213 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16214 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16216 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16218 ClutterActor *iter;
16220 for (iter = actor->priv->first_child;
16222 iter = iter->priv->next_sibling)
16224 flags = _clutter_actor_traverse_depth (iter,
16225 before_children_callback,
16226 after_children_callback,
16230 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16231 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16235 if (after_children_callback)
16236 return after_children_callback (actor, current_depth, user_data);
16238 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16241 /* _clutter_actor_traverse:
16242 * @actor: The actor to start traversing the graph from
16243 * @flags: These flags may affect how the traversal is done
16244 * @before_children_callback: A function to call before visiting the
16245 * children of the current actor.
16246 * @after_children_callback: A function to call after visiting the
16247 * children of the current actor. (Ignored if
16248 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16249 * @user_data: The private data to pass to the callbacks
16251 * Traverses the scenegraph starting at the specified @actor and
16252 * descending through all its children and its children's children.
16253 * For each actor traversed @before_children_callback and
16254 * @after_children_callback are called with the specified
16255 * @user_data, before and after visiting that actor's children.
16257 * The callbacks can return flags that affect the ongoing traversal
16258 * such as by skipping over an actors children or bailing out of
16259 * any further traversing.
16262 _clutter_actor_traverse (ClutterActor *actor,
16263 ClutterActorTraverseFlags flags,
16264 ClutterTraverseCallback before_children_callback,
16265 ClutterTraverseCallback after_children_callback,
16266 gpointer user_data)
16268 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16269 _clutter_actor_traverse_breadth (actor,
16270 before_children_callback,
16272 else /* DEPTH_FIRST */
16273 _clutter_actor_traverse_depth (actor,
16274 before_children_callback,
16275 after_children_callback,
16276 0, /* start depth */
16281 on_layout_manager_changed (ClutterLayoutManager *manager,
16282 ClutterActor *self)
16284 clutter_actor_queue_relayout (self);
16288 * clutter_actor_set_layout_manager:
16289 * @self: a #ClutterActor
16290 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16292 * Sets the #ClutterLayoutManager delegate object that will be used to
16293 * lay out the children of @self.
16295 * The #ClutterActor will take a reference on the passed @manager which
16296 * will be released either when the layout manager is removed, or when
16297 * the actor is destroyed.
16302 clutter_actor_set_layout_manager (ClutterActor *self,
16303 ClutterLayoutManager *manager)
16305 ClutterActorPrivate *priv;
16307 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16308 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16312 if (priv->layout_manager != NULL)
16314 g_signal_handlers_disconnect_by_func (priv->layout_manager,
16315 G_CALLBACK (on_layout_manager_changed),
16317 clutter_layout_manager_set_container (priv->layout_manager, NULL);
16318 g_clear_object (&priv->layout_manager);
16321 priv->layout_manager = manager;
16323 if (priv->layout_manager != NULL)
16325 g_object_ref_sink (priv->layout_manager);
16326 clutter_layout_manager_set_container (priv->layout_manager,
16327 CLUTTER_CONTAINER (self));
16328 g_signal_connect (priv->layout_manager, "layout-changed",
16329 G_CALLBACK (on_layout_manager_changed),
16333 clutter_actor_queue_relayout (self);
16335 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16339 * clutter_actor_get_layout_manager:
16340 * @self: a #ClutterActor
16342 * Retrieves the #ClutterLayoutManager used by @self.
16344 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16349 ClutterLayoutManager *
16350 clutter_actor_get_layout_manager (ClutterActor *self)
16352 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16354 return self->priv->layout_manager;
16357 static const ClutterLayoutInfo default_layout_info = {
16358 CLUTTER_POINT_INIT_ZERO, /* fixed-pos */
16359 { 0, 0, 0, 0 }, /* margin */
16360 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
16361 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
16362 FALSE, FALSE, /* expand */
16363 CLUTTER_SIZE_INIT_ZERO, /* minimum */
16364 CLUTTER_SIZE_INIT_ZERO, /* natural */
16368 layout_info_free (gpointer data)
16370 if (G_LIKELY (data != NULL))
16371 g_slice_free (ClutterLayoutInfo, data);
16375 * _clutter_actor_peek_layout_info:
16376 * @self: a #ClutterActor
16378 * Retrieves a pointer to the ClutterLayoutInfo structure.
16380 * If the actor does not have a ClutterLayoutInfo associated to it, %NULL is returned.
16382 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16384 ClutterLayoutInfo *
16385 _clutter_actor_peek_layout_info (ClutterActor *self)
16387 return g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16391 * _clutter_actor_get_layout_info:
16392 * @self: a #ClutterActor
16394 * Retrieves a pointer to the ClutterLayoutInfo structure.
16396 * If the actor does not have a ClutterLayoutInfo associated to it, one
16397 * will be created and initialized to the default values.
16399 * This function should be used for setters.
16401 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16404 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16406 ClutterLayoutInfo *
16407 _clutter_actor_get_layout_info (ClutterActor *self)
16409 ClutterLayoutInfo *retval;
16411 retval = _clutter_actor_peek_layout_info (self);
16412 if (retval == NULL)
16414 retval = g_slice_new (ClutterLayoutInfo);
16416 *retval = default_layout_info;
16418 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16427 * _clutter_actor_get_layout_info_or_defaults:
16428 * @self: a #ClutterActor
16430 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16432 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16433 * then the default structure will be returned.
16435 * This function should only be used for getters.
16437 * Return value: a const pointer to the ClutterLayoutInfo structure
16439 const ClutterLayoutInfo *
16440 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16442 const ClutterLayoutInfo *info;
16444 info = _clutter_actor_peek_layout_info (self);
16446 return &default_layout_info;
16452 * clutter_actor_set_x_align:
16453 * @self: a #ClutterActor
16454 * @x_align: the horizontal alignment policy
16456 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16457 * actor received extra horizontal space.
16459 * See also the #ClutterActor:x-align property.
16464 clutter_actor_set_x_align (ClutterActor *self,
16465 ClutterActorAlign x_align)
16467 ClutterLayoutInfo *info;
16469 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16471 info = _clutter_actor_get_layout_info (self);
16473 if (info->x_align != x_align)
16475 info->x_align = x_align;
16477 clutter_actor_queue_relayout (self);
16479 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16484 * clutter_actor_get_x_align:
16485 * @self: a #ClutterActor
16487 * Retrieves the horizontal alignment policy set using
16488 * clutter_actor_set_x_align().
16490 * Return value: the horizontal alignment policy.
16495 clutter_actor_get_x_align (ClutterActor *self)
16497 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16499 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16503 * clutter_actor_set_y_align:
16504 * @self: a #ClutterActor
16505 * @y_align: the vertical alignment policy
16507 * Sets the vertical alignment policy of a #ClutterActor, in case the
16508 * actor received extra vertical space.
16510 * See also the #ClutterActor:y-align property.
16515 clutter_actor_set_y_align (ClutterActor *self,
16516 ClutterActorAlign y_align)
16518 ClutterLayoutInfo *info;
16520 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16522 info = _clutter_actor_get_layout_info (self);
16524 if (info->y_align != y_align)
16526 info->y_align = y_align;
16528 clutter_actor_queue_relayout (self);
16530 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16535 * clutter_actor_get_y_align:
16536 * @self: a #ClutterActor
16538 * Retrieves the vertical alignment policy set using
16539 * clutter_actor_set_y_align().
16541 * Return value: the vertical alignment policy.
16546 clutter_actor_get_y_align (ClutterActor *self)
16548 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16550 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16554 * clutter_actor_set_margin:
16555 * @self: a #ClutterActor
16556 * @margin: a #ClutterMargin
16558 * Sets all the components of the margin of a #ClutterActor.
16563 clutter_actor_set_margin (ClutterActor *self,
16564 const ClutterMargin *margin)
16566 ClutterLayoutInfo *info;
16570 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16571 g_return_if_fail (margin != NULL);
16573 obj = G_OBJECT (self);
16576 g_object_freeze_notify (obj);
16578 info = _clutter_actor_get_layout_info (self);
16580 if (info->margin.top != margin->top)
16582 info->margin.top = margin->top;
16583 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16587 if (info->margin.right != margin->right)
16589 info->margin.right = margin->right;
16590 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16594 if (info->margin.bottom != margin->bottom)
16596 info->margin.bottom = margin->bottom;
16597 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16601 if (info->margin.left != margin->left)
16603 info->margin.left = margin->left;
16604 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16609 clutter_actor_queue_relayout (self);
16611 g_object_thaw_notify (obj);
16615 * clutter_actor_get_margin:
16616 * @self: a #ClutterActor
16617 * @margin: (out caller-allocates): return location for a #ClutterMargin
16619 * Retrieves all the components of the margin of a #ClutterActor.
16624 clutter_actor_get_margin (ClutterActor *self,
16625 ClutterMargin *margin)
16627 const ClutterLayoutInfo *info;
16629 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16630 g_return_if_fail (margin != NULL);
16632 info = _clutter_actor_get_layout_info_or_defaults (self);
16634 *margin = info->margin;
16638 * clutter_actor_set_margin_top:
16639 * @self: a #ClutterActor
16640 * @margin: the top margin
16642 * Sets the margin from the top of a #ClutterActor.
16647 clutter_actor_set_margin_top (ClutterActor *self,
16650 ClutterLayoutInfo *info;
16652 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16653 g_return_if_fail (margin >= 0.f);
16655 info = _clutter_actor_get_layout_info (self);
16657 if (info->margin.top == margin)
16660 info->margin.top = margin;
16662 clutter_actor_queue_relayout (self);
16664 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16668 * clutter_actor_get_margin_top:
16669 * @self: a #ClutterActor
16671 * Retrieves the top margin of a #ClutterActor.
16673 * Return value: the top margin
16678 clutter_actor_get_margin_top (ClutterActor *self)
16680 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16682 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16686 * clutter_actor_set_margin_bottom:
16687 * @self: a #ClutterActor
16688 * @margin: the bottom margin
16690 * Sets the margin from the bottom of a #ClutterActor.
16695 clutter_actor_set_margin_bottom (ClutterActor *self,
16698 ClutterLayoutInfo *info;
16700 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16701 g_return_if_fail (margin >= 0.f);
16703 info = _clutter_actor_get_layout_info (self);
16705 if (info->margin.bottom == margin)
16708 info->margin.bottom = margin;
16710 clutter_actor_queue_relayout (self);
16712 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16716 * clutter_actor_get_margin_bottom:
16717 * @self: a #ClutterActor
16719 * Retrieves the bottom margin of a #ClutterActor.
16721 * Return value: the bottom margin
16726 clutter_actor_get_margin_bottom (ClutterActor *self)
16728 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16730 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16734 * clutter_actor_set_margin_left:
16735 * @self: a #ClutterActor
16736 * @margin: the left margin
16738 * Sets the margin from the left of a #ClutterActor.
16743 clutter_actor_set_margin_left (ClutterActor *self,
16746 ClutterLayoutInfo *info;
16748 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16749 g_return_if_fail (margin >= 0.f);
16751 info = _clutter_actor_get_layout_info (self);
16753 if (info->margin.left == margin)
16756 info->margin.left = margin;
16758 clutter_actor_queue_relayout (self);
16760 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16764 * clutter_actor_get_margin_left:
16765 * @self: a #ClutterActor
16767 * Retrieves the left margin of a #ClutterActor.
16769 * Return value: the left margin
16774 clutter_actor_get_margin_left (ClutterActor *self)
16776 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16778 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16782 * clutter_actor_set_margin_right:
16783 * @self: a #ClutterActor
16784 * @margin: the right margin
16786 * Sets the margin from the right of a #ClutterActor.
16791 clutter_actor_set_margin_right (ClutterActor *self,
16794 ClutterLayoutInfo *info;
16796 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16797 g_return_if_fail (margin >= 0.f);
16799 info = _clutter_actor_get_layout_info (self);
16801 if (info->margin.right == margin)
16804 info->margin.right = margin;
16806 clutter_actor_queue_relayout (self);
16808 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16812 * clutter_actor_get_margin_right:
16813 * @self: a #ClutterActor
16815 * Retrieves the right margin of a #ClutterActor.
16817 * Return value: the right margin
16822 clutter_actor_get_margin_right (ClutterActor *self)
16824 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16826 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16830 clutter_actor_set_background_color_internal (ClutterActor *self,
16831 const ClutterColor *color)
16833 ClutterActorPrivate *priv = self->priv;
16836 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16839 obj = G_OBJECT (self);
16841 priv->bg_color = *color;
16842 priv->bg_color_set = TRUE;
16844 clutter_actor_queue_redraw (self);
16846 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16847 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16851 * clutter_actor_set_background_color:
16852 * @self: a #ClutterActor
16853 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16856 * Sets the background color of a #ClutterActor.
16858 * The background color will be used to cover the whole allocation of the
16859 * actor. The default background color of an actor is transparent.
16861 * To check whether an actor has a background color, you can use the
16862 * #ClutterActor:background-color-set actor property.
16864 * The #ClutterActor:background-color property is animatable.
16869 clutter_actor_set_background_color (ClutterActor *self,
16870 const ClutterColor *color)
16872 ClutterActorPrivate *priv;
16874 GParamSpec *bg_color_pspec;
16876 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16878 obj = G_OBJECT (self);
16884 priv->bg_color_set = FALSE;
16885 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16886 clutter_actor_queue_redraw (self);
16890 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16891 if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16893 _clutter_actor_create_transition (self, bg_color_pspec,
16898 _clutter_actor_update_transition (self, bg_color_pspec, color);
16900 clutter_actor_queue_redraw (self);
16904 * clutter_actor_get_background_color:
16905 * @self: a #ClutterActor
16906 * @color: (out caller-allocates): return location for a #ClutterColor
16908 * Retrieves the color set using clutter_actor_set_background_color().
16913 clutter_actor_get_background_color (ClutterActor *self,
16914 ClutterColor *color)
16916 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16917 g_return_if_fail (color != NULL);
16919 *color = self->priv->bg_color;
16923 * clutter_actor_get_previous_sibling:
16924 * @self: a #ClutterActor
16926 * Retrieves the sibling of @self that comes before it in the list
16927 * of children of @self's parent.
16929 * The returned pointer is only valid until the scene graph changes; it
16930 * is not safe to modify the list of children of @self while iterating
16933 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16938 clutter_actor_get_previous_sibling (ClutterActor *self)
16940 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16942 return self->priv->prev_sibling;
16946 * clutter_actor_get_next_sibling:
16947 * @self: a #ClutterActor
16949 * Retrieves the sibling of @self that comes after it in the list
16950 * of children of @self's parent.
16952 * The returned pointer is only valid until the scene graph changes; it
16953 * is not safe to modify the list of children of @self while iterating
16956 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16961 clutter_actor_get_next_sibling (ClutterActor *self)
16963 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16965 return self->priv->next_sibling;
16969 * clutter_actor_get_first_child:
16970 * @self: a #ClutterActor
16972 * Retrieves the first child of @self.
16974 * The returned pointer is only valid until the scene graph changes; it
16975 * is not safe to modify the list of children of @self while iterating
16978 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16983 clutter_actor_get_first_child (ClutterActor *self)
16985 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16987 return self->priv->first_child;
16991 * clutter_actor_get_last_child:
16992 * @self: a #ClutterActor
16994 * Retrieves the last child of @self.
16996 * The returned pointer is only valid until the scene graph changes; it
16997 * is not safe to modify the list of children of @self while iterating
17000 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
17005 clutter_actor_get_last_child (ClutterActor *self)
17007 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17009 return self->priv->last_child;
17012 /* easy way to have properly named fields instead of the dummy ones
17013 * we use in the public structure
17015 typedef struct _RealActorIter
17017 ClutterActor *root; /* dummy1 */
17018 ClutterActor *current; /* dummy2 */
17019 gpointer padding_1; /* dummy3 */
17020 gint age; /* dummy4 */
17021 gpointer padding_2; /* dummy5 */
17025 * clutter_actor_iter_init:
17026 * @iter: a #ClutterActorIter
17027 * @root: a #ClutterActor
17029 * Initializes a #ClutterActorIter, which can then be used to iterate
17030 * efficiently over a section of the scene graph, and associates it
17033 * Modifying the scene graph section that contains @root will invalidate
17037 * ClutterActorIter iter;
17038 * ClutterActor *child;
17040 * clutter_actor_iter_init (&iter, container);
17041 * while (clutter_actor_iter_next (&iter, &child))
17043 * /* do something with child */
17050 clutter_actor_iter_init (ClutterActorIter *iter,
17051 ClutterActor *root)
17053 RealActorIter *ri = (RealActorIter *) iter;
17055 g_return_if_fail (iter != NULL);
17056 g_return_if_fail (CLUTTER_IS_ACTOR (root));
17059 ri->current = NULL;
17060 ri->age = root->priv->age;
17064 * clutter_actor_iter_next:
17065 * @iter: a #ClutterActorIter
17066 * @child: (out): return location for a #ClutterActor
17068 * Advances the @iter and retrieves the next child of the root #ClutterActor
17069 * that was used to initialize the #ClutterActorIterator.
17071 * If the iterator can advance, this function returns %TRUE and sets the
17074 * If the iterator cannot advance, this function returns %FALSE, and
17075 * the contents of @child are undefined.
17077 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17082 clutter_actor_iter_next (ClutterActorIter *iter,
17083 ClutterActor **child)
17085 RealActorIter *ri = (RealActorIter *) iter;
17087 g_return_val_if_fail (iter != NULL, FALSE);
17088 g_return_val_if_fail (ri->root != NULL, FALSE);
17089 #ifndef G_DISABLE_ASSERT
17090 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17093 if (ri->current == NULL)
17094 ri->current = ri->root->priv->first_child;
17096 ri->current = ri->current->priv->next_sibling;
17099 *child = ri->current;
17101 return ri->current != NULL;
17105 * clutter_actor_iter_prev:
17106 * @iter: a #ClutterActorIter
17107 * @child: (out): return location for a #ClutterActor
17109 * Advances the @iter and retrieves the previous child of the root
17110 * #ClutterActor that was used to initialize the #ClutterActorIterator.
17112 * If the iterator can advance, this function returns %TRUE and sets the
17115 * If the iterator cannot advance, this function returns %FALSE, and
17116 * the contents of @child are undefined.
17118 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17123 clutter_actor_iter_prev (ClutterActorIter *iter,
17124 ClutterActor **child)
17126 RealActorIter *ri = (RealActorIter *) iter;
17128 g_return_val_if_fail (iter != NULL, FALSE);
17129 g_return_val_if_fail (ri->root != NULL, FALSE);
17130 #ifndef G_DISABLE_ASSERT
17131 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17134 if (ri->current == NULL)
17135 ri->current = ri->root->priv->last_child;
17137 ri->current = ri->current->priv->prev_sibling;
17140 *child = ri->current;
17142 return ri->current != NULL;
17146 * clutter_actor_iter_remove:
17147 * @iter: a #ClutterActorIter
17149 * Safely removes the #ClutterActor currently pointer to by the iterator
17152 * This function can only be called after clutter_actor_iter_next() or
17153 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17154 * than once for the same actor.
17156 * This function will call clutter_actor_remove_child() internally.
17161 clutter_actor_iter_remove (ClutterActorIter *iter)
17163 RealActorIter *ri = (RealActorIter *) iter;
17166 g_return_if_fail (iter != NULL);
17167 g_return_if_fail (ri->root != NULL);
17168 #ifndef G_DISABLE_ASSERT
17169 g_return_if_fail (ri->age == ri->root->priv->age);
17171 g_return_if_fail (ri->current != NULL);
17177 ri->current = cur->priv->prev_sibling;
17179 clutter_actor_remove_child_internal (ri->root, cur,
17180 REMOVE_CHILD_DEFAULT_FLAGS);
17187 * clutter_actor_iter_destroy:
17188 * @iter: a #ClutterActorIter
17190 * Safely destroys the #ClutterActor currently pointer to by the iterator
17193 * This function can only be called after clutter_actor_iter_next() or
17194 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17195 * than once for the same actor.
17197 * This function will call clutter_actor_destroy() internally.
17202 clutter_actor_iter_destroy (ClutterActorIter *iter)
17204 RealActorIter *ri = (RealActorIter *) iter;
17207 g_return_if_fail (iter != NULL);
17208 g_return_if_fail (ri->root != NULL);
17209 #ifndef G_DISABLE_ASSERT
17210 g_return_if_fail (ri->age == ri->root->priv->age);
17212 g_return_if_fail (ri->current != NULL);
17218 ri->current = cur->priv->prev_sibling;
17220 clutter_actor_destroy (cur);
17226 static const ClutterAnimationInfo default_animation_info = {
17227 NULL, /* transitions */
17229 NULL, /* cur_state */
17233 clutter_animation_info_free (gpointer data)
17237 ClutterAnimationInfo *info = data;
17239 if (info->transitions != NULL)
17240 g_hash_table_unref (info->transitions);
17242 if (info->states != NULL)
17243 g_array_unref (info->states);
17245 g_slice_free (ClutterAnimationInfo, info);
17249 const ClutterAnimationInfo *
17250 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17252 const ClutterAnimationInfo *res;
17253 GObject *obj = G_OBJECT (self);
17255 res = g_object_get_qdata (obj, quark_actor_animation_info);
17259 return &default_animation_info;
17262 ClutterAnimationInfo *
17263 _clutter_actor_get_animation_info (ClutterActor *self)
17265 GObject *obj = G_OBJECT (self);
17266 ClutterAnimationInfo *res;
17268 res = g_object_get_qdata (obj, quark_actor_animation_info);
17271 res = g_slice_new (ClutterAnimationInfo);
17273 *res = default_animation_info;
17275 g_object_set_qdata_full (obj, quark_actor_animation_info,
17277 clutter_animation_info_free);
17283 ClutterTransition *
17284 _clutter_actor_get_transition (ClutterActor *actor,
17287 const ClutterAnimationInfo *info;
17289 info = _clutter_actor_get_animation_info_or_defaults (actor);
17291 if (info->transitions == NULL)
17294 return g_hash_table_lookup (info->transitions, pspec->name);
17298 transition_closure_free (gpointer data)
17300 if (G_LIKELY (data != NULL))
17302 TransitionClosure *clos = data;
17303 ClutterTimeline *timeline;
17305 timeline = CLUTTER_TIMELINE (clos->transition);
17307 if (clutter_timeline_is_playing (timeline))
17308 clutter_timeline_stop (timeline);
17310 g_signal_handler_disconnect (clos->transition, clos->completed_id);
17312 g_object_unref (clos->transition);
17313 g_free (clos->name);
17315 g_slice_free (TransitionClosure, clos);
17320 on_transition_stopped (ClutterTransition *transition,
17321 gboolean is_finished,
17322 TransitionClosure *clos)
17324 ClutterActor *actor = clos->actor;
17325 ClutterAnimationInfo *info;
17327 /* reset the caches used by animations */
17328 clutter_actor_store_content_box (actor, NULL);
17333 info = _clutter_actor_get_animation_info (actor);
17335 /* we take a reference here because removing the closure
17336 * will release the reference on the transition, and we
17337 * want the transition to survive the signal emission;
17338 * the master clock will release the last reference at
17339 * the end of the frame processing.
17341 g_object_ref (transition);
17342 g_hash_table_remove (info->transitions, clos->name);
17344 /* if it's the last transition then we clean up */
17345 if (g_hash_table_size (info->transitions) == 0)
17347 g_hash_table_unref (info->transitions);
17348 info->transitions = NULL;
17350 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17351 _clutter_actor_get_debug_name (actor));
17353 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17358 _clutter_actor_update_transition (ClutterActor *actor,
17362 TransitionClosure *clos;
17363 ClutterTimeline *timeline;
17364 ClutterInterval *interval;
17365 const ClutterAnimationInfo *info;
17368 GValue initial = G_VALUE_INIT;
17369 GValue final = G_VALUE_INIT;
17370 char *error = NULL;
17372 info = _clutter_actor_get_animation_info_or_defaults (actor);
17374 if (info->transitions == NULL)
17377 clos = g_hash_table_lookup (info->transitions, pspec->name);
17381 timeline = CLUTTER_TIMELINE (clos->transition);
17383 va_start (var_args, pspec);
17385 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17387 g_value_init (&initial, ptype);
17388 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17392 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17395 g_critical ("%s: %s", G_STRLOC, error);
17400 interval = clutter_transition_get_interval (clos->transition);
17401 clutter_interval_set_initial_value (interval, &initial);
17402 clutter_interval_set_final_value (interval, &final);
17404 /* if we're updating with an easing duration of zero milliseconds,
17405 * we just jump the timeline to the end and let it run its course
17407 if (info->cur_state != NULL &&
17408 info->cur_state->easing_duration != 0)
17410 guint cur_duration = clutter_timeline_get_duration (timeline);
17411 ClutterAnimationMode cur_mode =
17412 clutter_timeline_get_progress_mode (timeline);
17414 if (cur_duration != info->cur_state->easing_duration)
17415 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17417 if (cur_mode != info->cur_state->easing_mode)
17418 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17420 clutter_timeline_rewind (timeline);
17424 guint duration = clutter_timeline_get_duration (timeline);
17426 clutter_timeline_advance (timeline, duration);
17430 g_value_unset (&initial);
17431 g_value_unset (&final);
17437 * _clutter_actor_create_transition:
17438 * @actor: a #ClutterActor
17439 * @pspec: the property used for the transition
17440 * @...: initial and final state
17442 * Creates a #ClutterTransition for the property represented by @pspec.
17444 * Return value: a #ClutterTransition
17446 ClutterTransition *
17447 _clutter_actor_create_transition (ClutterActor *actor,
17451 ClutterAnimationInfo *info;
17452 ClutterTransition *res = NULL;
17453 gboolean call_restore = FALSE;
17454 TransitionClosure *clos;
17457 info = _clutter_actor_get_animation_info (actor);
17459 /* XXX - this will go away in 2.0
17461 * if no state has been pushed, we assume that the easing state is
17462 * in "compatibility mode": all transitions have a duration of 0
17463 * msecs, which means that they happen immediately. in Clutter 2.0
17464 * this will turn into a g_assert(info->states != NULL), as every
17465 * actor will start with a predefined easing state
17467 if (info->states == NULL)
17469 clutter_actor_save_easing_state (actor);
17470 clutter_actor_set_easing_duration (actor, 0);
17471 call_restore = TRUE;
17474 if (info->transitions == NULL)
17475 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17477 transition_closure_free);
17479 va_start (var_args, pspec);
17481 clos = g_hash_table_lookup (info->transitions, pspec->name);
17484 ClutterTimeline *timeline;
17485 ClutterInterval *interval;
17486 GValue initial = G_VALUE_INIT;
17487 GValue final = G_VALUE_INIT;
17491 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17493 G_VALUE_COLLECT_INIT (&initial, ptype,
17498 g_critical ("%s: %s", G_STRLOC, error);
17503 G_VALUE_COLLECT_INIT (&final, ptype,
17509 g_critical ("%s: %s", G_STRLOC, error);
17510 g_value_unset (&initial);
17515 /* if the current easing state has a duration of 0, then we don't
17516 * bother to create the transition, and we just set the final value
17517 * directly on the actor; we don't go through the Animatable
17518 * interface because we know we got here through an animatable
17521 if (info->cur_state->easing_duration == 0)
17523 clutter_actor_set_animatable_property (actor,
17527 g_value_unset (&initial);
17528 g_value_unset (&final);
17533 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17535 g_value_unset (&initial);
17536 g_value_unset (&final);
17538 res = clutter_property_transition_new (pspec->name);
17540 clutter_transition_set_interval (res, interval);
17541 clutter_transition_set_remove_on_complete (res, TRUE);
17543 timeline = CLUTTER_TIMELINE (res);
17544 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17545 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17546 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17548 CLUTTER_NOTE (ANIMATION,
17549 "Created transition for %s:%s (len:%u, mode:%s, delay:%u)",
17550 _clutter_actor_get_debug_name (actor),
17552 info->cur_state->easing_duration,
17553 clutter_get_easing_name_for_mode (info->cur_state->easing_mode),
17554 info->cur_state->easing_delay);
17556 /* this will start the transition as well */
17557 clutter_actor_add_transition (actor, pspec->name, res);
17559 /* the actor now owns the transition */
17560 g_object_unref (res);
17563 res = clos->transition;
17567 clutter_actor_restore_easing_state (actor);
17575 * clutter_actor_add_transition:
17576 * @self: a #ClutterActor
17577 * @name: the name of the transition to add
17578 * @transition: the #ClutterTransition to add
17580 * Adds a @transition to the #ClutterActor's list of animations.
17582 * The @name string is a per-actor unique identifier of the @transition: only
17583 * one #ClutterTransition can be associated to the specified @name.
17585 * The @transition will be started once added.
17587 * This function will take a reference on the @transition.
17589 * This function is usually called implicitly when modifying an animatable
17595 clutter_actor_add_transition (ClutterActor *self,
17597 ClutterTransition *transition)
17599 ClutterTimeline *timeline;
17600 TransitionClosure *clos;
17601 ClutterAnimationInfo *info;
17603 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17604 g_return_if_fail (name != NULL);
17605 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17607 info = _clutter_actor_get_animation_info (self);
17609 if (info->transitions == NULL)
17610 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17612 transition_closure_free);
17614 if (g_hash_table_lookup (info->transitions, name) != NULL)
17616 g_warning ("A transition with name '%s' already exists for "
17619 _clutter_actor_get_debug_name (self));
17623 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17625 timeline = CLUTTER_TIMELINE (transition);
17627 clos = g_slice_new (TransitionClosure);
17628 clos->actor = self;
17629 clos->transition = g_object_ref (transition);
17630 clos->name = g_strdup (name);
17631 clos->completed_id = g_signal_connect (timeline, "stopped",
17632 G_CALLBACK (on_transition_stopped),
17635 CLUTTER_NOTE (ANIMATION,
17636 "Adding transition '%s' [%p] to actor '%s'",
17639 _clutter_actor_get_debug_name (self));
17641 g_hash_table_insert (info->transitions, clos->name, clos);
17642 clutter_timeline_start (timeline);
17646 * clutter_actor_remove_transition:
17647 * @self: a #ClutterActor
17648 * @name: the name of the transition to remove
17650 * Removes the transition stored inside a #ClutterActor using @name
17653 * If the transition is currently in progress, it will be stopped.
17655 * This function releases the reference acquired when the transition
17656 * was added to the #ClutterActor.
17661 clutter_actor_remove_transition (ClutterActor *self,
17664 const ClutterAnimationInfo *info;
17666 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17667 g_return_if_fail (name != NULL);
17669 info = _clutter_actor_get_animation_info_or_defaults (self);
17671 if (info->transitions == NULL)
17674 g_hash_table_remove (info->transitions, name);
17678 * clutter_actor_remove_all_transitions:
17679 * @self: a #ClutterActor
17681 * Removes all transitions associated to @self.
17686 clutter_actor_remove_all_transitions (ClutterActor *self)
17688 const ClutterAnimationInfo *info;
17690 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17692 info = _clutter_actor_get_animation_info_or_defaults (self);
17693 if (info->transitions == NULL)
17696 g_hash_table_remove_all (info->transitions);
17700 * clutter_actor_set_easing_duration:
17701 * @self: a #ClutterActor
17702 * @msecs: the duration of the easing, or %NULL
17704 * Sets the duration of the tweening for animatable properties
17705 * of @self for the current easing state.
17710 clutter_actor_set_easing_duration (ClutterActor *self,
17713 ClutterAnimationInfo *info;
17715 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17717 info = _clutter_actor_get_animation_info (self);
17719 if (info->cur_state == NULL)
17721 g_warning ("You must call clutter_actor_save_easing_state() prior "
17722 "to calling clutter_actor_set_easing_duration().");
17726 if (info->cur_state->easing_duration != msecs)
17727 info->cur_state->easing_duration = msecs;
17731 * clutter_actor_get_easing_duration:
17732 * @self: a #ClutterActor
17734 * Retrieves the duration of the tweening for animatable
17735 * properties of @self for the current easing state.
17737 * Return value: the duration of the tweening, in milliseconds
17742 clutter_actor_get_easing_duration (ClutterActor *self)
17744 const ClutterAnimationInfo *info;
17746 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17748 info = _clutter_actor_get_animation_info_or_defaults (self);
17750 if (info->cur_state != NULL)
17751 return info->cur_state->easing_duration;
17757 * clutter_actor_set_easing_mode:
17758 * @self: a #ClutterActor
17759 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17761 * Sets the easing mode for the tweening of animatable properties
17767 clutter_actor_set_easing_mode (ClutterActor *self,
17768 ClutterAnimationMode mode)
17770 ClutterAnimationInfo *info;
17772 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17773 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17774 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17776 info = _clutter_actor_get_animation_info (self);
17778 if (info->cur_state == NULL)
17780 g_warning ("You must call clutter_actor_save_easing_state() prior "
17781 "to calling clutter_actor_set_easing_mode().");
17785 if (info->cur_state->easing_mode != mode)
17786 info->cur_state->easing_mode = mode;
17790 * clutter_actor_get_easing_mode:
17791 * @self: a #ClutterActor
17793 * Retrieves the easing mode for the tweening of animatable properties
17794 * of @self for the current easing state.
17796 * Return value: an easing mode
17800 ClutterAnimationMode
17801 clutter_actor_get_easing_mode (ClutterActor *self)
17803 const ClutterAnimationInfo *info;
17805 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17807 info = _clutter_actor_get_animation_info_or_defaults (self);
17809 if (info->cur_state != NULL)
17810 return info->cur_state->easing_mode;
17812 return CLUTTER_EASE_OUT_CUBIC;
17816 * clutter_actor_set_easing_delay:
17817 * @self: a #ClutterActor
17818 * @msecs: the delay before the start of the tweening, in milliseconds
17820 * Sets the delay that should be applied before tweening animatable
17826 clutter_actor_set_easing_delay (ClutterActor *self,
17829 ClutterAnimationInfo *info;
17831 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17833 info = _clutter_actor_get_animation_info (self);
17835 if (info->cur_state == NULL)
17837 g_warning ("You must call clutter_actor_save_easing_state() prior "
17838 "to calling clutter_actor_set_easing_delay().");
17842 if (info->cur_state->easing_delay != msecs)
17843 info->cur_state->easing_delay = msecs;
17847 * clutter_actor_get_easing_delay:
17848 * @self: a #ClutterActor
17850 * Retrieves the delay that should be applied when tweening animatable
17853 * Return value: a delay, in milliseconds
17858 clutter_actor_get_easing_delay (ClutterActor *self)
17860 const ClutterAnimationInfo *info;
17862 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17864 info = _clutter_actor_get_animation_info_or_defaults (self);
17866 if (info->cur_state != NULL)
17867 return info->cur_state->easing_delay;
17873 * clutter_actor_get_transition:
17874 * @self: a #ClutterActor
17875 * @name: the name of the transition
17877 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17878 * transition @name.
17880 * Transitions created for animatable properties use the name of the
17881 * property itself, for instance the code below:
17884 * clutter_actor_set_easing_duration (actor, 1000);
17885 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17887 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17888 * g_signal_connect (transition, "stopped",
17889 * G_CALLBACK (on_transition_stopped),
17893 * will call the <function>on_transition_stopped</function> callback when
17894 * the transition is finished.
17896 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17897 * was found to match the passed name; the returned instance is owned
17898 * by Clutter and it should not be freed
17902 ClutterTransition *
17903 clutter_actor_get_transition (ClutterActor *self,
17906 TransitionClosure *clos;
17907 const ClutterAnimationInfo *info;
17909 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17910 g_return_val_if_fail (name != NULL, NULL);
17912 info = _clutter_actor_get_animation_info_or_defaults (self);
17913 if (info->transitions == NULL)
17916 clos = g_hash_table_lookup (info->transitions, name);
17920 return clos->transition;
17924 * clutter_actor_save_easing_state:
17925 * @self: a #ClutterActor
17927 * Saves the current easing state for animatable properties, and creates
17928 * a new state with the default values for easing mode and duration.
17933 clutter_actor_save_easing_state (ClutterActor *self)
17935 ClutterAnimationInfo *info;
17938 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17940 info = _clutter_actor_get_animation_info (self);
17942 if (info->states == NULL)
17943 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17945 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17946 new_state.easing_duration = 250;
17947 new_state.easing_delay = 0;
17949 g_array_append_val (info->states, new_state);
17951 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17955 * clutter_actor_restore_easing_state:
17956 * @self: a #ClutterActor
17958 * Restores the easing state as it was prior to a call to
17959 * clutter_actor_save_easing_state().
17964 clutter_actor_restore_easing_state (ClutterActor *self)
17966 ClutterAnimationInfo *info;
17968 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17970 info = _clutter_actor_get_animation_info (self);
17972 if (info->states == NULL)
17974 g_critical ("The function clutter_actor_restore_easing_state() has "
17975 "called without a previous call to "
17976 "clutter_actor_save_easing_state().");
17980 g_array_remove_index (info->states, info->states->len - 1);
17982 if (info->states->len > 0)
17983 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17986 g_array_unref (info->states);
17987 info->states = NULL;
17988 info->cur_state = NULL;
17993 * clutter_actor_set_content:
17994 * @self: a #ClutterActor
17995 * @content: (allow-none): a #ClutterContent, or %NULL
17997 * Sets the contents of a #ClutterActor.
18002 clutter_actor_set_content (ClutterActor *self,
18003 ClutterContent *content)
18005 ClutterActorPrivate *priv;
18007 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18008 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
18012 if (priv->content != NULL)
18014 _clutter_content_detached (priv->content, self);
18015 g_clear_object (&priv->content);
18018 priv->content = content;
18020 if (priv->content != NULL)
18022 g_object_ref (priv->content);
18023 _clutter_content_attached (priv->content, self);
18026 /* given that the content is always painted within the allocation,
18027 * we only need to queue a redraw here
18029 clutter_actor_queue_redraw (self);
18031 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
18033 /* if the content gravity is not resize-fill, and the new content has a
18034 * different preferred size than the previous one, then the content box
18035 * may have been changed. since we compute that lazily, we just notify
18036 * here, and let whomever watches :content-box do whatever they need to
18039 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18040 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
18044 * clutter_actor_get_content:
18045 * @self: a #ClutterActor
18047 * Retrieves the contents of @self.
18049 * Return value: (transfer none): a pointer to the #ClutterContent instance,
18050 * or %NULL if none was set
18055 clutter_actor_get_content (ClutterActor *self)
18057 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
18059 return self->priv->content;
18063 * clutter_actor_set_content_gravity:
18064 * @self: a #ClutterActor
18065 * @gravity: the #ClutterContentGravity
18067 * Sets the gravity of the #ClutterContent used by @self.
18069 * See the description of the #ClutterActor:content-gravity property for
18070 * more information.
18072 * The #ClutterActor:content-gravity property is animatable.
18077 clutter_actor_set_content_gravity (ClutterActor *self,
18078 ClutterContentGravity gravity)
18080 ClutterActorPrivate *priv;
18082 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18086 if (priv->content_gravity == gravity)
18089 priv->content_box_valid = FALSE;
18091 if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
18093 ClutterActorBox from_box, to_box;
18095 clutter_actor_get_content_box (self, &from_box);
18097 priv->content_gravity = gravity;
18099 clutter_actor_get_content_box (self, &to_box);
18101 _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
18107 ClutterActorBox to_box;
18109 priv->content_gravity = gravity;
18111 clutter_actor_get_content_box (self, &to_box);
18113 _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
18117 clutter_actor_queue_redraw (self);
18119 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
18123 * clutter_actor_get_content_gravity:
18124 * @self: a #ClutterActor
18126 * Retrieves the content gravity as set using
18127 * clutter_actor_get_content_gravity().
18129 * Return value: the content gravity
18133 ClutterContentGravity
18134 clutter_actor_get_content_gravity (ClutterActor *self)
18136 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
18137 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
18139 return self->priv->content_gravity;
18143 * clutter_actor_get_content_box:
18144 * @self: a #ClutterActor
18145 * @box: (out caller-allocates): the return location for the bounding
18146 * box for the #ClutterContent
18148 * Retrieves the bounding box for the #ClutterContent of @self.
18150 * The bounding box is relative to the actor's allocation.
18152 * If no #ClutterContent is set for @self, or if @self has not been
18153 * allocated yet, then the result is undefined.
18155 * The content box is guaranteed to be, at most, as big as the allocation
18156 * of the #ClutterActor.
18158 * If the #ClutterContent used by the actor has a preferred size, then
18159 * it is possible to modify the content box by using the
18160 * #ClutterActor:content-gravity property.
18165 clutter_actor_get_content_box (ClutterActor *self,
18166 ClutterActorBox *box)
18168 ClutterActorPrivate *priv;
18169 gfloat content_w, content_h;
18170 gfloat alloc_w, alloc_h;
18172 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18173 g_return_if_fail (box != NULL);
18179 box->x2 = priv->allocation.x2 - priv->allocation.x1;
18180 box->y2 = priv->allocation.y2 - priv->allocation.y1;
18182 if (priv->content_box_valid)
18184 *box = priv->content_box;
18188 /* no need to do any more work */
18189 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18192 if (priv->content == NULL)
18195 /* if the content does not have a preferred size then there is
18196 * no point in computing the content box
18198 if (!clutter_content_get_preferred_size (priv->content,
18206 switch (priv->content_gravity)
18208 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18209 box->x2 = box->x1 + MIN (content_w, alloc_w);
18210 box->y2 = box->y1 + MIN (content_h, alloc_h);
18213 case CLUTTER_CONTENT_GRAVITY_TOP:
18214 if (alloc_w > content_w)
18216 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18217 box->x2 = box->x1 + content_w;
18219 box->y2 = box->y1 + MIN (content_h, alloc_h);
18222 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18223 if (alloc_w > content_w)
18225 box->x1 += (alloc_w - content_w);
18226 box->x2 = box->x1 + content_w;
18228 box->y2 = box->y1 + MIN (content_h, alloc_h);
18231 case CLUTTER_CONTENT_GRAVITY_LEFT:
18232 box->x2 = box->x1 + MIN (content_w, alloc_w);
18233 if (alloc_h > content_h)
18235 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18236 box->y2 = box->y1 + content_h;
18240 case CLUTTER_CONTENT_GRAVITY_CENTER:
18241 if (alloc_w > content_w)
18243 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18244 box->x2 = box->x1 + content_w;
18246 if (alloc_h > content_h)
18248 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18249 box->y2 = box->y1 + content_h;
18253 case CLUTTER_CONTENT_GRAVITY_RIGHT:
18254 if (alloc_w > content_w)
18256 box->x1 += (alloc_w - content_w);
18257 box->x2 = box->x1 + content_w;
18259 if (alloc_h > content_h)
18261 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18262 box->y2 = box->y1 + content_h;
18266 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18267 box->x2 = box->x1 + MIN (content_w, alloc_w);
18268 if (alloc_h > content_h)
18270 box->y1 += (alloc_h - content_h);
18271 box->y2 = box->y1 + content_h;
18275 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18276 if (alloc_w > content_w)
18278 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18279 box->x2 = box->x1 + content_w;
18281 if (alloc_h > content_h)
18283 box->y1 += (alloc_h - content_h);
18284 box->y2 = box->y1 + content_h;
18288 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18289 if (alloc_w > content_w)
18291 box->x1 += (alloc_w - content_w);
18292 box->x2 = box->x1 + content_w;
18294 if (alloc_h > content_h)
18296 box->y1 += (alloc_h - content_h);
18297 box->y2 = box->y1 + content_h;
18301 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18302 g_assert_not_reached ();
18305 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18307 double r_c = content_w / content_h;
18311 if ((alloc_w / r_c) > alloc_h)
18316 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18317 box->y2 = box->y1 + (alloc_w / r_c);
18324 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18325 box->x2 = box->x1 + (alloc_h * r_c);
18330 if ((alloc_w / r_c) > alloc_h)
18335 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18336 box->x2 = box->x1 + (alloc_h * r_c);
18343 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18344 box->y2 = box->y1 + (alloc_w / r_c);
18348 CLUTTER_NOTE (LAYOUT,
18349 "r_c: %.3f, r_a: %.3f\t"
18350 "a: [%.2fx%.2f], c: [%.2fx%.2f]\t"
18351 "b: [%.2f, %.2f, %.2f, %.2f]",
18352 r_c, alloc_w / alloc_h,
18354 content_w, content_h,
18355 box->x1, box->y1, box->x2, box->y2);
18362 * clutter_actor_set_content_scaling_filters:
18363 * @self: a #ClutterActor
18364 * @min_filter: the minification filter for the content
18365 * @mag_filter: the magnification filter for the content
18367 * Sets the minification and magnification filter to be applied when
18368 * scaling the #ClutterActor:content of a #ClutterActor.
18370 * The #ClutterActor:minification-filter will be used when reducing
18371 * the size of the content; the #ClutterActor:magnification-filter
18372 * will be used when increasing the size of the content.
18377 clutter_actor_set_content_scaling_filters (ClutterActor *self,
18378 ClutterScalingFilter min_filter,
18379 ClutterScalingFilter mag_filter)
18381 ClutterActorPrivate *priv;
18385 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18388 obj = G_OBJECT (self);
18390 g_object_freeze_notify (obj);
18394 if (priv->min_filter != min_filter)
18396 priv->min_filter = min_filter;
18399 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18402 if (priv->mag_filter != mag_filter)
18404 priv->mag_filter = mag_filter;
18407 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18411 clutter_actor_queue_redraw (self);
18413 g_object_thaw_notify (obj);
18417 * clutter_actor_get_content_scaling_filters:
18418 * @self: a #ClutterActor
18419 * @min_filter: (out) (allow-none): return location for the minification
18421 * @mag_filter: (out) (allow-none): return location for the magnification
18424 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18429 clutter_actor_get_content_scaling_filters (ClutterActor *self,
18430 ClutterScalingFilter *min_filter,
18431 ClutterScalingFilter *mag_filter)
18433 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18435 if (min_filter != NULL)
18436 *min_filter = self->priv->min_filter;
18438 if (mag_filter != NULL)
18439 *mag_filter = self->priv->mag_filter;
18443 * clutter_actor_queue_compute_expand:
18444 * @self: a #ClutterActor
18446 * Invalidates the needs_x_expand and needs_y_expand flags on @self
18447 * and its parents up to the top-level actor.
18449 * This function also queues a relayout if anything changed.
18452 clutter_actor_queue_compute_expand (ClutterActor *self)
18454 ClutterActor *parent;
18457 if (self->priv->needs_compute_expand)
18462 while (parent != NULL)
18464 if (!parent->priv->needs_compute_expand)
18466 parent->priv->needs_compute_expand = TRUE;
18470 parent = parent->priv->parent;
18474 clutter_actor_queue_relayout (self);
18478 * clutter_actor_set_x_expand:
18479 * @self: a #ClutterActor
18480 * @expand: whether the actor should expand horizontally
18482 * Sets whether a #ClutterActor should expand horizontally; this means
18483 * that layout manager should allocate extra space for the actor, if
18486 * Setting an actor to expand will also make all its parent expand, so
18487 * that it's possible to build an actor tree and only set this flag on
18488 * its leaves and not on every single actor.
18493 clutter_actor_set_x_expand (ClutterActor *self,
18496 ClutterLayoutInfo *info;
18498 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18502 info = _clutter_actor_get_layout_info (self);
18503 if (info->x_expand != expand)
18505 info->x_expand = expand;
18507 self->priv->x_expand_set = TRUE;
18509 clutter_actor_queue_compute_expand (self);
18511 g_object_notify_by_pspec (G_OBJECT (self),
18512 obj_props[PROP_X_EXPAND]);
18517 * clutter_actor_get_x_expand:
18518 * @self: a #ClutterActor
18520 * Retrieves the value set with clutter_actor_set_x_expand().
18522 * See also: clutter_actor_needs_expand()
18524 * Return value: %TRUE if the actor has been set to expand
18529 clutter_actor_get_x_expand (ClutterActor *self)
18531 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18533 return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18537 * clutter_actor_set_y_expand:
18538 * @self: a #ClutterActor
18539 * @expand: whether the actor should expand vertically
18541 * Sets whether a #ClutterActor should expand horizontally; this means
18542 * that layout manager should allocate extra space for the actor, if
18545 * Setting an actor to expand will also make all its parent expand, so
18546 * that it's possible to build an actor tree and only set this flag on
18547 * its leaves and not on every single actor.
18552 clutter_actor_set_y_expand (ClutterActor *self,
18555 ClutterLayoutInfo *info;
18557 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18561 info = _clutter_actor_get_layout_info (self);
18562 if (info->y_expand != expand)
18564 info->y_expand = expand;
18566 self->priv->y_expand_set = TRUE;
18568 clutter_actor_queue_compute_expand (self);
18570 g_object_notify_by_pspec (G_OBJECT (self),
18571 obj_props[PROP_Y_EXPAND]);
18576 * clutter_actor_get_y_expand:
18577 * @self: a #ClutterActor
18579 * Retrieves the value set with clutter_actor_set_y_expand().
18581 * See also: clutter_actor_needs_expand()
18583 * Return value: %TRUE if the actor has been set to expand
18588 clutter_actor_get_y_expand (ClutterActor *self)
18590 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18592 return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18596 clutter_actor_compute_expand_recursive (ClutterActor *self,
18597 gboolean *x_expand_p,
18598 gboolean *y_expand_p)
18600 ClutterActorIter iter;
18601 ClutterActor *child;
18602 gboolean x_expand, y_expand;
18604 x_expand = y_expand = FALSE;
18606 /* note that we don't recurse into children if we're already set to expand;
18607 * this avoids traversing the whole actor tree, even if it may lead to some
18608 * child left with the needs_compute_expand flag set.
18610 clutter_actor_iter_init (&iter, self);
18611 while (clutter_actor_iter_next (&iter, &child))
18613 x_expand = x_expand ||
18614 clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL);
18616 y_expand = y_expand ||
18617 clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL);
18620 *x_expand_p = x_expand;
18621 *y_expand_p = y_expand;
18625 clutter_actor_compute_expand (ClutterActor *self)
18627 if (self->priv->needs_compute_expand)
18629 const ClutterLayoutInfo *info;
18630 gboolean x_expand, y_expand;
18632 info = _clutter_actor_get_layout_info_or_defaults (self);
18634 if (self->priv->x_expand_set)
18635 x_expand = info->x_expand;
18639 if (self->priv->y_expand_set)
18640 y_expand = info->y_expand;
18644 /* we don't need to recurse down to the children if the
18645 * actor has been forcibly set to expand
18647 if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18649 if (self->priv->n_children != 0)
18651 gboolean *x_expand_p, *y_expand_p;
18652 gboolean ignored = FALSE;
18654 x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18655 y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18657 clutter_actor_compute_expand_recursive (self,
18663 self->priv->needs_compute_expand = FALSE;
18664 self->priv->needs_x_expand = (x_expand != FALSE);
18665 self->priv->needs_y_expand = (y_expand != FALSE);
18670 * clutter_actor_needs_expand:
18671 * @self: a #ClutterActor
18672 * @orientation: the direction of expansion
18674 * Checks whether an actor, or any of its children, is set to expand
18675 * horizontally or vertically.
18677 * This function should only be called by layout managers that can
18678 * assign extra space to their children.
18680 * If you want to know whether the actor was explicitly set to expand,
18681 * use clutter_actor_get_x_expand() or clutter_actor_get_y_expand().
18683 * Return value: %TRUE if the actor should expand
18688 clutter_actor_needs_expand (ClutterActor *self,
18689 ClutterOrientation orientation)
18691 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18693 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18696 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18699 clutter_actor_compute_expand (self);
18701 switch (orientation)
18703 case CLUTTER_ORIENTATION_HORIZONTAL:
18704 return self->priv->needs_x_expand;
18706 case CLUTTER_ORIENTATION_VERTICAL:
18707 return self->priv->needs_y_expand;