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;
729 ClutterContentRepeat content_repeat;
731 /* used when painting, to update the paint volume */
732 ClutterEffect *current_effect;
734 /* This is used to store an effect which needs to be redrawn. A
735 redraw can be queued to start from a particular effect. This is
736 used by parametrised effects that can cache an image of the
737 actor. If a parameter of the effect changes then it only needs to
738 redraw the cached image, not the actual actor. The pointer is
739 only valid if is_dirty == TRUE. If the pointer is NULL then the
740 whole actor is dirty. */
741 ClutterEffect *effect_to_redraw;
743 /* This is used when painting effects to implement the
744 clutter_actor_continue_paint() function. It points to the node in
745 the list of effects that is next in the chain */
746 const GList *next_effect_to_paint;
748 ClutterPaintVolume paint_volume;
750 /* NB: This volume isn't relative to this actor, it is in eye
751 * coordinates so that it can remain valid after the actor changes.
753 ClutterPaintVolume last_paint_volume;
755 ClutterStageQueueRedrawEntry *queue_redraw_entry;
757 ClutterColor bg_color;
759 #ifdef CLUTTER_ENABLE_DEBUG
760 /* a string used for debugging messages */
766 /* fixed position and sizes */
767 guint position_set : 1;
768 guint min_width_set : 1;
769 guint min_height_set : 1;
770 guint natural_width_set : 1;
771 guint natural_height_set : 1;
772 /* cached request is invalid (implies allocation is too) */
773 guint needs_width_request : 1;
774 /* cached request is invalid (implies allocation is too) */
775 guint needs_height_request : 1;
776 /* cached allocation is invalid (request has changed, probably) */
777 guint needs_allocation : 1;
778 guint show_on_set_parent : 1;
780 guint clip_to_allocation : 1;
781 guint enable_model_view_transform : 1;
782 guint enable_paint_unmapped : 1;
783 guint has_pointer : 1;
784 guint propagated_one_redraw : 1;
785 guint paint_volume_valid : 1;
786 guint last_paint_volume_valid : 1;
787 guint in_clone_paint : 1;
788 guint transform_valid : 1;
789 /* This is TRUE if anything has queued a redraw since we were last
790 painted. In this case effect_to_redraw will point to an effect
791 the redraw was queued from or it will be NULL if the redraw was
792 queued without an effect. */
794 guint bg_color_set : 1;
795 guint content_box_valid : 1;
796 guint x_expand_set : 1;
797 guint y_expand_set : 1;
798 guint needs_compute_expand : 1;
799 guint needs_x_expand : 1;
800 guint needs_y_expand : 1;
809 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
810 * when set they force a size request, when gotten they
811 * get the allocation if the allocation is valid, and the
822 /* Then the rest of these size-related properties are the "actual"
823 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
828 PROP_FIXED_POSITION_SET,
837 PROP_NATURAL_WIDTH_SET,
840 PROP_NATURAL_HEIGHT_SET,
844 /* Allocation properties are read-only */
851 PROP_CLIP_TO_ALLOCATION,
855 PROP_OFFSCREEN_REDIRECT,
868 PROP_ROTATION_ANGLE_X,
869 PROP_ROTATION_ANGLE_Y,
870 PROP_ROTATION_ANGLE_Z,
871 PROP_ROTATION_CENTER_X,
872 PROP_ROTATION_CENTER_Y,
873 PROP_ROTATION_CENTER_Z,
874 /* This property only makes sense for the z rotation because the
875 others would depend on the actor having a size along the
877 PROP_ROTATION_CENTER_Z_GRAVITY,
883 PROP_SHOW_ON_SET_PARENT,
903 PROP_BACKGROUND_COLOR,
904 PROP_BACKGROUND_COLOR_SET,
910 PROP_CONTENT_GRAVITY,
912 PROP_MINIFICATION_FILTER,
913 PROP_MAGNIFICATION_FILTER,
919 static GParamSpec *obj_props[PROP_LAST];
938 BUTTON_RELEASE_EVENT,
946 TRANSITIONS_COMPLETED,
951 static guint actor_signals[LAST_SIGNAL] = { 0, };
953 typedef struct _TransitionClosure
956 ClutterTransition *transition;
961 static void clutter_container_iface_init (ClutterContainerIface *iface);
962 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
963 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
964 static void atk_implementor_iface_init (AtkImplementorIface *iface);
966 /* These setters are all static for now, maybe they should be in the
967 * public API, but they are perhaps obscure enough to leave only as
970 static void clutter_actor_set_min_width (ClutterActor *self,
972 static void clutter_actor_set_min_height (ClutterActor *self,
974 static void clutter_actor_set_natural_width (ClutterActor *self,
975 gfloat natural_width);
976 static void clutter_actor_set_natural_height (ClutterActor *self,
977 gfloat natural_height);
978 static void clutter_actor_set_min_width_set (ClutterActor *self,
979 gboolean use_min_width);
980 static void clutter_actor_set_min_height_set (ClutterActor *self,
981 gboolean use_min_height);
982 static void clutter_actor_set_natural_width_set (ClutterActor *self,
983 gboolean use_natural_width);
984 static void clutter_actor_set_natural_height_set (ClutterActor *self,
985 gboolean use_natural_height);
986 static void clutter_actor_update_map_state (ClutterActor *self,
987 MapStateChange change);
988 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
990 /* Helper routines for managing anchor coords */
991 static void clutter_anchor_coord_get_units (ClutterActor *self,
992 const AnchorCoord *coord,
996 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
1001 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
1002 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
1003 ClutterGravity gravity);
1005 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
1007 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
1009 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
1010 ClutterActor *ancestor,
1011 CoglMatrix *matrix);
1013 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
1015 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
1017 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
1018 const ClutterColor *color);
1020 static void on_layout_manager_changed (ClutterLayoutManager *manager,
1021 ClutterActor *self);
1023 static inline void clutter_actor_queue_compute_expand (ClutterActor *self);
1025 /* Helper macro which translates by the anchor coord, applies the
1026 given transformation and then translates back */
1027 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
1028 gfloat _tx, _ty, _tz; \
1029 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
1030 cogl_matrix_translate ((m), _tx, _ty, _tz); \
1032 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
1034 static GQuark quark_shader_data = 0;
1035 static GQuark quark_actor_layout_info = 0;
1036 static GQuark quark_actor_transform_info = 0;
1037 static GQuark quark_actor_animation_info = 0;
1039 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1041 G_TYPE_INITIALLY_UNOWNED,
1042 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1043 clutter_container_iface_init)
1044 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1045 clutter_scriptable_iface_init)
1046 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1047 clutter_animatable_iface_init)
1048 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1049 atk_implementor_iface_init));
1052 * clutter_actor_get_debug_name:
1053 * @actor: a #ClutterActor
1055 * Retrieves a printable name of @actor for debugging messages
1057 * Return value: a string with a printable name
1060 _clutter_actor_get_debug_name (ClutterActor *actor)
1062 ClutterActorPrivate *priv = actor->priv;
1063 const gchar *retval;
1065 #ifdef CLUTTER_ENABLE_DEBUG
1066 if (G_UNLIKELY (priv->debug_name == NULL))
1068 priv->debug_name = g_strdup_printf ("<%s>[<%s>:%p]",
1069 priv->name != NULL ? priv->name
1071 G_OBJECT_TYPE_NAME (actor),
1075 retval = priv->debug_name;
1077 retval = priv->name != NULL
1079 : G_OBJECT_TYPE_NAME (actor);
1085 #ifdef CLUTTER_ENABLE_DEBUG
1086 /* XXX - this is for debugging only, remove once working (or leave
1087 * in only in some debug mode). Should leave it for a little while
1088 * until we're confident in the new map/realize/visible handling.
1091 clutter_actor_verify_map_state (ClutterActor *self)
1093 ClutterActorPrivate *priv = self->priv;
1095 if (CLUTTER_ACTOR_IS_REALIZED (self))
1097 /* all bets are off during reparent when we're potentially realized,
1098 * but should not be according to invariants
1100 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1102 if (priv->parent == NULL)
1104 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1108 g_warning ("Realized non-toplevel actor '%s' should "
1110 _clutter_actor_get_debug_name (self));
1112 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1114 g_warning ("Realized actor %s has an unrealized parent %s",
1115 _clutter_actor_get_debug_name (self),
1116 _clutter_actor_get_debug_name (priv->parent));
1121 if (CLUTTER_ACTOR_IS_MAPPED (self))
1123 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1124 g_warning ("Actor '%s' is mapped but not realized",
1125 _clutter_actor_get_debug_name (self));
1127 /* remaining bets are off during reparent when we're potentially
1128 * mapped, but should not be according to invariants
1130 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1132 if (priv->parent == NULL)
1134 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1136 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1137 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1139 g_warning ("Toplevel actor '%s' is mapped "
1141 _clutter_actor_get_debug_name (self));
1146 g_warning ("Mapped actor '%s' should have a parent",
1147 _clutter_actor_get_debug_name (self));
1152 ClutterActor *iter = self;
1154 /* check for the enable_paint_unmapped flag on the actor
1155 * and parents; if the flag is enabled at any point of this
1156 * branch of the scene graph then all the later checks
1159 while (iter != NULL)
1161 if (iter->priv->enable_paint_unmapped)
1164 iter = iter->priv->parent;
1167 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1169 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1171 _clutter_actor_get_debug_name (self),
1172 _clutter_actor_get_debug_name (priv->parent));
1175 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1177 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1179 _clutter_actor_get_debug_name (self),
1180 _clutter_actor_get_debug_name (priv->parent));
1183 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1185 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1186 g_warning ("Actor '%s' is mapped but its non-toplevel "
1187 "parent '%s' is not mapped",
1188 _clutter_actor_get_debug_name (self),
1189 _clutter_actor_get_debug_name (priv->parent));
1196 #endif /* CLUTTER_ENABLE_DEBUG */
1199 clutter_actor_set_mapped (ClutterActor *self,
1202 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1207 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1208 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1212 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1213 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1217 /* this function updates the mapped and realized states according to
1218 * invariants, in the appropriate order.
1221 clutter_actor_update_map_state (ClutterActor *self,
1222 MapStateChange change)
1224 gboolean was_mapped;
1226 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1228 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1230 /* the mapped flag on top-level actors must be set by the
1231 * per-backend implementation because it might be asynchronous.
1233 * That is, the MAPPED flag on toplevels currently tracks the X
1234 * server mapped-ness of the window, while the expected behavior
1235 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1236 * This creates some weird complexity by breaking the invariant
1237 * that if we're visible and all ancestors shown then we are
1238 * also mapped - instead, we are mapped if all ancestors
1239 * _possibly excepting_ the stage are mapped. The stage
1240 * will map/unmap for example when it is minimized or
1241 * moved to another workspace.
1243 * So, the only invariant on the stage is that if visible it
1244 * should be realized, and that it has to be visible to be
1247 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1248 clutter_actor_realize (self);
1252 case MAP_STATE_CHECK:
1255 case MAP_STATE_MAKE_MAPPED:
1256 g_assert (!was_mapped);
1257 clutter_actor_set_mapped (self, TRUE);
1260 case MAP_STATE_MAKE_UNMAPPED:
1261 g_assert (was_mapped);
1262 clutter_actor_set_mapped (self, FALSE);
1265 case MAP_STATE_MAKE_UNREALIZED:
1266 /* we only use MAKE_UNREALIZED in unparent,
1267 * and unparenting a stage isn't possible.
1268 * If someone wants to just unrealize a stage
1269 * then clutter_actor_unrealize() doesn't
1270 * go through this codepath.
1272 g_warning ("Trying to force unrealize stage is not allowed");
1276 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1277 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1278 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1280 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1281 "it is somehow still mapped",
1282 _clutter_actor_get_debug_name (self));
1287 ClutterActorPrivate *priv = self->priv;
1288 ClutterActor *parent = priv->parent;
1289 gboolean should_be_mapped;
1290 gboolean may_be_realized;
1291 gboolean must_be_realized;
1293 should_be_mapped = FALSE;
1294 may_be_realized = TRUE;
1295 must_be_realized = FALSE;
1297 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1299 may_be_realized = FALSE;
1303 /* Maintain invariant that if parent is mapped, and we are
1304 * visible, then we are mapped ... unless parent is a
1305 * stage, in which case we map regardless of parent's map
1306 * state but do require stage to be visible and realized.
1308 * If parent is realized, that does not force us to be
1309 * realized; but if parent is unrealized, that does force
1310 * us to be unrealized.
1312 * The reason we don't force children to realize with
1313 * parents is _clutter_actor_rerealize(); if we require that
1314 * a realized parent means children are realized, then to
1315 * unrealize an actor we would have to unrealize its
1316 * parents, which would end up meaning unrealizing and
1317 * hiding the entire stage. So we allow unrealizing a
1318 * child (as long as that child is not mapped) while that
1319 * child still has a realized parent.
1321 * Also, if we unrealize from leaf nodes to root, and
1322 * realize from root to leaf, the invariants are never
1323 * violated if we allow children to be unrealized
1324 * while parents are realized.
1326 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1327 * to force us to unmap, even though parent is still
1328 * mapped. This is because we're unmapping from leaf nodes
1331 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1332 change != MAP_STATE_MAKE_UNMAPPED)
1334 gboolean parent_is_visible_realized_toplevel;
1336 parent_is_visible_realized_toplevel =
1337 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1338 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1339 CLUTTER_ACTOR_IS_REALIZED (parent));
1341 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1342 parent_is_visible_realized_toplevel)
1344 must_be_realized = TRUE;
1345 should_be_mapped = TRUE;
1349 /* if the actor has been set to be painted even if unmapped
1350 * then we should map it and check for realization as well;
1351 * this is an override for the branch of the scene graph
1352 * which begins with this node
1354 if (priv->enable_paint_unmapped)
1356 if (priv->parent == NULL)
1357 g_warning ("Attempting to map an unparented actor '%s'",
1358 _clutter_actor_get_debug_name (self));
1360 should_be_mapped = TRUE;
1361 must_be_realized = TRUE;
1364 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1365 may_be_realized = FALSE;
1368 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1371 g_warning ("Attempting to map a child that does not "
1372 "meet the necessary invariants: the actor '%s' "
1374 _clutter_actor_get_debug_name (self));
1376 g_warning ("Attempting to map a child that does not "
1377 "meet the necessary invariants: the actor '%s' "
1378 "is parented to an unmapped actor '%s'",
1379 _clutter_actor_get_debug_name (self),
1380 _clutter_actor_get_debug_name (priv->parent));
1383 /* If in reparent, we temporarily suspend unmap and unrealize.
1385 * We want to go in the order "realize, map" and "unmap, unrealize"
1389 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1390 clutter_actor_set_mapped (self, FALSE);
1393 if (must_be_realized)
1394 clutter_actor_realize (self);
1396 /* if we must be realized then we may be, presumably */
1397 g_assert (!(must_be_realized && !may_be_realized));
1400 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1401 clutter_actor_unrealize_not_hiding (self);
1404 if (should_be_mapped)
1406 if (!must_be_realized)
1407 g_warning ("Somehow we think actor '%s' should be mapped but "
1408 "not realized, which isn't allowed",
1409 _clutter_actor_get_debug_name (self));
1411 /* realization is allowed to fail (though I don't know what
1412 * an app is supposed to do about that - shouldn't it just
1413 * be a g_error? anyway, we have to avoid mapping if this
1416 if (CLUTTER_ACTOR_IS_REALIZED (self))
1417 clutter_actor_set_mapped (self, TRUE);
1421 #ifdef CLUTTER_ENABLE_DEBUG
1422 /* check all invariants were kept */
1423 clutter_actor_verify_map_state (self);
1428 clutter_actor_real_map (ClutterActor *self)
1430 ClutterActorPrivate *priv = self->priv;
1431 ClutterActor *stage, *iter;
1433 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1435 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1436 _clutter_actor_get_debug_name (self));
1438 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1440 stage = _clutter_actor_get_stage_internal (self);
1441 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1443 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1445 _clutter_actor_get_debug_name (self));
1447 /* notify on parent mapped before potentially mapping
1448 * children, so apps see a top-down notification.
1450 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1452 for (iter = self->priv->first_child;
1454 iter = iter->priv->next_sibling)
1456 clutter_actor_map (iter);
1461 * clutter_actor_map:
1462 * @self: A #ClutterActor
1464 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1465 * and realizes its children if they are visible. Does nothing if the
1466 * actor is not visible.
1468 * Calling this function is strongly disencouraged: the default
1469 * implementation of #ClutterActorClass.map() will map all the children
1470 * of an actor when mapping its parent.
1472 * When overriding map, it is mandatory to chain up to the parent
1478 clutter_actor_map (ClutterActor *self)
1480 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1482 if (CLUTTER_ACTOR_IS_MAPPED (self))
1485 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1488 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1492 clutter_actor_real_unmap (ClutterActor *self)
1494 ClutterActorPrivate *priv = self->priv;
1497 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1499 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1500 _clutter_actor_get_debug_name (self));
1502 for (iter = self->priv->first_child;
1504 iter = iter->priv->next_sibling)
1506 clutter_actor_unmap (iter);
1509 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1511 /* clear the contents of the last paint volume, so that hiding + moving +
1512 * showing will not result in the wrong area being repainted
1514 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1515 priv->last_paint_volume_valid = TRUE;
1517 /* notify on parent mapped after potentially unmapping
1518 * children, so apps see a bottom-up notification.
1520 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1522 /* relinquish keyboard focus if we were unmapped while owning it */
1523 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1525 ClutterStage *stage;
1527 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1530 _clutter_stage_release_pick_id (stage, priv->pick_id);
1534 if (stage != NULL &&
1535 clutter_stage_get_key_focus (stage) == self)
1537 clutter_stage_set_key_focus (stage, NULL);
1543 * clutter_actor_unmap:
1544 * @self: A #ClutterActor
1546 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1547 * unmaps its children if they were mapped.
1549 * Calling this function is not encouraged: the default #ClutterActor
1550 * implementation of #ClutterActorClass.unmap() will also unmap any
1551 * eventual children by default when their parent is unmapped.
1553 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1554 * chain up to the parent implementation.
1556 * <note>It is important to note that the implementation of the
1557 * #ClutterActorClass.unmap() virtual function may be called after
1558 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1559 * implementation, but it is guaranteed to be called before the
1560 * #GObjectClass.finalize() implementation.</note>
1565 clutter_actor_unmap (ClutterActor *self)
1567 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1569 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1572 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1576 clutter_actor_real_show (ClutterActor *self)
1578 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1580 ClutterActorPrivate *priv = self->priv;
1582 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1584 /* we notify on the "visible" flag in the clutter_actor_show()
1585 * wrapper so the entire show signal emission completes first
1588 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1590 /* we queue a relayout unless the actor is inside a
1591 * container that explicitly told us not to
1593 if (priv->parent != NULL &&
1594 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1596 /* While an actor is hidden the parent may not have
1597 * allocated/requested so we need to start from scratch
1598 * and avoid the short-circuiting in
1599 * clutter_actor_queue_relayout().
1601 priv->needs_width_request = FALSE;
1602 priv->needs_height_request = FALSE;
1603 priv->needs_allocation = FALSE;
1604 clutter_actor_queue_relayout (self);
1610 set_show_on_set_parent (ClutterActor *self,
1613 ClutterActorPrivate *priv = self->priv;
1615 set_show = !!set_show;
1617 if (priv->show_on_set_parent == set_show)
1620 if (priv->parent == NULL)
1622 priv->show_on_set_parent = set_show;
1623 g_object_notify_by_pspec (G_OBJECT (self),
1624 obj_props[PROP_SHOW_ON_SET_PARENT]);
1629 * clutter_actor_show:
1630 * @self: A #ClutterActor
1632 * Flags an actor to be displayed. An actor that isn't shown will not
1633 * be rendered on the stage.
1635 * Actors are visible by default.
1637 * If this function is called on an actor without a parent, the
1638 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1642 clutter_actor_show (ClutterActor *self)
1644 ClutterActorPrivate *priv;
1646 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1648 /* simple optimization */
1649 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1651 /* we still need to set the :show-on-set-parent property, in
1652 * case show() is called on an unparented actor
1654 set_show_on_set_parent (self, TRUE);
1658 #ifdef CLUTTER_ENABLE_DEBUG
1659 clutter_actor_verify_map_state (self);
1664 g_object_freeze_notify (G_OBJECT (self));
1666 set_show_on_set_parent (self, TRUE);
1668 /* if we're showing a child that needs to expand, or may
1669 * expand, then we need to recompute the expand flags for
1670 * its parent as well
1672 if (priv->needs_compute_expand ||
1673 priv->needs_x_expand ||
1674 priv->needs_y_expand)
1676 clutter_actor_queue_compute_expand (self);
1679 g_signal_emit (self, actor_signals[SHOW], 0);
1680 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1682 if (priv->parent != NULL)
1683 clutter_actor_queue_redraw (priv->parent);
1685 g_object_thaw_notify (G_OBJECT (self));
1689 * clutter_actor_show_all:
1690 * @self: a #ClutterActor
1692 * Calls clutter_actor_show() on all children of an actor (if any).
1696 * Deprecated: 1.10: Actors are visible by default
1699 clutter_actor_show_all (ClutterActor *self)
1701 ClutterActorClass *klass;
1703 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1705 klass = CLUTTER_ACTOR_GET_CLASS (self);
1706 if (klass->show_all)
1707 klass->show_all (self);
1711 clutter_actor_real_hide (ClutterActor *self)
1713 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1715 ClutterActorPrivate *priv = self->priv;
1717 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1719 /* we notify on the "visible" flag in the clutter_actor_hide()
1720 * wrapper so the entire hide signal emission completes first
1723 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1725 /* we queue a relayout unless the actor is inside a
1726 * container that explicitly told us not to
1728 if (priv->parent != NULL &&
1729 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1730 clutter_actor_queue_relayout (priv->parent);
1735 * clutter_actor_hide:
1736 * @self: A #ClutterActor
1738 * Flags an actor to be hidden. A hidden actor will not be
1739 * rendered on the stage.
1741 * Actors are visible by default.
1743 * If this function is called on an actor without a parent, the
1744 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1748 clutter_actor_hide (ClutterActor *self)
1750 ClutterActorPrivate *priv;
1752 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1754 /* simple optimization */
1755 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1757 /* we still need to set the :show-on-set-parent property, in
1758 * case hide() is called on an unparented actor
1760 set_show_on_set_parent (self, FALSE);
1764 #ifdef CLUTTER_ENABLE_DEBUG
1765 clutter_actor_verify_map_state (self);
1770 g_object_freeze_notify (G_OBJECT (self));
1772 set_show_on_set_parent (self, FALSE);
1774 /* if we're hiding a child that needs to expand, or may
1775 * expand, then we need to recompute the expand flags for
1776 * its parent as well
1778 if (priv->needs_compute_expand ||
1779 priv->needs_x_expand ||
1780 priv->needs_y_expand)
1782 clutter_actor_queue_compute_expand (self);
1785 g_signal_emit (self, actor_signals[HIDE], 0);
1786 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1788 if (priv->parent != NULL)
1789 clutter_actor_queue_redraw (priv->parent);
1791 g_object_thaw_notify (G_OBJECT (self));
1795 * clutter_actor_hide_all:
1796 * @self: a #ClutterActor
1798 * Calls clutter_actor_hide() on all child actors (if any).
1802 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1803 * prevent its children from being painted as well.
1806 clutter_actor_hide_all (ClutterActor *self)
1808 ClutterActorClass *klass;
1810 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1812 klass = CLUTTER_ACTOR_GET_CLASS (self);
1813 if (klass->hide_all)
1814 klass->hide_all (self);
1818 * clutter_actor_realize:
1819 * @self: A #ClutterActor
1821 * Realization informs the actor that it is attached to a stage. It
1822 * can use this to allocate resources if it wanted to delay allocation
1823 * until it would be rendered. However it is perfectly acceptable for
1824 * an actor to create resources before being realized because Clutter
1825 * only ever has a single rendering context so that actor is free to
1826 * be moved from one stage to another.
1828 * This function does nothing if the actor is already realized.
1830 * Because a realized actor must have realized parent actors, calling
1831 * clutter_actor_realize() will also realize all parents of the actor.
1833 * This function does not realize child actors, except in the special
1834 * case that realizing the stage, when the stage is visible, will
1835 * suddenly map (and thus realize) the children of the stage.
1838 clutter_actor_realize (ClutterActor *self)
1840 ClutterActorPrivate *priv;
1842 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1846 #ifdef CLUTTER_ENABLE_DEBUG
1847 clutter_actor_verify_map_state (self);
1850 if (CLUTTER_ACTOR_IS_REALIZED (self))
1853 /* To be realized, our parent actors must be realized first.
1854 * This will only succeed if we're inside a toplevel.
1856 if (priv->parent != NULL)
1857 clutter_actor_realize (priv->parent);
1859 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1861 /* toplevels can be realized at any time */
1865 /* "Fail" the realization if parent is missing or unrealized;
1866 * this should really be a g_warning() not some kind of runtime
1867 * failure; how can an app possibly recover? Instead it's a bug
1868 * in the app and the app should get an explanatory warning so
1869 * someone can fix it. But for now it's too hard to fix this
1870 * because e.g. ClutterTexture needs reworking.
1872 if (priv->parent == NULL ||
1873 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1877 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1879 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1880 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1882 g_signal_emit (self, actor_signals[REALIZE], 0);
1884 /* Stage actor is allowed to unset the realized flag again in its
1885 * default signal handler, though that is a pathological situation.
1888 /* If realization "failed" we'll have to update child state. */
1889 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1893 clutter_actor_real_unrealize (ClutterActor *self)
1895 /* we must be unmapped (implying our children are also unmapped) */
1896 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1900 * clutter_actor_unrealize:
1901 * @self: A #ClutterActor
1903 * Unrealization informs the actor that it may be being destroyed or
1904 * moved to another stage. The actor may want to destroy any
1905 * underlying graphics resources at this point. However it is
1906 * perfectly acceptable for it to retain the resources until the actor
1907 * is destroyed because Clutter only ever uses a single rendering
1908 * context and all of the graphics resources are valid on any stage.
1910 * Because mapped actors must be realized, actors may not be
1911 * unrealized if they are mapped. This function hides the actor to be
1912 * sure it isn't mapped, an application-visible side effect that you
1913 * may not be expecting.
1915 * This function should not be called by application code.
1918 clutter_actor_unrealize (ClutterActor *self)
1920 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1921 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1923 /* This function should not really be in the public API, because
1924 * there isn't a good reason to call it. ClutterActor will already
1925 * unrealize things for you when it's important to do so.
1927 * If you were using clutter_actor_unrealize() in a dispose
1928 * implementation, then don't, just chain up to ClutterActor's
1931 * If you were using clutter_actor_unrealize() to implement
1932 * unrealizing children of your container, then don't, ClutterActor
1933 * will already take care of that.
1935 * If you were using clutter_actor_unrealize() to re-realize to
1936 * create your resources in a different way, then use
1937 * _clutter_actor_rerealize() (inside Clutter) or just call your
1938 * code that recreates your resources directly (outside Clutter).
1941 #ifdef CLUTTER_ENABLE_DEBUG
1942 clutter_actor_verify_map_state (self);
1945 clutter_actor_hide (self);
1947 clutter_actor_unrealize_not_hiding (self);
1950 static ClutterActorTraverseVisitFlags
1951 unrealize_actor_before_children_cb (ClutterActor *self,
1955 /* If an actor is already unrealized we know its children have also
1956 * already been unrealized... */
1957 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1958 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1960 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1962 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1965 static ClutterActorTraverseVisitFlags
1966 unrealize_actor_after_children_cb (ClutterActor *self,
1970 /* We want to unset the realized flag only _after_
1971 * child actors are unrealized, to maintain invariants.
1973 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1974 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1975 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1979 * clutter_actor_unrealize_not_hiding:
1980 * @self: A #ClutterActor
1982 * Unrealization informs the actor that it may be being destroyed or
1983 * moved to another stage. The actor may want to destroy any
1984 * underlying graphics resources at this point. However it is
1985 * perfectly acceptable for it to retain the resources until the actor
1986 * is destroyed because Clutter only ever uses a single rendering
1987 * context and all of the graphics resources are valid on any stage.
1989 * Because mapped actors must be realized, actors may not be
1990 * unrealized if they are mapped. You must hide the actor or one of
1991 * its parents before attempting to unrealize.
1993 * This function is separate from clutter_actor_unrealize() because it
1994 * does not automatically hide the actor.
1995 * Actors need not be hidden to be unrealized, they just need to
1996 * be unmapped. In fact we don't want to mess up the application's
1997 * setting of the "visible" flag, so hiding is very undesirable.
1999 * clutter_actor_unrealize() does a clutter_actor_hide() just for
2000 * backward compatibility.
2003 clutter_actor_unrealize_not_hiding (ClutterActor *self)
2005 _clutter_actor_traverse (self,
2006 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
2007 unrealize_actor_before_children_cb,
2008 unrealize_actor_after_children_cb,
2013 * _clutter_actor_rerealize:
2014 * @self: A #ClutterActor
2015 * @callback: Function to call while unrealized
2016 * @data: data for callback
2018 * If an actor is already unrealized, this just calls the callback.
2020 * If it is realized, it unrealizes temporarily, calls the callback,
2021 * and then re-realizes the actor.
2023 * As a side effect, leaves all children of the actor unrealized if
2024 * the actor was realized but not showing. This is because when we
2025 * unrealize the actor temporarily we must unrealize its children
2026 * (e.g. children of a stage can't be realized if stage window is
2027 * gone). And we aren't clever enough to save the realization state of
2028 * all children. In most cases this should not matter, because
2029 * the children will automatically realize when they next become mapped.
2032 _clutter_actor_rerealize (ClutterActor *self,
2033 ClutterCallback callback,
2036 gboolean was_mapped;
2037 gboolean was_showing;
2038 gboolean was_realized;
2040 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2042 #ifdef CLUTTER_ENABLE_DEBUG
2043 clutter_actor_verify_map_state (self);
2046 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
2047 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
2048 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
2050 /* Must be unmapped to unrealize. Note we only have to hide this
2051 * actor if it was mapped (if all parents were showing). If actor
2052 * is merely visible (but not mapped), then that's fine, we can
2056 clutter_actor_hide (self);
2058 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
2060 /* unrealize self and all children */
2061 clutter_actor_unrealize_not_hiding (self);
2063 if (callback != NULL)
2065 (* callback) (self, data);
2069 clutter_actor_show (self); /* will realize only if mapping implies it */
2070 else if (was_realized)
2071 clutter_actor_realize (self); /* realize self and all parents */
2075 clutter_actor_real_pick (ClutterActor *self,
2076 const ClutterColor *color)
2078 /* the default implementation is just to paint a rectangle
2079 * with the same size of the actor using the passed color
2081 if (clutter_actor_should_pick_paint (self))
2083 ClutterActorBox box = { 0, };
2084 float width, height;
2086 clutter_actor_get_allocation_box (self, &box);
2088 width = box.x2 - box.x1;
2089 height = box.y2 - box.y1;
2091 cogl_set_source_color4ub (color->red,
2096 cogl_rectangle (0, 0, width, height);
2099 /* XXX - this thoroughly sucks, but we need to maintain compatibility
2100 * with existing container classes that override the pick() virtual
2101 * and chain up to the default implementation - otherwise we'll end up
2102 * painting our children twice.
2104 * this has to go away for 2.0; hopefully along the pick() itself.
2106 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2110 for (iter = self->priv->first_child;
2112 iter = iter->priv->next_sibling)
2113 clutter_actor_paint (iter);
2118 * clutter_actor_should_pick_paint:
2119 * @self: A #ClutterActor
2121 * Should be called inside the implementation of the
2122 * #ClutterActor::pick virtual function in order to check whether
2123 * the actor should paint itself in pick mode or not.
2125 * This function should never be called directly by applications.
2127 * Return value: %TRUE if the actor should paint its silhouette,
2131 clutter_actor_should_pick_paint (ClutterActor *self)
2133 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2135 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2136 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2137 CLUTTER_ACTOR_IS_REACTIVE (self)))
2144 clutter_actor_real_get_preferred_width (ClutterActor *self,
2146 gfloat *min_width_p,
2147 gfloat *natural_width_p)
2149 ClutterActorPrivate *priv = self->priv;
2151 if (priv->n_children != 0 &&
2152 priv->layout_manager != NULL)
2154 ClutterContainer *container = CLUTTER_CONTAINER (self);
2156 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2157 "for the preferred width",
2158 G_OBJECT_TYPE_NAME (priv->layout_manager),
2159 priv->layout_manager);
2161 clutter_layout_manager_get_preferred_width (priv->layout_manager,
2170 /* Default implementation is always 0x0, usually an actor
2171 * using this default is relying on someone to set the
2174 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2179 if (natural_width_p)
2180 *natural_width_p = 0;
2184 clutter_actor_real_get_preferred_height (ClutterActor *self,
2186 gfloat *min_height_p,
2187 gfloat *natural_height_p)
2189 ClutterActorPrivate *priv = self->priv;
2191 if (priv->n_children != 0 &&
2192 priv->layout_manager != NULL)
2194 ClutterContainer *container = CLUTTER_CONTAINER (self);
2196 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2197 "for the preferred height",
2198 G_OBJECT_TYPE_NAME (priv->layout_manager),
2199 priv->layout_manager);
2201 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2209 /* Default implementation is always 0x0, usually an actor
2210 * using this default is relying on someone to set the
2213 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2218 if (natural_height_p)
2219 *natural_height_p = 0;
2223 clutter_actor_store_old_geometry (ClutterActor *self,
2224 ClutterActorBox *box)
2226 *box = self->priv->allocation;
2230 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2231 const ClutterActorBox *old)
2233 ClutterActorPrivate *priv = self->priv;
2234 GObject *obj = G_OBJECT (self);
2236 g_object_freeze_notify (obj);
2238 /* to avoid excessive requisition or allocation cycles we
2239 * use the cached values.
2241 * - if we don't have an allocation we assume that we need
2243 * - if we don't have a width or a height request we notify
2245 * - if we have a valid allocation then we check the old
2246 * bounding box with the current allocation and we notify
2249 if (priv->needs_allocation)
2251 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2252 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2253 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2254 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2255 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2256 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2258 else if (priv->needs_width_request || priv->needs_height_request)
2260 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2261 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2262 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2267 gfloat width, height;
2269 x = priv->allocation.x1;
2270 y = priv->allocation.y1;
2271 width = priv->allocation.x2 - priv->allocation.x1;
2272 height = priv->allocation.y2 - priv->allocation.y1;
2276 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2277 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2282 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2283 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2286 if (width != (old->x2 - old->x1))
2288 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2289 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2292 if (height != (old->y2 - old->y1))
2294 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2295 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2299 g_object_thaw_notify (obj);
2303 * clutter_actor_set_allocation_internal:
2304 * @self: a #ClutterActor
2305 * @box: a #ClutterActorBox
2306 * @flags: allocation flags
2308 * Stores the allocation of @self.
2310 * This function only performs basic storage and property notification.
2312 * This function should be called by clutter_actor_set_allocation()
2313 * and by the default implementation of #ClutterActorClass.allocate().
2315 * Return value: %TRUE if the allocation of the #ClutterActor has been
2316 * changed, and %FALSE otherwise
2318 static inline gboolean
2319 clutter_actor_set_allocation_internal (ClutterActor *self,
2320 const ClutterActorBox *box,
2321 ClutterAllocationFlags flags)
2323 ClutterActorPrivate *priv = self->priv;
2325 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2327 ClutterActorBox old_alloc = { 0, };
2329 obj = G_OBJECT (self);
2331 g_object_freeze_notify (obj);
2333 clutter_actor_store_old_geometry (self, &old_alloc);
2335 x1_changed = priv->allocation.x1 != box->x1;
2336 y1_changed = priv->allocation.y1 != box->y1;
2337 x2_changed = priv->allocation.x2 != box->x2;
2338 y2_changed = priv->allocation.y2 != box->y2;
2340 priv->allocation = *box;
2341 priv->allocation_flags = flags;
2343 /* allocation is authoritative */
2344 priv->needs_width_request = FALSE;
2345 priv->needs_height_request = FALSE;
2346 priv->needs_allocation = FALSE;
2353 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2354 _clutter_actor_get_debug_name (self));
2356 priv->transform_valid = FALSE;
2358 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2360 /* if the allocation changes, so does the content box */
2361 if (priv->content != NULL)
2363 priv->content_box_valid = FALSE;
2364 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2372 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2374 g_object_thaw_notify (obj);
2379 static void clutter_actor_real_allocate (ClutterActor *self,
2380 const ClutterActorBox *box,
2381 ClutterAllocationFlags flags);
2384 clutter_actor_maybe_layout_children (ClutterActor *self,
2385 const ClutterActorBox *allocation,
2386 ClutterAllocationFlags flags)
2388 ClutterActorPrivate *priv = self->priv;
2390 /* this is going to be a bit hard to follow, so let's put an explanation
2393 * we want ClutterActor to have a default layout manager if the actor was
2394 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2396 * we also want any subclass of ClutterActor that does not override the
2397 * ::allocate() virtual function to delegate to a layout manager.
2399 * finally, we want to allow people subclassing ClutterActor and overriding
2400 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2402 * on the other hand, we want existing actor subclasses overriding the
2403 * ::allocate() virtual function and chaining up to the parent's
2404 * implementation to continue working without allocating their children
2405 * twice, or without entering an allocation loop.
2407 * for the first two points, we check if the class of the actor is
2408 * overridding the ::allocate() virtual function; if it isn't, then we
2409 * follow through with checking whether we have children and a layout
2410 * manager, and eventually calling clutter_layout_manager_allocate().
2412 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2413 * allocation flags that we got passed, and if it is present, we continue
2414 * with the check above.
2416 * if neither of these two checks yields a positive result, we just
2417 * assume that the ::allocate() virtual function that resulted in this
2418 * function being called will also allocate the children of the actor.
2421 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2424 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2430 if (priv->n_children != 0 &&
2431 priv->layout_manager != NULL)
2433 ClutterContainer *container = CLUTTER_CONTAINER (self);
2434 ClutterAllocationFlags children_flags;
2435 ClutterActorBox children_box;
2437 /* normalize the box passed to the layout manager */
2438 children_box.x1 = children_box.y1 = 0.f;
2439 children_box.x2 = (allocation->x2 - allocation->x1);
2440 children_box.y2 = (allocation->y2 - allocation->y1);
2442 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2443 * the actor's children, since it refers only to the current
2444 * actor's allocation.
2446 children_flags = flags;
2447 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2449 CLUTTER_NOTE (LAYOUT,
2450 "Allocating %d children of %s "
2451 "at { %.2f, %.2f - %.2f x %.2f } "
2454 _clutter_actor_get_debug_name (self),
2457 (allocation->x2 - allocation->x1),
2458 (allocation->y2 - allocation->y1),
2459 G_OBJECT_TYPE_NAME (priv->layout_manager));
2461 clutter_layout_manager_allocate (priv->layout_manager,
2469 clutter_actor_real_allocate (ClutterActor *self,
2470 const ClutterActorBox *box,
2471 ClutterAllocationFlags flags)
2473 ClutterActorPrivate *priv = self->priv;
2476 g_object_freeze_notify (G_OBJECT (self));
2478 changed = clutter_actor_set_allocation_internal (self, box, flags);
2480 /* we allocate our children before we notify changes in our geometry,
2481 * so that people connecting to properties will be able to get valid
2482 * data out of the sub-tree of the scene graph that has this actor at
2485 clutter_actor_maybe_layout_children (self, box, flags);
2489 ClutterActorBox signal_box = priv->allocation;
2490 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2492 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2497 g_object_thaw_notify (G_OBJECT (self));
2501 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2502 ClutterActor *origin)
2504 /* no point in queuing a redraw on a destroyed actor */
2505 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2508 /* NB: We can't bail out early here if the actor is hidden in case
2509 * the actor bas been cloned. In this case the clone will need to
2510 * receive the signal so it can queue its own redraw.
2513 /* calls klass->queue_redraw in default handler */
2514 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2518 clutter_actor_real_queue_redraw (ClutterActor *self,
2519 ClutterActor *origin)
2521 ClutterActor *parent;
2523 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2524 _clutter_actor_get_debug_name (self),
2525 origin != NULL ? _clutter_actor_get_debug_name (origin)
2528 /* no point in queuing a redraw on a destroyed actor */
2529 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2532 /* If the queue redraw is coming from a child then the actor has
2533 become dirty and any queued effect is no longer valid */
2536 self->priv->is_dirty = TRUE;
2537 self->priv->effect_to_redraw = NULL;
2540 /* If the actor isn't visible, we still had to emit the signal
2541 * to allow for a ClutterClone, but the appearance of the parent
2542 * won't change so we don't have to propagate up the hierarchy.
2544 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2547 /* Although we could determine here that a full stage redraw
2548 * has already been queued and immediately bail out, we actually
2549 * guarantee that we will propagate a queue-redraw signal to our
2550 * parent at least once so that it's possible to implement a
2551 * container that tracks which of its children have queued a
2554 if (self->priv->propagated_one_redraw)
2556 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2557 if (stage != NULL &&
2558 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2562 self->priv->propagated_one_redraw = TRUE;
2564 /* notify parents, if they are all visible eventually we'll
2565 * queue redraw on the stage, which queues the redraw idle.
2567 parent = clutter_actor_get_parent (self);
2570 /* this will go up recursively */
2571 _clutter_actor_signal_queue_redraw (parent, origin);
2576 clutter_actor_real_queue_relayout (ClutterActor *self)
2578 ClutterActorPrivate *priv = self->priv;
2580 /* no point in queueing a redraw on a destroyed actor */
2581 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2584 priv->needs_width_request = TRUE;
2585 priv->needs_height_request = TRUE;
2586 priv->needs_allocation = TRUE;
2588 /* reset the cached size requests */
2589 memset (priv->width_requests, 0,
2590 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2591 memset (priv->height_requests, 0,
2592 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2594 /* We need to go all the way up the hierarchy */
2595 if (priv->parent != NULL)
2596 _clutter_actor_queue_only_relayout (priv->parent);
2600 * clutter_actor_apply_relative_transform_to_point:
2601 * @self: A #ClutterActor
2602 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2603 * default #ClutterStage
2604 * @point: A point as #ClutterVertex
2605 * @vertex: (out caller-allocates): The translated #ClutterVertex
2607 * Transforms @point in coordinates relative to the actor into
2608 * ancestor-relative coordinates using the relevant transform
2609 * stack (i.e. scale, rotation, etc).
2611 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2612 * this case, the coordinates returned will be the coordinates on
2613 * the stage before the projection is applied. This is different from
2614 * the behaviour of clutter_actor_apply_transform_to_point().
2619 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2620 ClutterActor *ancestor,
2621 const ClutterVertex *point,
2622 ClutterVertex *vertex)
2627 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2628 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2629 g_return_if_fail (point != NULL);
2630 g_return_if_fail (vertex != NULL);
2635 if (ancestor == NULL)
2636 ancestor = _clutter_actor_get_stage_internal (self);
2638 if (ancestor == NULL)
2644 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2645 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2649 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2650 const ClutterVertex *vertices_in,
2651 ClutterVertex *vertices_out,
2654 ClutterActor *stage;
2655 CoglMatrix modelview;
2656 CoglMatrix projection;
2659 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2661 stage = _clutter_actor_get_stage_internal (self);
2663 /* We really can't do anything meaningful in this case so don't try
2664 * to do any transform */
2668 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2669 * that gets us to stage coordinates, we want to go all the way to eye
2671 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2673 /* Fetch the projection and viewport */
2674 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2675 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2681 _clutter_util_fully_transform_vertices (&modelview,
2692 * clutter_actor_apply_transform_to_point:
2693 * @self: A #ClutterActor
2694 * @point: A point as #ClutterVertex
2695 * @vertex: (out caller-allocates): The translated #ClutterVertex
2697 * Transforms @point in coordinates relative to the actor
2698 * into screen-relative coordinates with the current actor
2699 * transformation (i.e. scale, rotation, etc)
2704 clutter_actor_apply_transform_to_point (ClutterActor *self,
2705 const ClutterVertex *point,
2706 ClutterVertex *vertex)
2708 g_return_if_fail (point != NULL);
2709 g_return_if_fail (vertex != NULL);
2710 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2714 * _clutter_actor_get_relative_transformation_matrix:
2715 * @self: The actor whose coordinate space you want to transform from.
2716 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2717 * or %NULL if you want to transform all the way to eye coordinates.
2718 * @matrix: A #CoglMatrix to store the transformation
2720 * This gets a transformation @matrix that will transform coordinates from the
2721 * coordinate space of @self into the coordinate space of @ancestor.
2723 * For example if you need a matrix that can transform the local actor
2724 * coordinates of @self into stage coordinates you would pass the actor's stage
2725 * pointer as the @ancestor.
2727 * If you pass %NULL then the transformation will take you all the way through
2728 * to eye coordinates. This can be useful if you want to extract the entire
2729 * modelview transform that Clutter applies before applying the projection
2730 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2731 * using cogl_set_modelview_matrix() for example then you would want a matrix
2732 * that transforms into eye coordinates.
2734 * <note><para>This function explicitly initializes the given @matrix. If you just
2735 * want clutter to multiply a relative transformation with an existing matrix
2736 * you can use clutter_actor_apply_relative_transformation_matrix()
2737 * instead.</para></note>
2740 /* XXX: We should consider caching the stage relative modelview along with
2741 * the actor itself */
2743 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2744 ClutterActor *ancestor,
2747 cogl_matrix_init_identity (matrix);
2749 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2752 /* Project the given @box into stage window coordinates, writing the
2753 * transformed vertices to @verts[]. */
2755 _clutter_actor_transform_and_project_box (ClutterActor *self,
2756 const ClutterActorBox *box,
2757 ClutterVertex verts[])
2759 ClutterVertex box_vertices[4];
2761 box_vertices[0].x = box->x1;
2762 box_vertices[0].y = box->y1;
2763 box_vertices[0].z = 0;
2764 box_vertices[1].x = box->x2;
2765 box_vertices[1].y = box->y1;
2766 box_vertices[1].z = 0;
2767 box_vertices[2].x = box->x1;
2768 box_vertices[2].y = box->y2;
2769 box_vertices[2].z = 0;
2770 box_vertices[3].x = box->x2;
2771 box_vertices[3].y = box->y2;
2772 box_vertices[3].z = 0;
2775 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2779 * clutter_actor_get_allocation_vertices:
2780 * @self: A #ClutterActor
2781 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2782 * against, or %NULL to use the #ClutterStage
2783 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2784 * location for an array of 4 #ClutterVertex in which to store the result
2786 * Calculates the transformed coordinates of the four corners of the
2787 * actor in the plane of @ancestor. The returned vertices relate to
2788 * the #ClutterActorBox coordinates as follows:
2790 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2791 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2792 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2793 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2796 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2797 * this case, the coordinates returned will be the coordinates on
2798 * the stage before the projection is applied. This is different from
2799 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2804 clutter_actor_get_allocation_vertices (ClutterActor *self,
2805 ClutterActor *ancestor,
2806 ClutterVertex verts[])
2808 ClutterActorPrivate *priv;
2809 ClutterActorBox box;
2810 ClutterVertex vertices[4];
2811 CoglMatrix modelview;
2813 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2814 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2816 if (ancestor == NULL)
2817 ancestor = _clutter_actor_get_stage_internal (self);
2819 /* Fallback to a NOP transform if the actor isn't parented under a
2821 if (ancestor == NULL)
2826 /* if the actor needs to be allocated we force a relayout, so that
2827 * we will have valid values to use in the transformations */
2828 if (priv->needs_allocation)
2830 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2832 _clutter_stage_maybe_relayout (stage);
2835 box.x1 = box.y1 = 0;
2836 /* The result isn't really meaningful in this case but at
2837 * least try to do something *vaguely* reasonable... */
2838 clutter_actor_get_size (self, &box.x2, &box.y2);
2842 clutter_actor_get_allocation_box (self, &box);
2844 vertices[0].x = box.x1;
2845 vertices[0].y = box.y1;
2847 vertices[1].x = box.x2;
2848 vertices[1].y = box.y1;
2850 vertices[2].x = box.x1;
2851 vertices[2].y = box.y2;
2853 vertices[3].x = box.x2;
2854 vertices[3].y = box.y2;
2857 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2860 cogl_matrix_transform_points (&modelview,
2862 sizeof (ClutterVertex),
2864 sizeof (ClutterVertex),
2870 * clutter_actor_get_abs_allocation_vertices:
2871 * @self: A #ClutterActor
2872 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2873 * of 4 #ClutterVertex where to store the result.
2875 * Calculates the transformed screen coordinates of the four corners of
2876 * the actor; the returned vertices relate to the #ClutterActorBox
2877 * coordinates as follows:
2879 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2880 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2881 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2882 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2888 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2889 ClutterVertex verts[])
2891 ClutterActorPrivate *priv;
2892 ClutterActorBox actor_space_allocation;
2894 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2898 /* if the actor needs to be allocated we force a relayout, so that
2899 * the actor allocation box will be valid for
2900 * _clutter_actor_transform_and_project_box()
2902 if (priv->needs_allocation)
2904 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2905 /* There's nothing meaningful we can do now */
2909 _clutter_stage_maybe_relayout (stage);
2912 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2913 * own coordinate space... */
2914 actor_space_allocation.x1 = 0;
2915 actor_space_allocation.y1 = 0;
2916 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2917 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2918 _clutter_actor_transform_and_project_box (self,
2919 &actor_space_allocation,
2924 clutter_actor_real_apply_transform (ClutterActor *self,
2927 ClutterActorPrivate *priv = self->priv;
2929 if (!priv->transform_valid)
2931 CoglMatrix *transform = &priv->transform;
2932 const ClutterTransformInfo *info;
2934 info = _clutter_actor_get_transform_info_or_defaults (self);
2936 cogl_matrix_init_identity (transform);
2938 cogl_matrix_translate (transform,
2939 priv->allocation.x1,
2940 priv->allocation.y1,
2944 cogl_matrix_translate (transform, 0, 0, info->depth);
2947 * because the rotation involves translations, we must scale
2948 * before applying the rotations (if we apply the scale after
2949 * the rotations, the translations included in the rotation are
2950 * not scaled and so the entire object will move on the screen
2951 * as a result of rotating it).
2953 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2955 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2956 &info->scale_center,
2957 cogl_matrix_scale (transform,
2964 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2966 cogl_matrix_rotate (transform,
2971 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2973 cogl_matrix_rotate (transform,
2978 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2980 cogl_matrix_rotate (transform,
2984 if (!clutter_anchor_coord_is_zero (&info->anchor))
2988 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2989 cogl_matrix_translate (transform, -x, -y, -z);
2992 priv->transform_valid = TRUE;
2995 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2998 /* Applies the transforms associated with this actor to the given
3001 _clutter_actor_apply_modelview_transform (ClutterActor *self,
3004 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
3008 * clutter_actor_apply_relative_transformation_matrix:
3009 * @self: The actor whose coordinate space you want to transform from.
3010 * @ancestor: The ancestor actor whose coordinate space you want to transform too
3011 * or %NULL if you want to transform all the way to eye coordinates.
3012 * @matrix: A #CoglMatrix to apply the transformation too.
3014 * This multiplies a transform with @matrix that will transform coordinates
3015 * from the coordinate space of @self into the coordinate space of @ancestor.
3017 * For example if you need a matrix that can transform the local actor
3018 * coordinates of @self into stage coordinates you would pass the actor's stage
3019 * pointer as the @ancestor.
3021 * If you pass %NULL then the transformation will take you all the way through
3022 * to eye coordinates. This can be useful if you want to extract the entire
3023 * modelview transform that Clutter applies before applying the projection
3024 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
3025 * using cogl_set_modelview_matrix() for example then you would want a matrix
3026 * that transforms into eye coordinates.
3028 * <note>This function doesn't initialize the given @matrix, it simply
3029 * multiplies the requested transformation matrix with the existing contents of
3030 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
3031 * before calling this function, or you can use
3032 * clutter_actor_get_relative_transformation_matrix() instead.</note>
3035 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
3036 ClutterActor *ancestor,
3039 ClutterActor *parent;
3041 /* Note we terminate before ever calling stage->apply_transform()
3042 * since that would conceptually be relative to the underlying
3043 * window OpenGL coordinates so we'd need a special @ancestor
3044 * value to represent the fake parent of the stage. */
3045 if (self == ancestor)
3048 parent = clutter_actor_get_parent (self);
3051 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
3054 _clutter_actor_apply_modelview_transform (self, matrix);
3058 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
3059 ClutterPaintVolume *pv,
3061 const CoglColor *color)
3063 static CoglPipeline *outline = NULL;
3064 CoglPrimitive *prim;
3065 ClutterVertex line_ends[12 * 2];
3068 clutter_backend_get_cogl_context (clutter_get_default_backend ());
3069 /* XXX: at some point we'll query this from the stage but we can't
3070 * do that until the osx backend uses Cogl natively. */
3071 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
3073 if (outline == NULL)
3074 outline = cogl_pipeline_new (ctx);
3076 _clutter_paint_volume_complete (pv);
3078 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3081 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3082 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3083 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3084 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3089 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3090 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3091 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3092 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3094 /* Lines connecting front face to back face */
3095 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3096 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3097 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3098 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3101 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3103 (CoglVertexP3 *)line_ends);
3105 cogl_pipeline_set_color (outline, color);
3106 cogl_framebuffer_draw_primitive (fb, outline, prim);
3107 cogl_object_unref (prim);
3111 PangoLayout *layout;
3112 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3113 pango_layout_set_text (layout, label, -1);
3114 cogl_pango_render_layout (layout,
3119 g_object_unref (layout);
3124 _clutter_actor_draw_paint_volume (ClutterActor *self)
3126 ClutterPaintVolume *pv;
3129 pv = _clutter_actor_get_paint_volume_mutable (self);
3132 gfloat width, height;
3133 ClutterPaintVolume fake_pv;
3135 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3136 _clutter_paint_volume_init_static (&fake_pv, stage);
3138 clutter_actor_get_size (self, &width, &height);
3139 clutter_paint_volume_set_width (&fake_pv, width);
3140 clutter_paint_volume_set_height (&fake_pv, height);
3142 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3143 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3144 _clutter_actor_get_debug_name (self),
3147 clutter_paint_volume_free (&fake_pv);
3151 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3152 _clutter_actor_draw_paint_volume_full (self, pv,
3153 _clutter_actor_get_debug_name (self),
3159 _clutter_actor_paint_cull_result (ClutterActor *self,
3161 ClutterCullResult result)
3163 ClutterPaintVolume *pv;
3168 if (result == CLUTTER_CULL_RESULT_IN)
3169 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3170 else if (result == CLUTTER_CULL_RESULT_OUT)
3171 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3173 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3176 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3178 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3179 _clutter_actor_draw_paint_volume_full (self, pv,
3180 _clutter_actor_get_debug_name (self),
3184 PangoLayout *layout;
3186 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3187 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3188 cogl_set_source_color (&color);
3190 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3191 pango_layout_set_text (layout, label, -1);
3192 cogl_pango_render_layout (layout,
3198 g_object_unref (layout);
3202 static int clone_paint_level = 0;
3205 _clutter_actor_push_clone_paint (void)
3207 clone_paint_level++;
3211 _clutter_actor_pop_clone_paint (void)
3213 clone_paint_level--;
3217 in_clone_paint (void)
3219 return clone_paint_level > 0;
3222 /* Returns TRUE if the actor can be ignored */
3223 /* FIXME: we should return a ClutterCullResult, and
3224 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3225 * means there's no point in trying to cull descendants of the current
3228 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3230 ClutterActorPrivate *priv = self->priv;
3231 ClutterActor *stage;
3232 const ClutterPlane *stage_clip;
3234 if (!priv->last_paint_volume_valid)
3236 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3237 "->last_paint_volume_valid == FALSE",
3238 _clutter_actor_get_debug_name (self));
3242 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3245 stage = _clutter_actor_get_stage_internal (self);
3246 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3247 if (G_UNLIKELY (!stage_clip))
3249 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3250 "No stage clip set",
3251 _clutter_actor_get_debug_name (self));
3255 if (cogl_get_draw_framebuffer () !=
3256 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3258 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3259 "Current framebuffer doesn't correspond to stage",
3260 _clutter_actor_get_debug_name (self));
3265 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3270 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3272 ClutterActorPrivate *priv = self->priv;
3273 const ClutterPaintVolume *pv;
3275 if (priv->last_paint_volume_valid)
3277 clutter_paint_volume_free (&priv->last_paint_volume);
3278 priv->last_paint_volume_valid = FALSE;
3281 pv = clutter_actor_get_paint_volume (self);
3284 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3285 "Actor failed to report a paint volume",
3286 _clutter_actor_get_debug_name (self));
3290 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3292 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3293 NULL); /* eye coordinates */
3295 priv->last_paint_volume_valid = TRUE;
3298 static inline gboolean
3299 actor_has_shader_data (ClutterActor *self)
3301 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3305 _clutter_actor_get_pick_id (ClutterActor *self)
3307 if (self->priv->pick_id < 0)
3310 return self->priv->pick_id;
3313 /* This is the same as clutter_actor_add_effect except that it doesn't
3314 queue a redraw and it doesn't notify on the effect property */
3316 _clutter_actor_add_effect_internal (ClutterActor *self,
3317 ClutterEffect *effect)
3319 ClutterActorPrivate *priv = self->priv;
3321 if (priv->effects == NULL)
3323 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3324 priv->effects->actor = self;
3327 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3330 /* This is the same as clutter_actor_remove_effect except that it doesn't
3331 queue a redraw and it doesn't notify on the effect property */
3333 _clutter_actor_remove_effect_internal (ClutterActor *self,
3334 ClutterEffect *effect)
3336 ClutterActorPrivate *priv = self->priv;
3338 if (priv->effects == NULL)
3341 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3343 if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3344 g_clear_object (&priv->effects);
3348 needs_flatten_effect (ClutterActor *self)
3350 ClutterActorPrivate *priv = self->priv;
3352 if (G_UNLIKELY (clutter_paint_debug_flags &
3353 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3356 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3358 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3360 if (clutter_actor_get_paint_opacity (self) < 255 &&
3361 clutter_actor_has_overlaps (self))
3369 add_or_remove_flatten_effect (ClutterActor *self)
3371 ClutterActorPrivate *priv = self->priv;
3373 /* Add or remove the flatten effect depending on the
3374 offscreen-redirect property. */
3375 if (needs_flatten_effect (self))
3377 if (priv->flatten_effect == NULL)
3379 ClutterActorMeta *actor_meta;
3382 priv->flatten_effect = _clutter_flatten_effect_new ();
3383 /* Keep a reference to the effect so that we can queue
3385 g_object_ref_sink (priv->flatten_effect);
3387 /* Set the priority of the effect to high so that it will
3388 always be applied to the actor first. It uses an internal
3389 priority so that it won't be visible to applications */
3390 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3391 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3392 _clutter_actor_meta_set_priority (actor_meta, priority);
3394 /* This will add the effect without queueing a redraw */
3395 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3400 if (priv->flatten_effect != NULL)
3402 /* Destroy the effect so that it will lose its fbo cache of
3404 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3405 g_clear_object (&priv->flatten_effect);
3411 clutter_actor_real_paint (ClutterActor *actor)
3413 ClutterActorPrivate *priv = actor->priv;
3416 for (iter = priv->first_child;
3418 iter = iter->priv->next_sibling)
3420 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3421 _clutter_actor_get_debug_name (iter),
3422 _clutter_actor_get_debug_name (actor),
3423 iter->priv->allocation.x1,
3424 iter->priv->allocation.y1,
3425 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3426 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3428 clutter_actor_paint (iter);
3433 clutter_actor_paint_node (ClutterActor *actor,
3434 ClutterPaintNode *root)
3436 ClutterActorPrivate *priv = actor->priv;
3441 if (priv->bg_color_set &&
3442 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3444 ClutterPaintNode *node;
3445 ClutterColor bg_color;
3446 ClutterActorBox box;
3450 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3451 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3453 bg_color = priv->bg_color;
3454 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3455 * priv->bg_color.alpha
3458 node = clutter_color_node_new (&bg_color);
3459 clutter_paint_node_set_name (node, "backgroundColor");
3460 clutter_paint_node_add_rectangle (node, &box);
3461 clutter_paint_node_add_child (root, node);
3462 clutter_paint_node_unref (node);
3465 if (priv->content != NULL)
3466 _clutter_content_paint_content (priv->content, actor, root);
3468 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3469 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3471 if (clutter_paint_node_get_n_children (root) == 0)
3474 #ifdef CLUTTER_ENABLE_DEBUG
3475 if (CLUTTER_HAS_DEBUG (PAINT))
3477 /* dump the tree only if we have one */
3478 _clutter_paint_node_dump_tree (root);
3480 #endif /* CLUTTER_ENABLE_DEBUG */
3482 _clutter_paint_node_paint (root);
3485 /* XXX: Uncomment this when we disable emitting the paint signal */
3486 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3493 * clutter_actor_paint:
3494 * @self: A #ClutterActor
3496 * Renders the actor to display.
3498 * This function should not be called directly by applications.
3499 * Call clutter_actor_queue_redraw() to queue paints, instead.
3501 * This function is context-aware, and will either cause a
3502 * regular paint or a pick paint.
3504 * This function will emit the #ClutterActor::paint signal or
3505 * the #ClutterActor::pick signal, depending on the context.
3507 * This function does not paint the actor if the actor is set to 0,
3508 * unless it is performing a pick paint.
3511 clutter_actor_paint (ClutterActor *self)
3513 ClutterActorPrivate *priv;
3514 ClutterPickMode pick_mode;
3515 gboolean clip_set = FALSE;
3516 gboolean shader_applied = FALSE;
3518 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3519 "Actor real-paint counter",
3520 "Increments each time any actor is painted",
3521 0 /* no application private data */);
3522 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3523 "Actor pick-paint counter",
3524 "Increments each time any actor is painted "
3526 0 /* no application private data */);
3528 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3530 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3535 pick_mode = _clutter_context_get_pick_mode ();
3537 if (pick_mode == CLUTTER_PICK_NONE)
3538 priv->propagated_one_redraw = FALSE;
3540 /* It's an important optimization that we consider painting of
3541 * actors with 0 opacity to be a NOP... */
3542 if (pick_mode == CLUTTER_PICK_NONE &&
3543 /* ignore top-levels, since they might be transparent */
3544 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3545 /* Use the override opacity if its been set */
3546 ((priv->opacity_override >= 0) ?
3547 priv->opacity_override : priv->opacity) == 0)
3550 /* if we aren't paintable (not in a toplevel with all
3551 * parents paintable) then do nothing.
3553 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3556 /* mark that we are in the paint process */
3557 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3561 if (priv->enable_model_view_transform)
3565 /* XXX: It could be better to cache the modelview with the actor
3566 * instead of progressively building up the transformations on
3567 * the matrix stack every time we paint. */
3568 cogl_get_modelview_matrix (&matrix);
3569 _clutter_actor_apply_modelview_transform (self, &matrix);
3571 #ifdef CLUTTER_ENABLE_DEBUG
3572 /* Catch when out-of-band transforms have been made by actors not as part
3573 * of an apply_transform vfunc... */
3574 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3576 CoglMatrix expected_matrix;
3578 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3581 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3583 GString *buf = g_string_sized_new (1024);
3584 ClutterActor *parent;
3587 while (parent != NULL)
3589 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3591 if (parent->priv->parent != NULL)
3592 g_string_append (buf, "->");
3594 parent = parent->priv->parent;
3597 g_warning ("Unexpected transform found when painting actor "
3598 "\"%s\". This will be caused by one of the actor's "
3599 "ancestors (%s) using the Cogl API directly to transform "
3600 "children instead of using ::apply_transform().",
3601 _clutter_actor_get_debug_name (self),
3604 g_string_free (buf, TRUE);
3607 #endif /* CLUTTER_ENABLE_DEBUG */
3609 cogl_set_modelview_matrix (&matrix);
3614 cogl_clip_push_rectangle (priv->clip.x,
3616 priv->clip.x + priv->clip.width,
3617 priv->clip.y + priv->clip.height);
3620 else if (priv->clip_to_allocation)
3622 gfloat width, height;
3624 width = priv->allocation.x2 - priv->allocation.x1;
3625 height = priv->allocation.y2 - priv->allocation.y1;
3627 cogl_clip_push_rectangle (0, 0, width, height);
3631 if (pick_mode == CLUTTER_PICK_NONE)
3633 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3635 /* We check whether we need to add the flatten effect before
3636 each paint so that we can avoid having a mechanism for
3637 applications to notify when the value of the
3638 has_overlaps virtual changes. */
3639 add_or_remove_flatten_effect (self);
3642 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3644 /* We save the current paint volume so that the next time the
3645 * actor queues a redraw we can constrain the redraw to just
3646 * cover the union of the new bounding box and the old.
3648 * We also fetch the current paint volume to perform culling so
3649 * we can avoid painting actors outside the current clip region.
3651 * If we are painting inside a clone, we should neither update
3652 * the paint volume or use it to cull painting, since the paint
3653 * box represents the location of the source actor on the
3656 * XXX: We are starting to do a lot of vertex transforms on
3657 * the CPU in a typical paint, so at some point we should
3658 * audit these and consider caching some things.
3660 * NB: We don't perform culling while picking at this point because
3661 * clutter-stage.c doesn't setup the clipping planes appropriately.
3663 * NB: We don't want to update the last-paint-volume during picking
3664 * because the last-paint-volume is used to determine the old screen
3665 * space location of an actor that has moved so we can know the
3666 * minimal region to redraw to clear an old view of the actor. If we
3667 * update this during picking then by the time we come around to
3668 * paint then the last-paint-volume would likely represent the new
3669 * actor position not the old.
3671 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3674 /* annoyingly gcc warns if uninitialized even though
3675 * the initialization is redundant :-( */
3676 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3678 if (G_LIKELY ((clutter_paint_debug_flags &
3679 (CLUTTER_DEBUG_DISABLE_CULLING |
3680 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3681 (CLUTTER_DEBUG_DISABLE_CULLING |
3682 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3683 _clutter_actor_update_last_paint_volume (self);
3685 success = cull_actor (self, &result);
3687 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3688 _clutter_actor_paint_cull_result (self, success, result);
3689 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3693 if (priv->effects == NULL)
3695 if (pick_mode == CLUTTER_PICK_NONE &&
3696 actor_has_shader_data (self))
3698 _clutter_actor_shader_pre_paint (self, FALSE);
3699 shader_applied = TRUE;
3702 priv->next_effect_to_paint = NULL;
3705 priv->next_effect_to_paint =
3706 _clutter_meta_group_peek_metas (priv->effects);
3708 clutter_actor_continue_paint (self);
3711 _clutter_actor_shader_post_paint (self);
3713 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3714 pick_mode == CLUTTER_PICK_NONE))
3715 _clutter_actor_draw_paint_volume (self);
3718 /* If we make it here then the actor has run through a complete
3719 paint run including all the effects so it's no longer dirty */
3720 if (pick_mode == CLUTTER_PICK_NONE)
3721 priv->is_dirty = FALSE;
3728 /* paint sequence complete */
3729 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3733 * clutter_actor_continue_paint:
3734 * @self: A #ClutterActor
3736 * Run the next stage of the paint sequence. This function should only
3737 * be called within the implementation of the ‘run’ virtual of a
3738 * #ClutterEffect. It will cause the run method of the next effect to
3739 * be applied, or it will paint the actual actor if the current effect
3740 * is the last effect in the chain.
3745 clutter_actor_continue_paint (ClutterActor *self)
3747 ClutterActorPrivate *priv;
3749 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3750 /* This should only be called from with in the ‘run’ implementation
3751 of a ClutterEffect */
3752 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3756 /* Skip any effects that are disabled */
3757 while (priv->next_effect_to_paint &&
3758 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3759 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3761 /* If this has come from the last effect then we'll just paint the
3763 if (priv->next_effect_to_paint == NULL)
3765 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3767 ClutterPaintNode *dummy;
3769 /* XXX - this will go away in 2.0, when we can get rid of this
3770 * stuff and switch to a pure retained render tree of PaintNodes
3771 * for the entire frame, starting from the Stage; the paint()
3772 * virtual function can then be called directly.
3774 dummy = _clutter_dummy_node_new (self);
3775 clutter_paint_node_set_name (dummy, "Root");
3777 /* XXX - for 1.12, we use the return value of paint_node() to
3778 * decide whether we should emit the ::paint signal.
3780 clutter_actor_paint_node (self, dummy);
3781 clutter_paint_node_unref (dummy);
3783 g_signal_emit (self, actor_signals[PAINT], 0);
3787 ClutterColor col = { 0, };
3789 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3791 /* Actor will then paint silhouette of itself in supplied
3792 * color. See clutter_stage_get_actor_at_pos() for where
3793 * picking is enabled.
3795 g_signal_emit (self, actor_signals[PICK], 0, &col);
3800 ClutterEffect *old_current_effect;
3801 ClutterEffectPaintFlags run_flags = 0;
3803 /* Cache the current effect so that we can put it back before
3805 old_current_effect = priv->current_effect;
3807 priv->current_effect = priv->next_effect_to_paint->data;
3808 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3810 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3814 /* If there's an effect queued with this redraw then all
3815 effects up to that one will be considered dirty. It
3816 is expected the queued effect will paint the cached
3817 image and not call clutter_actor_continue_paint again
3818 (although it should work ok if it does) */
3819 if (priv->effect_to_redraw == NULL ||
3820 priv->current_effect != priv->effect_to_redraw)
3821 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3824 _clutter_effect_paint (priv->current_effect, run_flags);
3828 /* We can't determine when an actor has been modified since
3829 its last pick so lets just assume it has always been
3831 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3833 _clutter_effect_pick (priv->current_effect, run_flags);
3836 priv->current_effect = old_current_effect;
3841 _clutter_actor_stop_transitions (ClutterActor *self)
3843 const ClutterAnimationInfo *info;
3844 GHashTableIter iter;
3847 info = _clutter_actor_get_animation_info_or_defaults (self);
3848 if (info->transitions == NULL)
3851 g_hash_table_iter_init (&iter, info->transitions);
3852 while (g_hash_table_iter_next (&iter, NULL, &value))
3854 TransitionClosure *closure = value;
3855 clutter_timeline_stop (CLUTTER_TIMELINE (closure->transition));
3859 static ClutterActorTraverseVisitFlags
3860 invalidate_queue_redraw_entry (ClutterActor *self,
3864 ClutterActorPrivate *priv = self->priv;
3866 if (priv->queue_redraw_entry != NULL)
3868 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3869 priv->queue_redraw_entry = NULL;
3872 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3876 remove_child (ClutterActor *self,
3877 ClutterActor *child)
3879 ClutterActor *prev_sibling, *next_sibling;
3881 prev_sibling = child->priv->prev_sibling;
3882 next_sibling = child->priv->next_sibling;
3884 if (prev_sibling != NULL)
3885 prev_sibling->priv->next_sibling = next_sibling;
3887 if (next_sibling != NULL)
3888 next_sibling->priv->prev_sibling = prev_sibling;
3890 if (self->priv->first_child == child)
3891 self->priv->first_child = next_sibling;
3893 if (self->priv->last_child == child)
3894 self->priv->last_child = prev_sibling;
3896 child->priv->parent = NULL;
3897 child->priv->prev_sibling = NULL;
3898 child->priv->next_sibling = NULL;
3902 REMOVE_CHILD_DESTROY_META = 1 << 0,
3903 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3904 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3905 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3906 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3907 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3908 REMOVE_CHILD_STOP_TRANSITIONS = 1 << 6,
3910 /* default flags for public API */
3911 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_STOP_TRANSITIONS |
3912 REMOVE_CHILD_DESTROY_META |
3913 REMOVE_CHILD_EMIT_PARENT_SET |
3914 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3915 REMOVE_CHILD_CHECK_STATE |
3916 REMOVE_CHILD_FLUSH_QUEUE |
3917 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3919 /* flags for legacy/deprecated API */
3920 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_STOP_TRANSITIONS |
3921 REMOVE_CHILD_CHECK_STATE |
3922 REMOVE_CHILD_FLUSH_QUEUE |
3923 REMOVE_CHILD_EMIT_PARENT_SET |
3924 REMOVE_CHILD_NOTIFY_FIRST_LAST
3925 } ClutterActorRemoveChildFlags;
3928 * clutter_actor_remove_child_internal:
3929 * @self: a #ClutterActor
3930 * @child: the child of @self that has to be removed
3931 * @flags: control the removal operations
3933 * Removes @child from the list of children of @self.
3936 clutter_actor_remove_child_internal (ClutterActor *self,
3937 ClutterActor *child,
3938 ClutterActorRemoveChildFlags flags)
3940 ClutterActor *old_first, *old_last;
3941 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3942 gboolean flush_queue;
3943 gboolean notify_first_last;
3944 gboolean was_mapped;
3945 gboolean stop_transitions;
3947 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3948 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3949 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3950 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3951 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3952 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3953 stop_transitions = (flags & REMOVE_CHILD_STOP_TRANSITIONS) != 0;
3955 g_object_freeze_notify (G_OBJECT (self));
3957 if (stop_transitions)
3958 _clutter_actor_stop_transitions (child);
3961 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3965 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3967 /* we need to unrealize *before* we set parent_actor to NULL,
3968 * because in an unrealize method actors are dissociating from the
3969 * stage, which means they need to be able to
3970 * clutter_actor_get_stage().
3972 * yhis should unmap and unrealize, unless we're reparenting.
3974 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3981 /* We take this opportunity to invalidate any queue redraw entry
3982 * associated with the actor and descendants since we won't be able to
3983 * determine the appropriate stage after this.
3985 * we do this after we updated the mapped state because actors might
3986 * end up queueing redraws inside their mapped/unmapped virtual
3987 * functions, and if we invalidate the redraw entry we could end up
3988 * with an inconsistent state and weird memory corruption. see
3991 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3992 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3994 _clutter_actor_traverse (child,
3996 invalidate_queue_redraw_entry,
4001 old_first = self->priv->first_child;
4002 old_last = self->priv->last_child;
4004 remove_child (self, child);
4006 self->priv->n_children -= 1;
4008 self->priv->age += 1;
4010 /* if the child that got removed was visible and set to
4011 * expand then we want to reset the parent's state in
4012 * case the child was the only thing that was making it
4015 if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
4016 (child->priv->needs_compute_expand ||
4017 child->priv->needs_x_expand ||
4018 child->priv->needs_y_expand))
4020 clutter_actor_queue_compute_expand (self);
4023 /* clutter_actor_reparent() will emit ::parent-set for us */
4024 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
4025 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
4027 /* if the child was mapped then we need to relayout ourselves to account
4028 * for the removed child
4031 clutter_actor_queue_relayout (self);
4033 /* we need to emit the signal before dropping the reference */
4034 if (emit_actor_removed)
4035 g_signal_emit_by_name (self, "actor-removed", child);
4037 if (notify_first_last)
4039 if (old_first != self->priv->first_child)
4040 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
4042 if (old_last != self->priv->last_child)
4043 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
4046 g_object_thaw_notify (G_OBJECT (self));
4048 /* remove the reference we acquired in clutter_actor_add_child() */
4049 g_object_unref (child);
4052 static const ClutterTransformInfo default_transform_info = {
4053 0.0, { 0, }, /* rotation-x */
4054 0.0, { 0, }, /* rotation-y */
4055 0.0, { 0, }, /* rotation-z */
4057 1.0, 1.0, { 0, }, /* scale */
4059 { 0, }, /* anchor */
4065 * _clutter_actor_get_transform_info_or_defaults:
4066 * @self: a #ClutterActor
4068 * Retrieves the ClutterTransformInfo structure associated to an actor.
4070 * If the actor does not have a ClutterTransformInfo structure associated
4071 * to it, then the default structure will be returned.
4073 * This function should only be used for getters.
4075 * Return value: a const pointer to the ClutterTransformInfo structure
4077 const ClutterTransformInfo *
4078 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
4080 ClutterTransformInfo *info;
4082 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4086 return &default_transform_info;
4090 clutter_transform_info_free (gpointer data)
4093 g_slice_free (ClutterTransformInfo, data);
4097 * _clutter_actor_get_transform_info:
4098 * @self: a #ClutterActor
4100 * Retrieves a pointer to the ClutterTransformInfo structure.
4102 * If the actor does not have a ClutterTransformInfo associated to it, one
4103 * will be created and initialized to the default values.
4105 * This function should be used for setters.
4107 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
4110 * Return value: (transfer none): a pointer to the ClutterTransformInfo
4113 ClutterTransformInfo *
4114 _clutter_actor_get_transform_info (ClutterActor *self)
4116 ClutterTransformInfo *info;
4118 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4121 info = g_slice_new (ClutterTransformInfo);
4123 *info = default_transform_info;
4125 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4127 clutter_transform_info_free);
4134 * clutter_actor_set_rotation_angle_internal:
4135 * @self: a #ClutterActor
4136 * @axis: the axis of the angle to change
4137 * @angle: the angle of rotation
4139 * Sets the rotation angle on the given axis without affecting the
4140 * rotation center point.
4143 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
4144 ClutterRotateAxis axis,
4147 GObject *obj = G_OBJECT (self);
4148 ClutterTransformInfo *info;
4150 info = _clutter_actor_get_transform_info (self);
4152 g_object_freeze_notify (obj);
4156 case CLUTTER_X_AXIS:
4157 info->rx_angle = angle;
4158 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4161 case CLUTTER_Y_AXIS:
4162 info->ry_angle = angle;
4163 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4166 case CLUTTER_Z_AXIS:
4167 info->rz_angle = angle;
4168 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4172 self->priv->transform_valid = FALSE;
4174 g_object_thaw_notify (obj);
4176 clutter_actor_queue_redraw (self);
4180 clutter_actor_set_rotation_angle (ClutterActor *self,
4181 ClutterRotateAxis axis,
4184 const ClutterTransformInfo *info;
4185 const double *cur_angle_p = NULL;
4186 GParamSpec *pspec = NULL;
4188 info = _clutter_actor_get_transform_info_or_defaults (self);
4192 case CLUTTER_X_AXIS:
4193 cur_angle_p = &info->rx_angle;
4194 pspec = obj_props[PROP_ROTATION_ANGLE_X];
4197 case CLUTTER_Y_AXIS:
4198 cur_angle_p = &info->ry_angle;
4199 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4202 case CLUTTER_Z_AXIS:
4203 cur_angle_p = &info->rz_angle;
4204 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4208 g_assert (pspec != NULL);
4209 g_assert (cur_angle_p != NULL);
4211 if (_clutter_actor_get_transition (self, pspec) == NULL)
4212 _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4214 _clutter_actor_update_transition (self, pspec, angle);
4216 clutter_actor_queue_redraw (self);
4220 * clutter_actor_set_rotation_center_internal:
4221 * @self: a #ClutterActor
4222 * @axis: the axis of the center to change
4223 * @center: the coordinates of the rotation center
4225 * Sets the rotation center on the given axis without affecting the
4229 clutter_actor_set_rotation_center_internal (ClutterActor *self,
4230 ClutterRotateAxis axis,
4231 const ClutterVertex *center)
4233 GObject *obj = G_OBJECT (self);
4234 ClutterTransformInfo *info;
4235 ClutterVertex v = { 0, 0, 0 };
4237 info = _clutter_actor_get_transform_info (self);
4242 g_object_freeze_notify (obj);
4246 case CLUTTER_X_AXIS:
4247 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4248 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4251 case CLUTTER_Y_AXIS:
4252 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4253 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4256 case CLUTTER_Z_AXIS:
4257 /* if the previously set rotation center was fractional, then
4258 * setting explicit coordinates will have to notify the
4259 * :rotation-center-z-gravity property as well
4261 if (info->rz_center.is_fractional)
4262 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4264 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4265 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4269 self->priv->transform_valid = FALSE;
4271 g_object_thaw_notify (obj);
4273 clutter_actor_queue_redraw (self);
4277 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4281 GObject *obj = G_OBJECT (self);
4282 ClutterTransformInfo *info;
4284 info = _clutter_actor_get_transform_info (self);
4286 if (pspec == obj_props[PROP_SCALE_X])
4287 info->scale_x = factor;
4289 info->scale_y = factor;
4291 self->priv->transform_valid = FALSE;
4292 clutter_actor_queue_redraw (self);
4293 g_object_notify_by_pspec (obj, pspec);
4297 clutter_actor_set_scale_factor (ClutterActor *self,
4298 ClutterRotateAxis axis,
4301 const ClutterTransformInfo *info;
4302 const double *scale_p = NULL;
4303 GParamSpec *pspec = NULL;
4305 info = _clutter_actor_get_transform_info_or_defaults (self);
4309 case CLUTTER_X_AXIS:
4310 pspec = obj_props[PROP_SCALE_X];
4311 scale_p = &info->scale_x;
4314 case CLUTTER_Y_AXIS:
4315 pspec = obj_props[PROP_SCALE_Y];
4316 scale_p = &info->scale_y;
4319 case CLUTTER_Z_AXIS:
4323 g_assert (pspec != NULL);
4324 g_assert (scale_p != NULL);
4326 if (_clutter_actor_get_transition (self, pspec) == NULL)
4327 _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4329 _clutter_actor_update_transition (self, pspec, factor);
4331 clutter_actor_queue_redraw (self);
4335 clutter_actor_set_scale_center (ClutterActor *self,
4336 ClutterRotateAxis axis,
4339 GObject *obj = G_OBJECT (self);
4340 ClutterTransformInfo *info;
4341 gfloat center_x, center_y;
4343 info = _clutter_actor_get_transform_info (self);
4345 g_object_freeze_notify (obj);
4347 /* get the current scale center coordinates */
4348 clutter_anchor_coord_get_units (self, &info->scale_center,
4353 /* we need to notify this too, because setting explicit coordinates will
4354 * change the gravity as a side effect
4356 if (info->scale_center.is_fractional)
4357 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4361 case CLUTTER_X_AXIS:
4362 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4363 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4366 case CLUTTER_Y_AXIS:
4367 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4368 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4372 g_assert_not_reached ();
4375 self->priv->transform_valid = FALSE;
4377 clutter_actor_queue_redraw (self);
4379 g_object_thaw_notify (obj);
4383 clutter_actor_set_scale_gravity (ClutterActor *self,
4384 ClutterGravity gravity)
4386 ClutterTransformInfo *info;
4389 info = _clutter_actor_get_transform_info (self);
4390 obj = G_OBJECT (self);
4392 if (gravity == CLUTTER_GRAVITY_NONE)
4393 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4395 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4397 self->priv->transform_valid = FALSE;
4399 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4400 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4401 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4403 clutter_actor_queue_redraw (self);
4407 clutter_actor_set_anchor_coord (ClutterActor *self,
4408 ClutterRotateAxis axis,
4411 GObject *obj = G_OBJECT (self);
4412 ClutterTransformInfo *info;
4413 gfloat anchor_x, anchor_y;
4415 info = _clutter_actor_get_transform_info (self);
4417 g_object_freeze_notify (obj);
4419 clutter_anchor_coord_get_units (self, &info->anchor,
4424 if (info->anchor.is_fractional)
4425 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4429 case CLUTTER_X_AXIS:
4430 clutter_anchor_coord_set_units (&info->anchor,
4434 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4437 case CLUTTER_Y_AXIS:
4438 clutter_anchor_coord_set_units (&info->anchor,
4442 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4446 g_assert_not_reached ();
4449 self->priv->transform_valid = FALSE;
4451 clutter_actor_queue_redraw (self);
4453 g_object_thaw_notify (obj);
4457 clutter_actor_set_property (GObject *object,
4459 const GValue *value,
4462 ClutterActor *actor = CLUTTER_ACTOR (object);
4463 ClutterActorPrivate *priv = actor->priv;
4468 clutter_actor_set_x (actor, g_value_get_float (value));
4472 clutter_actor_set_y (actor, g_value_get_float (value));
4477 const ClutterPoint *pos = g_value_get_boxed (value);
4480 clutter_actor_set_position (actor, pos->x, pos->y);
4482 clutter_actor_set_fixed_position_set (actor, FALSE);
4487 clutter_actor_set_width (actor, g_value_get_float (value));
4491 clutter_actor_set_height (actor, g_value_get_float (value));
4496 const ClutterSize *size = g_value_get_boxed (value);
4499 clutter_actor_set_size (actor, size->width, size->height);
4501 clutter_actor_set_size (actor, -1, -1);
4506 clutter_actor_set_x (actor, g_value_get_float (value));
4510 clutter_actor_set_y (actor, g_value_get_float (value));
4513 case PROP_FIXED_POSITION_SET:
4514 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4517 case PROP_MIN_WIDTH:
4518 clutter_actor_set_min_width (actor, g_value_get_float (value));
4521 case PROP_MIN_HEIGHT:
4522 clutter_actor_set_min_height (actor, g_value_get_float (value));
4525 case PROP_NATURAL_WIDTH:
4526 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4529 case PROP_NATURAL_HEIGHT:
4530 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4533 case PROP_MIN_WIDTH_SET:
4534 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4537 case PROP_MIN_HEIGHT_SET:
4538 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4541 case PROP_NATURAL_WIDTH_SET:
4542 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4545 case PROP_NATURAL_HEIGHT_SET:
4546 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4549 case PROP_REQUEST_MODE:
4550 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4554 clutter_actor_set_depth (actor, g_value_get_float (value));
4558 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4561 case PROP_OFFSCREEN_REDIRECT:
4562 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4566 clutter_actor_set_name (actor, g_value_get_string (value));
4570 if (g_value_get_boolean (value) == TRUE)
4571 clutter_actor_show (actor);
4573 clutter_actor_hide (actor);
4577 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4578 g_value_get_double (value));
4582 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4583 g_value_get_double (value));
4586 case PROP_SCALE_CENTER_X:
4587 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4588 g_value_get_float (value));
4591 case PROP_SCALE_CENTER_Y:
4592 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4593 g_value_get_float (value));
4596 case PROP_SCALE_GRAVITY:
4597 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4602 const ClutterGeometry *geom = g_value_get_boxed (value);
4604 clutter_actor_set_clip (actor,
4606 geom->width, geom->height);
4610 case PROP_CLIP_TO_ALLOCATION:
4611 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4615 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4618 case PROP_ROTATION_ANGLE_X:
4619 clutter_actor_set_rotation_angle (actor,
4621 g_value_get_double (value));
4624 case PROP_ROTATION_ANGLE_Y:
4625 clutter_actor_set_rotation_angle (actor,
4627 g_value_get_double (value));
4630 case PROP_ROTATION_ANGLE_Z:
4631 clutter_actor_set_rotation_angle (actor,
4633 g_value_get_double (value));
4636 case PROP_ROTATION_CENTER_X:
4637 clutter_actor_set_rotation_center_internal (actor,
4639 g_value_get_boxed (value));
4642 case PROP_ROTATION_CENTER_Y:
4643 clutter_actor_set_rotation_center_internal (actor,
4645 g_value_get_boxed (value));
4648 case PROP_ROTATION_CENTER_Z:
4649 clutter_actor_set_rotation_center_internal (actor,
4651 g_value_get_boxed (value));
4654 case PROP_ROTATION_CENTER_Z_GRAVITY:
4656 const ClutterTransformInfo *info;
4658 info = _clutter_actor_get_transform_info_or_defaults (actor);
4659 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4660 g_value_get_enum (value));
4665 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4666 g_value_get_float (value));
4670 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4671 g_value_get_float (value));
4674 case PROP_ANCHOR_GRAVITY:
4675 clutter_actor_set_anchor_point_from_gravity (actor,
4676 g_value_get_enum (value));
4679 case PROP_SHOW_ON_SET_PARENT:
4680 priv->show_on_set_parent = g_value_get_boolean (value);
4683 case PROP_TEXT_DIRECTION:
4684 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4688 clutter_actor_add_action (actor, g_value_get_object (value));
4691 case PROP_CONSTRAINTS:
4692 clutter_actor_add_constraint (actor, g_value_get_object (value));
4696 clutter_actor_add_effect (actor, g_value_get_object (value));
4699 case PROP_LAYOUT_MANAGER:
4700 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4704 clutter_actor_set_x_expand (actor, g_value_get_boolean (value));
4708 clutter_actor_set_y_expand (actor, g_value_get_boolean (value));
4712 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4716 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4719 case PROP_MARGIN_TOP:
4720 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4723 case PROP_MARGIN_BOTTOM:
4724 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4727 case PROP_MARGIN_LEFT:
4728 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4731 case PROP_MARGIN_RIGHT:
4732 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4735 case PROP_BACKGROUND_COLOR:
4736 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4740 clutter_actor_set_content (actor, g_value_get_object (value));
4743 case PROP_CONTENT_GRAVITY:
4744 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4747 case PROP_MINIFICATION_FILTER:
4748 clutter_actor_set_content_scaling_filters (actor,
4749 g_value_get_enum (value),
4750 actor->priv->mag_filter);
4753 case PROP_MAGNIFICATION_FILTER:
4754 clutter_actor_set_content_scaling_filters (actor,
4755 actor->priv->min_filter,
4756 g_value_get_enum (value));
4759 case PROP_CONTENT_REPEAT:
4760 clutter_actor_set_content_repeat (actor, g_value_get_flags (value));
4764 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4770 clutter_actor_get_property (GObject *object,
4775 ClutterActor *actor = CLUTTER_ACTOR (object);
4776 ClutterActorPrivate *priv = actor->priv;
4781 g_value_set_float (value, clutter_actor_get_x (actor));
4785 g_value_set_float (value, clutter_actor_get_y (actor));
4790 ClutterPoint position;
4792 clutter_point_init (&position,
4793 clutter_actor_get_x (actor),
4794 clutter_actor_get_y (actor));
4795 g_value_set_boxed (value, &position);
4800 g_value_set_float (value, clutter_actor_get_width (actor));
4804 g_value_set_float (value, clutter_actor_get_height (actor));
4811 clutter_size_init (&size,
4812 clutter_actor_get_width (actor),
4813 clutter_actor_get_height (actor));
4814 g_value_set_boxed (value, &size);
4820 const ClutterLayoutInfo *info;
4822 info = _clutter_actor_get_layout_info_or_defaults (actor);
4823 g_value_set_float (value, info->fixed_pos.x);
4829 const ClutterLayoutInfo *info;
4831 info = _clutter_actor_get_layout_info_or_defaults (actor);
4832 g_value_set_float (value, info->fixed_pos.y);
4836 case PROP_FIXED_POSITION_SET:
4837 g_value_set_boolean (value, priv->position_set);
4840 case PROP_MIN_WIDTH:
4842 const ClutterLayoutInfo *info;
4844 info = _clutter_actor_get_layout_info_or_defaults (actor);
4845 g_value_set_float (value, info->minimum.width);
4849 case PROP_MIN_HEIGHT:
4851 const ClutterLayoutInfo *info;
4853 info = _clutter_actor_get_layout_info_or_defaults (actor);
4854 g_value_set_float (value, info->minimum.height);
4858 case PROP_NATURAL_WIDTH:
4860 const ClutterLayoutInfo *info;
4862 info = _clutter_actor_get_layout_info_or_defaults (actor);
4863 g_value_set_float (value, info->natural.width);
4867 case PROP_NATURAL_HEIGHT:
4869 const ClutterLayoutInfo *info;
4871 info = _clutter_actor_get_layout_info_or_defaults (actor);
4872 g_value_set_float (value, info->natural.height);
4876 case PROP_MIN_WIDTH_SET:
4877 g_value_set_boolean (value, priv->min_width_set);
4880 case PROP_MIN_HEIGHT_SET:
4881 g_value_set_boolean (value, priv->min_height_set);
4884 case PROP_NATURAL_WIDTH_SET:
4885 g_value_set_boolean (value, priv->natural_width_set);
4888 case PROP_NATURAL_HEIGHT_SET:
4889 g_value_set_boolean (value, priv->natural_height_set);
4892 case PROP_REQUEST_MODE:
4893 g_value_set_enum (value, priv->request_mode);
4896 case PROP_ALLOCATION:
4897 g_value_set_boxed (value, &priv->allocation);
4901 g_value_set_float (value, clutter_actor_get_depth (actor));
4905 g_value_set_uint (value, priv->opacity);
4908 case PROP_OFFSCREEN_REDIRECT:
4909 g_value_set_enum (value, priv->offscreen_redirect);
4913 g_value_set_string (value, priv->name);
4917 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4921 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4925 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4929 g_value_set_boolean (value, priv->has_clip);
4934 ClutterGeometry clip;
4936 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4937 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4938 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4939 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4941 g_value_set_boxed (value, &clip);
4945 case PROP_CLIP_TO_ALLOCATION:
4946 g_value_set_boolean (value, priv->clip_to_allocation);
4951 const ClutterTransformInfo *info;
4953 info = _clutter_actor_get_transform_info_or_defaults (actor);
4954 g_value_set_double (value, info->scale_x);
4960 const ClutterTransformInfo *info;
4962 info = _clutter_actor_get_transform_info_or_defaults (actor);
4963 g_value_set_double (value, info->scale_y);
4967 case PROP_SCALE_CENTER_X:
4971 clutter_actor_get_scale_center (actor, ¢er, NULL);
4973 g_value_set_float (value, center);
4977 case PROP_SCALE_CENTER_Y:
4981 clutter_actor_get_scale_center (actor, NULL, ¢er);
4983 g_value_set_float (value, center);
4987 case PROP_SCALE_GRAVITY:
4988 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4992 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4995 case PROP_ROTATION_ANGLE_X:
4997 const ClutterTransformInfo *info;
4999 info = _clutter_actor_get_transform_info_or_defaults (actor);
5000 g_value_set_double (value, info->rx_angle);
5004 case PROP_ROTATION_ANGLE_Y:
5006 const ClutterTransformInfo *info;
5008 info = _clutter_actor_get_transform_info_or_defaults (actor);
5009 g_value_set_double (value, info->ry_angle);
5013 case PROP_ROTATION_ANGLE_Z:
5015 const ClutterTransformInfo *info;
5017 info = _clutter_actor_get_transform_info_or_defaults (actor);
5018 g_value_set_double (value, info->rz_angle);
5022 case PROP_ROTATION_CENTER_X:
5024 ClutterVertex center;
5026 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
5031 g_value_set_boxed (value, ¢er);
5035 case PROP_ROTATION_CENTER_Y:
5037 ClutterVertex center;
5039 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
5044 g_value_set_boxed (value, ¢er);
5048 case PROP_ROTATION_CENTER_Z:
5050 ClutterVertex center;
5052 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
5057 g_value_set_boxed (value, ¢er);
5061 case PROP_ROTATION_CENTER_Z_GRAVITY:
5062 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
5067 const ClutterTransformInfo *info;
5070 info = _clutter_actor_get_transform_info_or_defaults (actor);
5071 clutter_anchor_coord_get_units (actor, &info->anchor,
5075 g_value_set_float (value, anchor_x);
5081 const ClutterTransformInfo *info;
5084 info = _clutter_actor_get_transform_info_or_defaults (actor);
5085 clutter_anchor_coord_get_units (actor, &info->anchor,
5089 g_value_set_float (value, anchor_y);
5093 case PROP_ANCHOR_GRAVITY:
5094 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
5097 case PROP_SHOW_ON_SET_PARENT:
5098 g_value_set_boolean (value, priv->show_on_set_parent);
5101 case PROP_TEXT_DIRECTION:
5102 g_value_set_enum (value, priv->text_direction);
5105 case PROP_HAS_POINTER:
5106 g_value_set_boolean (value, priv->has_pointer);
5109 case PROP_LAYOUT_MANAGER:
5110 g_value_set_object (value, priv->layout_manager);
5115 const ClutterLayoutInfo *info;
5117 info = _clutter_actor_get_layout_info_or_defaults (actor);
5118 g_value_set_boolean (value, info->x_expand);
5124 const ClutterLayoutInfo *info;
5126 info = _clutter_actor_get_layout_info_or_defaults (actor);
5127 g_value_set_boolean (value, info->y_expand);
5133 const ClutterLayoutInfo *info;
5135 info = _clutter_actor_get_layout_info_or_defaults (actor);
5136 g_value_set_enum (value, info->x_align);
5142 const ClutterLayoutInfo *info;
5144 info = _clutter_actor_get_layout_info_or_defaults (actor);
5145 g_value_set_enum (value, info->y_align);
5149 case PROP_MARGIN_TOP:
5151 const ClutterLayoutInfo *info;
5153 info = _clutter_actor_get_layout_info_or_defaults (actor);
5154 g_value_set_float (value, info->margin.top);
5158 case PROP_MARGIN_BOTTOM:
5160 const ClutterLayoutInfo *info;
5162 info = _clutter_actor_get_layout_info_or_defaults (actor);
5163 g_value_set_float (value, info->margin.bottom);
5167 case PROP_MARGIN_LEFT:
5169 const ClutterLayoutInfo *info;
5171 info = _clutter_actor_get_layout_info_or_defaults (actor);
5172 g_value_set_float (value, info->margin.left);
5176 case PROP_MARGIN_RIGHT:
5178 const ClutterLayoutInfo *info;
5180 info = _clutter_actor_get_layout_info_or_defaults (actor);
5181 g_value_set_float (value, info->margin.right);
5185 case PROP_BACKGROUND_COLOR_SET:
5186 g_value_set_boolean (value, priv->bg_color_set);
5189 case PROP_BACKGROUND_COLOR:
5190 g_value_set_boxed (value, &priv->bg_color);
5193 case PROP_FIRST_CHILD:
5194 g_value_set_object (value, priv->first_child);
5197 case PROP_LAST_CHILD:
5198 g_value_set_object (value, priv->last_child);
5202 g_value_set_object (value, priv->content);
5205 case PROP_CONTENT_GRAVITY:
5206 g_value_set_enum (value, priv->content_gravity);
5209 case PROP_CONTENT_BOX:
5211 ClutterActorBox box = { 0, };
5213 clutter_actor_get_content_box (actor, &box);
5214 g_value_set_boxed (value, &box);
5218 case PROP_MINIFICATION_FILTER:
5219 g_value_set_enum (value, priv->min_filter);
5222 case PROP_MAGNIFICATION_FILTER:
5223 g_value_set_enum (value, priv->mag_filter);
5226 case PROP_CONTENT_REPEAT:
5227 g_value_set_flags (value, priv->content_repeat);
5231 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5237 clutter_actor_dispose (GObject *object)
5239 ClutterActor *self = CLUTTER_ACTOR (object);
5240 ClutterActorPrivate *priv = self->priv;
5242 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5244 g_type_name (G_OBJECT_TYPE (self)),
5247 g_signal_emit (self, actor_signals[DESTROY], 0);
5249 /* avoid recursing when called from clutter_actor_destroy() */
5250 if (priv->parent != NULL)
5252 ClutterActor *parent = priv->parent;
5254 /* go through the Container implementation unless this
5255 * is an internal child and has been marked as such.
5257 * removing the actor from its parent will reset the
5258 * realized and mapped states.
5260 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5261 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5263 clutter_actor_remove_child_internal (parent, self,
5264 REMOVE_CHILD_LEGACY_FLAGS);
5267 /* parent must be gone at this point */
5268 g_assert (priv->parent == NULL);
5270 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5272 /* can't be mapped or realized with no parent */
5273 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5274 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5277 g_clear_object (&priv->pango_context);
5278 g_clear_object (&priv->actions);
5279 g_clear_object (&priv->constraints);
5280 g_clear_object (&priv->effects);
5281 g_clear_object (&priv->flatten_effect);
5283 if (priv->layout_manager != NULL)
5285 clutter_layout_manager_set_container (priv->layout_manager, NULL);
5286 g_clear_object (&priv->layout_manager);
5289 if (priv->content != NULL)
5291 _clutter_content_detached (priv->content, self);
5292 g_clear_object (&priv->content);
5295 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5299 clutter_actor_finalize (GObject *object)
5301 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5303 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5304 priv->name != NULL ? priv->name : "<none>",
5306 g_type_name (G_OBJECT_TYPE (object)));
5308 clutter_actor_restore_easing_state (CLUTTER_ACTOR (object));
5310 _clutter_context_release_id (priv->id);
5312 g_free (priv->name);
5314 #ifdef CLUTTER_ENABLE_DEBUG
5315 g_free (priv->debug_name);
5318 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5323 * clutter_actor_get_accessible:
5324 * @self: a #ClutterActor
5326 * Returns the accessible object that describes the actor to an
5327 * assistive technology.
5329 * If no class-specific #AtkObject implementation is available for the
5330 * actor instance in question, it will inherit an #AtkObject
5331 * implementation from the first ancestor class for which such an
5332 * implementation is defined.
5334 * The documentation of the <ulink
5335 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5336 * library contains more information about accessible objects and
5339 * Returns: (transfer none): the #AtkObject associated with @actor
5342 clutter_actor_get_accessible (ClutterActor *self)
5344 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5346 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5350 clutter_actor_real_get_accessible (ClutterActor *actor)
5352 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5356 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5358 AtkObject *accessible;
5360 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5361 if (accessible != NULL)
5362 g_object_ref (accessible);
5368 atk_implementor_iface_init (AtkImplementorIface *iface)
5370 iface->ref_accessible = _clutter_actor_ref_accessible;
5374 clutter_actor_update_default_paint_volume (ClutterActor *self,
5375 ClutterPaintVolume *volume)
5377 ClutterActorPrivate *priv = self->priv;
5378 gboolean res = TRUE;
5380 /* we start from the allocation */
5381 clutter_paint_volume_set_width (volume,
5382 priv->allocation.x2 - priv->allocation.x1);
5383 clutter_paint_volume_set_height (volume,
5384 priv->allocation.y2 - priv->allocation.y1);
5386 /* if the actor has a clip set then we have a pretty definite
5387 * size for the paint volume: the actor cannot possibly paint
5388 * outside the clip region.
5390 if (priv->clip_to_allocation)
5392 /* the allocation has already been set, so we just flip the
5399 ClutterActor *child;
5401 if (priv->has_clip &&
5402 priv->clip.width >= 0 &&
5403 priv->clip.height >= 0)
5405 ClutterVertex origin;
5407 origin.x = priv->clip.x;
5408 origin.y = priv->clip.y;
5411 clutter_paint_volume_set_origin (volume, &origin);
5412 clutter_paint_volume_set_width (volume, priv->clip.width);
5413 clutter_paint_volume_set_height (volume, priv->clip.height);
5418 /* if we don't have children we just bail out here... */
5419 if (priv->n_children == 0)
5422 /* ...but if we have children then we ask for their paint volume in
5423 * our coordinates. if any of our children replies that it doesn't
5424 * have a paint volume, we bail out
5426 for (child = priv->first_child;
5428 child = child->priv->next_sibling)
5430 const ClutterPaintVolume *child_volume;
5432 if (!CLUTTER_ACTOR_IS_MAPPED (child))
5435 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5436 if (child_volume == NULL)
5442 clutter_paint_volume_union (volume, child_volume);
5452 clutter_actor_real_get_paint_volume (ClutterActor *self,
5453 ClutterPaintVolume *volume)
5455 ClutterActorClass *klass;
5458 klass = CLUTTER_ACTOR_GET_CLASS (self);
5460 /* XXX - this thoroughly sucks, but we don't want to penalize users
5461 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5462 * redraw. This should go away in 2.0.
5464 if (klass->paint == clutter_actor_real_paint &&
5465 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5471 /* this is the default return value: we cannot know if a class
5472 * is going to paint outside its allocation, so we take the
5473 * conservative approach.
5478 /* update_default_paint_volume() should only fail if one of the children
5479 * reported an invalid, or no, paint volume
5481 if (!clutter_actor_update_default_paint_volume (self, volume))
5488 * clutter_actor_get_default_paint_volume:
5489 * @self: a #ClutterActor
5491 * Retrieves the default paint volume for @self.
5493 * This function provides the same #ClutterPaintVolume that would be
5494 * computed by the default implementation inside #ClutterActor of the
5495 * #ClutterActorClass.get_paint_volume() virtual function.
5497 * This function should only be used by #ClutterActor subclasses that
5498 * cannot chain up to the parent implementation when computing their
5501 * Return value: (transfer none): a pointer to the default
5502 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5503 * the actor could not compute a valid paint volume. The returned value
5504 * is not guaranteed to be stable across multiple frames, so if you
5505 * want to retain it, you will need to copy it using
5506 * clutter_paint_volume_copy().
5510 const ClutterPaintVolume *
5511 clutter_actor_get_default_paint_volume (ClutterActor *self)
5513 ClutterPaintVolume volume;
5514 ClutterPaintVolume *res;
5516 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5519 _clutter_paint_volume_init_static (&volume, self);
5520 if (clutter_actor_update_default_paint_volume (self, &volume))
5522 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5526 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5527 _clutter_paint_volume_copy_static (&volume, res);
5531 clutter_paint_volume_free (&volume);
5537 clutter_actor_real_has_overlaps (ClutterActor *self)
5539 /* By default we'll assume that all actors need an offscreen redirect to get
5540 * the correct opacity. Actors such as ClutterTexture that would never need
5541 * an offscreen redirect can override this to return FALSE. */
5546 clutter_actor_real_destroy (ClutterActor *actor)
5548 ClutterActorIter iter;
5550 g_object_freeze_notify (G_OBJECT (actor));
5552 clutter_actor_iter_init (&iter, actor);
5553 while (clutter_actor_iter_next (&iter, NULL))
5554 clutter_actor_iter_destroy (&iter);
5556 g_object_thaw_notify (G_OBJECT (actor));
5560 clutter_actor_constructor (GType gtype,
5562 GObjectConstructParam *props)
5564 GObjectClass *gobject_class;
5568 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5569 retval = gobject_class->constructor (gtype, n_props, props);
5570 self = CLUTTER_ACTOR (retval);
5572 if (self->priv->layout_manager == NULL)
5574 ClutterLayoutManager *default_layout;
5576 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5578 default_layout = clutter_fixed_layout_new ();
5579 clutter_actor_set_layout_manager (self, default_layout);
5586 clutter_actor_class_init (ClutterActorClass *klass)
5588 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5590 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5591 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5592 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5593 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5595 object_class->constructor = clutter_actor_constructor;
5596 object_class->set_property = clutter_actor_set_property;
5597 object_class->get_property = clutter_actor_get_property;
5598 object_class->dispose = clutter_actor_dispose;
5599 object_class->finalize = clutter_actor_finalize;
5601 klass->show = clutter_actor_real_show;
5602 klass->show_all = clutter_actor_show;
5603 klass->hide = clutter_actor_real_hide;
5604 klass->hide_all = clutter_actor_hide;
5605 klass->map = clutter_actor_real_map;
5606 klass->unmap = clutter_actor_real_unmap;
5607 klass->unrealize = clutter_actor_real_unrealize;
5608 klass->pick = clutter_actor_real_pick;
5609 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5610 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5611 klass->allocate = clutter_actor_real_allocate;
5612 klass->queue_redraw = clutter_actor_real_queue_redraw;
5613 klass->queue_relayout = clutter_actor_real_queue_relayout;
5614 klass->apply_transform = clutter_actor_real_apply_transform;
5615 klass->get_accessible = clutter_actor_real_get_accessible;
5616 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5617 klass->has_overlaps = clutter_actor_real_has_overlaps;
5618 klass->paint = clutter_actor_real_paint;
5619 klass->destroy = clutter_actor_real_destroy;
5621 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5626 * X coordinate of the actor in pixels. If written, forces a fixed
5627 * position for the actor. If read, returns the fixed position if any,
5628 * otherwise the allocation if available, otherwise 0.
5630 * The #ClutterActor:x property is animatable.
5633 g_param_spec_float ("x",
5635 P_("X coordinate of the actor"),
5636 -G_MAXFLOAT, G_MAXFLOAT,
5639 G_PARAM_STATIC_STRINGS |
5640 CLUTTER_PARAM_ANIMATABLE);
5645 * Y coordinate of the actor in pixels. If written, forces a fixed
5646 * position for the actor. If read, returns the fixed position if
5647 * any, otherwise the allocation if available, otherwise 0.
5649 * The #ClutterActor:y property is animatable.
5652 g_param_spec_float ("y",
5654 P_("Y coordinate of the actor"),
5655 -G_MAXFLOAT, G_MAXFLOAT,
5658 G_PARAM_STATIC_STRINGS |
5659 CLUTTER_PARAM_ANIMATABLE);
5662 * ClutterActor:position:
5664 * The position of the origin of the actor.
5666 * This property is a shorthand for setting and getting the
5667 * #ClutterActor:x and #ClutterActor:y properties at the same
5670 * The #ClutterActor:position property is animatable.
5674 obj_props[PROP_POSITION] =
5675 g_param_spec_boxed ("position",
5677 P_("The position of the origin of the actor"),
5680 G_PARAM_STATIC_STRINGS |
5681 CLUTTER_PARAM_ANIMATABLE);
5684 * ClutterActor:width:
5686 * Width of the actor (in pixels). If written, forces the minimum and
5687 * natural size request of the actor to the given width. If read, returns
5688 * the allocated width if available, otherwise the width request.
5690 * The #ClutterActor:width property is animatable.
5692 obj_props[PROP_WIDTH] =
5693 g_param_spec_float ("width",
5695 P_("Width of the actor"),
5699 G_PARAM_STATIC_STRINGS |
5700 CLUTTER_PARAM_ANIMATABLE);
5703 * ClutterActor:height:
5705 * Height of the actor (in pixels). If written, forces the minimum and
5706 * natural size request of the actor to the given height. If read, returns
5707 * the allocated height if available, otherwise the height request.
5709 * The #ClutterActor:height property is animatable.
5711 obj_props[PROP_HEIGHT] =
5712 g_param_spec_float ("height",
5714 P_("Height of the actor"),
5718 G_PARAM_STATIC_STRINGS |
5719 CLUTTER_PARAM_ANIMATABLE);
5722 * ClutterActor:size:
5724 * The size of the actor.
5726 * This property is a shorthand for setting and getting the
5727 * #ClutterActor:width and #ClutterActor:height at the same time.
5729 * The #ClutterActor:size property is animatable.
5733 obj_props[PROP_SIZE] =
5734 g_param_spec_boxed ("size",
5736 P_("The size of the actor"),
5739 G_PARAM_STATIC_STRINGS |
5740 CLUTTER_PARAM_ANIMATABLE);
5743 * ClutterActor:fixed-x:
5745 * The fixed X position of the actor in pixels.
5747 * Writing this property sets #ClutterActor:fixed-position-set
5748 * property as well, as a side effect
5752 obj_props[PROP_FIXED_X] =
5753 g_param_spec_float ("fixed-x",
5755 P_("Forced X position of the actor"),
5756 -G_MAXFLOAT, G_MAXFLOAT,
5758 CLUTTER_PARAM_READWRITE);
5761 * ClutterActor:fixed-y:
5763 * The fixed Y position of the actor in pixels.
5765 * Writing this property sets the #ClutterActor:fixed-position-set
5766 * property as well, as a side effect
5770 obj_props[PROP_FIXED_Y] =
5771 g_param_spec_float ("fixed-y",
5773 P_("Forced Y position of the actor"),
5774 -G_MAXFLOAT, G_MAXFLOAT,
5776 CLUTTER_PARAM_READWRITE);
5779 * ClutterActor:fixed-position-set:
5781 * This flag controls whether the #ClutterActor:fixed-x and
5782 * #ClutterActor:fixed-y properties are used
5786 obj_props[PROP_FIXED_POSITION_SET] =
5787 g_param_spec_boolean ("fixed-position-set",
5788 P_("Fixed position set"),
5789 P_("Whether to use fixed positioning for the actor"),
5791 CLUTTER_PARAM_READWRITE);
5794 * ClutterActor:min-width:
5796 * A forced minimum width request for the actor, in pixels
5798 * Writing this property sets the #ClutterActor:min-width-set property
5799 * as well, as a side effect.
5801 *This property overrides the usual width request of the actor.
5805 obj_props[PROP_MIN_WIDTH] =
5806 g_param_spec_float ("min-width",
5808 P_("Forced minimum width request for the actor"),
5811 CLUTTER_PARAM_READWRITE);
5814 * ClutterActor:min-height:
5816 * A forced minimum height request for the actor, in pixels
5818 * Writing this property sets the #ClutterActor:min-height-set property
5819 * as well, as a side effect. This property overrides the usual height
5820 * request of the actor.
5824 obj_props[PROP_MIN_HEIGHT] =
5825 g_param_spec_float ("min-height",
5827 P_("Forced minimum height request for the actor"),
5830 CLUTTER_PARAM_READWRITE);
5833 * ClutterActor:natural-width:
5835 * A forced natural width request for the actor, in pixels
5837 * Writing this property sets the #ClutterActor:natural-width-set
5838 * property as well, as a side effect. This property overrides the
5839 * usual width request of the actor
5843 obj_props[PROP_NATURAL_WIDTH] =
5844 g_param_spec_float ("natural-width",
5845 P_("Natural Width"),
5846 P_("Forced natural width request for the actor"),
5849 CLUTTER_PARAM_READWRITE);
5852 * ClutterActor:natural-height:
5854 * A forced natural height request for the actor, in pixels
5856 * Writing this property sets the #ClutterActor:natural-height-set
5857 * property as well, as a side effect. This property overrides the
5858 * usual height request of the actor
5862 obj_props[PROP_NATURAL_HEIGHT] =
5863 g_param_spec_float ("natural-height",
5864 P_("Natural Height"),
5865 P_("Forced natural height request for the actor"),
5868 CLUTTER_PARAM_READWRITE);
5871 * ClutterActor:min-width-set:
5873 * This flag controls whether the #ClutterActor:min-width property
5878 obj_props[PROP_MIN_WIDTH_SET] =
5879 g_param_spec_boolean ("min-width-set",
5880 P_("Minimum width set"),
5881 P_("Whether to use the min-width property"),
5883 CLUTTER_PARAM_READWRITE);
5886 * ClutterActor:min-height-set:
5888 * This flag controls whether the #ClutterActor:min-height property
5893 obj_props[PROP_MIN_HEIGHT_SET] =
5894 g_param_spec_boolean ("min-height-set",
5895 P_("Minimum height set"),
5896 P_("Whether to use the min-height property"),
5898 CLUTTER_PARAM_READWRITE);
5901 * ClutterActor:natural-width-set:
5903 * This flag controls whether the #ClutterActor:natural-width property
5908 obj_props[PROP_NATURAL_WIDTH_SET] =
5909 g_param_spec_boolean ("natural-width-set",
5910 P_("Natural width set"),
5911 P_("Whether to use the natural-width property"),
5913 CLUTTER_PARAM_READWRITE);
5916 * ClutterActor:natural-height-set:
5918 * This flag controls whether the #ClutterActor:natural-height property
5923 obj_props[PROP_NATURAL_HEIGHT_SET] =
5924 g_param_spec_boolean ("natural-height-set",
5925 P_("Natural height set"),
5926 P_("Whether to use the natural-height property"),
5928 CLUTTER_PARAM_READWRITE);
5931 * ClutterActor:allocation:
5933 * The allocation for the actor, in pixels
5935 * This is property is read-only, but you might monitor it to know when an
5936 * actor moves or resizes
5940 obj_props[PROP_ALLOCATION] =
5941 g_param_spec_boxed ("allocation",
5943 P_("The actor's allocation"),
5944 CLUTTER_TYPE_ACTOR_BOX,
5946 G_PARAM_STATIC_STRINGS |
5947 CLUTTER_PARAM_ANIMATABLE);
5950 * ClutterActor:request-mode:
5952 * Request mode for the #ClutterActor. The request mode determines the
5953 * type of geometry management used by the actor, either height for width
5954 * (the default) or width for height.
5956 * For actors implementing height for width, the parent container should get
5957 * the preferred width first, and then the preferred height for that width.
5959 * For actors implementing width for height, the parent container should get
5960 * the preferred height first, and then the preferred width for that height.
5965 * ClutterRequestMode mode;
5966 * gfloat natural_width, min_width;
5967 * gfloat natural_height, min_height;
5969 * mode = clutter_actor_get_request_mode (child);
5970 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5972 * clutter_actor_get_preferred_width (child, -1,
5974 * &natural_width);
5975 * clutter_actor_get_preferred_height (child, natural_width,
5977 * &natural_height);
5981 * clutter_actor_get_preferred_height (child, -1,
5983 * &natural_height);
5984 * clutter_actor_get_preferred_width (child, natural_height,
5986 * &natural_width);
5990 * will retrieve the minimum and natural width and height depending on the
5991 * preferred request mode of the #ClutterActor "child".
5993 * The clutter_actor_get_preferred_size() function will implement this
5998 obj_props[PROP_REQUEST_MODE] =
5999 g_param_spec_enum ("request-mode",
6001 P_("The actor's request mode"),
6002 CLUTTER_TYPE_REQUEST_MODE,
6003 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
6004 CLUTTER_PARAM_READWRITE);
6007 * ClutterActor:depth:
6009 * The position of the actor on the Z axis.
6011 * The #ClutterActor:depth property is relative to the parent's
6014 * The #ClutterActor:depth property is animatable.
6018 obj_props[PROP_DEPTH] =
6019 g_param_spec_float ("depth",
6021 P_("Position on the Z axis"),
6022 -G_MAXFLOAT, G_MAXFLOAT,
6025 G_PARAM_STATIC_STRINGS |
6026 CLUTTER_PARAM_ANIMATABLE);
6029 * ClutterActor:opacity:
6031 * Opacity of an actor, between 0 (fully transparent) and
6032 * 255 (fully opaque)
6034 * The #ClutterActor:opacity property is animatable.
6036 obj_props[PROP_OPACITY] =
6037 g_param_spec_uint ("opacity",
6039 P_("Opacity of an actor"),
6043 G_PARAM_STATIC_STRINGS |
6044 CLUTTER_PARAM_ANIMATABLE);
6047 * ClutterActor:offscreen-redirect:
6049 * Determines the conditions in which the actor will be redirected
6050 * to an offscreen framebuffer while being painted. For example this
6051 * can be used to cache an actor in a framebuffer or for improved
6052 * handling of transparent actors. See
6053 * clutter_actor_set_offscreen_redirect() for details.
6057 obj_props[PROP_OFFSCREEN_REDIRECT] =
6058 g_param_spec_flags ("offscreen-redirect",
6059 P_("Offscreen redirect"),
6060 P_("Flags controlling when to flatten the actor into a single image"),
6061 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
6063 CLUTTER_PARAM_READWRITE);
6066 * ClutterActor:visible:
6068 * Whether the actor is set to be visible or not
6070 * See also #ClutterActor:mapped
6072 obj_props[PROP_VISIBLE] =
6073 g_param_spec_boolean ("visible",
6075 P_("Whether the actor is visible or not"),
6077 CLUTTER_PARAM_READWRITE);
6080 * ClutterActor:mapped:
6082 * Whether the actor is mapped (will be painted when the stage
6083 * to which it belongs is mapped)
6087 obj_props[PROP_MAPPED] =
6088 g_param_spec_boolean ("mapped",
6090 P_("Whether the actor will be painted"),
6092 CLUTTER_PARAM_READABLE);
6095 * ClutterActor:realized:
6097 * Whether the actor has been realized
6101 obj_props[PROP_REALIZED] =
6102 g_param_spec_boolean ("realized",
6104 P_("Whether the actor has been realized"),
6106 CLUTTER_PARAM_READABLE);
6109 * ClutterActor:reactive:
6111 * Whether the actor is reactive to events or not
6113 * Only reactive actors will emit event-related signals
6117 obj_props[PROP_REACTIVE] =
6118 g_param_spec_boolean ("reactive",
6120 P_("Whether the actor is reactive to events"),
6122 CLUTTER_PARAM_READWRITE);
6125 * ClutterActor:has-clip:
6127 * Whether the actor has the #ClutterActor:clip property set or not
6129 obj_props[PROP_HAS_CLIP] =
6130 g_param_spec_boolean ("has-clip",
6132 P_("Whether the actor has a clip set"),
6134 CLUTTER_PARAM_READABLE);
6137 * ClutterActor:clip:
6139 * The clip region for the actor, in actor-relative coordinates
6141 * Every part of the actor outside the clip region will not be
6144 obj_props[PROP_CLIP] =
6145 g_param_spec_boxed ("clip",
6147 P_("The clip region for the actor"),
6148 CLUTTER_TYPE_GEOMETRY,
6149 CLUTTER_PARAM_READWRITE);
6152 * ClutterActor:name:
6154 * The name of the actor
6158 obj_props[PROP_NAME] =
6159 g_param_spec_string ("name",
6161 P_("Name of the actor"),
6163 CLUTTER_PARAM_READWRITE);
6166 * ClutterActor:scale-x:
6168 * The horizontal scale of the actor.
6170 * The #ClutterActor:scale-x property is animatable.
6174 obj_props[PROP_SCALE_X] =
6175 g_param_spec_double ("scale-x",
6177 P_("Scale factor on the X axis"),
6181 G_PARAM_STATIC_STRINGS |
6182 CLUTTER_PARAM_ANIMATABLE);
6185 * ClutterActor:scale-y:
6187 * The vertical scale of the actor.
6189 * The #ClutterActor:scale-y property is animatable.
6193 obj_props[PROP_SCALE_Y] =
6194 g_param_spec_double ("scale-y",
6196 P_("Scale factor on the Y axis"),
6200 G_PARAM_STATIC_STRINGS |
6201 CLUTTER_PARAM_ANIMATABLE);
6204 * ClutterActor:scale-center-x:
6206 * The horizontal center point for scaling
6210 obj_props[PROP_SCALE_CENTER_X] =
6211 g_param_spec_float ("scale-center-x",
6212 P_("Scale Center X"),
6213 P_("Horizontal scale center"),
6214 -G_MAXFLOAT, G_MAXFLOAT,
6216 CLUTTER_PARAM_READWRITE);
6219 * ClutterActor:scale-center-y:
6221 * The vertical center point for scaling
6225 obj_props[PROP_SCALE_CENTER_Y] =
6226 g_param_spec_float ("scale-center-y",
6227 P_("Scale Center Y"),
6228 P_("Vertical scale center"),
6229 -G_MAXFLOAT, G_MAXFLOAT,
6231 CLUTTER_PARAM_READWRITE);
6234 * ClutterActor:scale-gravity:
6236 * The center point for scaling expressed as a #ClutterGravity
6240 obj_props[PROP_SCALE_GRAVITY] =
6241 g_param_spec_enum ("scale-gravity",
6242 P_("Scale Gravity"),
6243 P_("The center of scaling"),
6244 CLUTTER_TYPE_GRAVITY,
6245 CLUTTER_GRAVITY_NONE,
6246 CLUTTER_PARAM_READWRITE);
6249 * ClutterActor:rotation-angle-x:
6251 * The rotation angle on the X axis.
6253 * The #ClutterActor:rotation-angle-x property is animatable.
6257 obj_props[PROP_ROTATION_ANGLE_X] =
6258 g_param_spec_double ("rotation-angle-x",
6259 P_("Rotation Angle X"),
6260 P_("The rotation angle on the X axis"),
6261 -G_MAXDOUBLE, G_MAXDOUBLE,
6264 G_PARAM_STATIC_STRINGS |
6265 CLUTTER_PARAM_ANIMATABLE);
6268 * ClutterActor:rotation-angle-y:
6270 * The rotation angle on the Y axis
6272 * The #ClutterActor:rotation-angle-y property is animatable.
6276 obj_props[PROP_ROTATION_ANGLE_Y] =
6277 g_param_spec_double ("rotation-angle-y",
6278 P_("Rotation Angle Y"),
6279 P_("The rotation angle on the Y axis"),
6280 -G_MAXDOUBLE, G_MAXDOUBLE,
6283 G_PARAM_STATIC_STRINGS |
6284 CLUTTER_PARAM_ANIMATABLE);
6287 * ClutterActor:rotation-angle-z:
6289 * The rotation angle on the Z axis
6291 * The #ClutterActor:rotation-angle-z property is animatable.
6295 obj_props[PROP_ROTATION_ANGLE_Z] =
6296 g_param_spec_double ("rotation-angle-z",
6297 P_("Rotation Angle Z"),
6298 P_("The rotation angle on the Z axis"),
6299 -G_MAXDOUBLE, G_MAXDOUBLE,
6302 G_PARAM_STATIC_STRINGS |
6303 CLUTTER_PARAM_ANIMATABLE);
6306 * ClutterActor:rotation-center-x:
6308 * The rotation center on the X axis.
6312 obj_props[PROP_ROTATION_CENTER_X] =
6313 g_param_spec_boxed ("rotation-center-x",
6314 P_("Rotation Center X"),
6315 P_("The rotation center on the X axis"),
6316 CLUTTER_TYPE_VERTEX,
6317 CLUTTER_PARAM_READWRITE);
6320 * ClutterActor:rotation-center-y:
6322 * The rotation center on the Y axis.
6326 obj_props[PROP_ROTATION_CENTER_Y] =
6327 g_param_spec_boxed ("rotation-center-y",
6328 P_("Rotation Center Y"),
6329 P_("The rotation center on the Y axis"),
6330 CLUTTER_TYPE_VERTEX,
6331 CLUTTER_PARAM_READWRITE);
6334 * ClutterActor:rotation-center-z:
6336 * The rotation center on the Z axis.
6340 obj_props[PROP_ROTATION_CENTER_Z] =
6341 g_param_spec_boxed ("rotation-center-z",
6342 P_("Rotation Center Z"),
6343 P_("The rotation center on the Z axis"),
6344 CLUTTER_TYPE_VERTEX,
6345 CLUTTER_PARAM_READWRITE);
6348 * ClutterActor:rotation-center-z-gravity:
6350 * The rotation center on the Z axis expressed as a #ClutterGravity.
6354 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6355 g_param_spec_enum ("rotation-center-z-gravity",
6356 P_("Rotation Center Z Gravity"),
6357 P_("Center point for rotation around the Z axis"),
6358 CLUTTER_TYPE_GRAVITY,
6359 CLUTTER_GRAVITY_NONE,
6360 CLUTTER_PARAM_READWRITE);
6363 * ClutterActor:anchor-x:
6365 * The X coordinate of an actor's anchor point, relative to
6366 * the actor coordinate space, in pixels
6370 obj_props[PROP_ANCHOR_X] =
6371 g_param_spec_float ("anchor-x",
6373 P_("X coordinate of the anchor point"),
6374 -G_MAXFLOAT, G_MAXFLOAT,
6376 CLUTTER_PARAM_READWRITE);
6379 * ClutterActor:anchor-y:
6381 * The Y coordinate of an actor's anchor point, relative to
6382 * the actor coordinate space, in pixels
6386 obj_props[PROP_ANCHOR_Y] =
6387 g_param_spec_float ("anchor-y",
6389 P_("Y coordinate of the anchor point"),
6390 -G_MAXFLOAT, G_MAXFLOAT,
6392 CLUTTER_PARAM_READWRITE);
6395 * ClutterActor:anchor-gravity:
6397 * The anchor point expressed as a #ClutterGravity
6401 obj_props[PROP_ANCHOR_GRAVITY] =
6402 g_param_spec_enum ("anchor-gravity",
6403 P_("Anchor Gravity"),
6404 P_("The anchor point as a ClutterGravity"),
6405 CLUTTER_TYPE_GRAVITY,
6406 CLUTTER_GRAVITY_NONE,
6407 CLUTTER_PARAM_READWRITE);
6410 * ClutterActor:show-on-set-parent:
6412 * If %TRUE, the actor is automatically shown when parented.
6414 * Calling clutter_actor_hide() on an actor which has not been
6415 * parented will set this property to %FALSE as a side effect.
6419 obj_props[PROP_SHOW_ON_SET_PARENT] =
6420 g_param_spec_boolean ("show-on-set-parent",
6421 P_("Show on set parent"),
6422 P_("Whether the actor is shown when parented"),
6424 CLUTTER_PARAM_READWRITE);
6427 * ClutterActor:clip-to-allocation:
6429 * Whether the clip region should track the allocated area
6432 * This property is ignored if a clip area has been explicitly
6433 * set using clutter_actor_set_clip().
6437 obj_props[PROP_CLIP_TO_ALLOCATION] =
6438 g_param_spec_boolean ("clip-to-allocation",
6439 P_("Clip to Allocation"),
6440 P_("Sets the clip region to track the actor's allocation"),
6442 CLUTTER_PARAM_READWRITE);
6445 * ClutterActor:text-direction:
6447 * The direction of the text inside a #ClutterActor.
6451 obj_props[PROP_TEXT_DIRECTION] =
6452 g_param_spec_enum ("text-direction",
6453 P_("Text Direction"),
6454 P_("Direction of the text"),
6455 CLUTTER_TYPE_TEXT_DIRECTION,
6456 CLUTTER_TEXT_DIRECTION_LTR,
6457 CLUTTER_PARAM_READWRITE);
6460 * ClutterActor:has-pointer:
6462 * Whether the actor contains the pointer of a #ClutterInputDevice
6467 obj_props[PROP_HAS_POINTER] =
6468 g_param_spec_boolean ("has-pointer",
6470 P_("Whether the actor contains the pointer of an input device"),
6472 CLUTTER_PARAM_READABLE);
6475 * ClutterActor:actions:
6477 * Adds a #ClutterAction to the actor
6481 obj_props[PROP_ACTIONS] =
6482 g_param_spec_object ("actions",
6484 P_("Adds an action to the actor"),
6485 CLUTTER_TYPE_ACTION,
6486 CLUTTER_PARAM_WRITABLE);
6489 * ClutterActor:constraints:
6491 * Adds a #ClutterConstraint to the actor
6495 obj_props[PROP_CONSTRAINTS] =
6496 g_param_spec_object ("constraints",
6498 P_("Adds a constraint to the actor"),
6499 CLUTTER_TYPE_CONSTRAINT,
6500 CLUTTER_PARAM_WRITABLE);
6503 * ClutterActor:effect:
6505 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6509 obj_props[PROP_EFFECT] =
6510 g_param_spec_object ("effect",
6512 P_("Add an effect to be applied on the actor"),
6513 CLUTTER_TYPE_EFFECT,
6514 CLUTTER_PARAM_WRITABLE);
6517 * ClutterActor:layout-manager:
6519 * A delegate object for controlling the layout of the children of
6524 obj_props[PROP_LAYOUT_MANAGER] =
6525 g_param_spec_object ("layout-manager",
6526 P_("Layout Manager"),
6527 P_("The object controlling the layout of an actor's children"),
6528 CLUTTER_TYPE_LAYOUT_MANAGER,
6529 CLUTTER_PARAM_READWRITE);
6532 * ClutterActor:x-expand:
6534 * Whether a layout manager should assign more space to the actor on
6539 obj_props[PROP_X_EXPAND] =
6540 g_param_spec_boolean ("x-expand",
6542 P_("Whether extra horizontal space should be assigned to the actor"),
6545 G_PARAM_STATIC_STRINGS);
6548 * ClutterActor:y-expand:
6550 * Whether a layout manager should assign more space to the actor on
6555 obj_props[PROP_Y_EXPAND] =
6556 g_param_spec_boolean ("y-expand",
6558 P_("Whether extra vertical space should be assigned to the actor"),
6561 G_PARAM_STATIC_STRINGS);
6564 * ClutterActor:x-align:
6566 * The alignment of an actor on the X axis, if the actor has been given
6567 * extra space for its allocation. See also the #ClutterActor:x-expand
6572 obj_props[PROP_X_ALIGN] =
6573 g_param_spec_enum ("x-align",
6575 P_("The alignment of the actor on the X axis within its allocation"),
6576 CLUTTER_TYPE_ACTOR_ALIGN,
6577 CLUTTER_ACTOR_ALIGN_FILL,
6578 CLUTTER_PARAM_READWRITE);
6581 * ClutterActor:y-align:
6583 * The alignment of an actor on the Y axis, if the actor has been given
6584 * extra space for its allocation.
6588 obj_props[PROP_Y_ALIGN] =
6589 g_param_spec_enum ("y-align",
6591 P_("The alignment of the actor on the Y axis within its allocation"),
6592 CLUTTER_TYPE_ACTOR_ALIGN,
6593 CLUTTER_ACTOR_ALIGN_FILL,
6594 CLUTTER_PARAM_READWRITE);
6597 * ClutterActor:margin-top:
6599 * The margin (in pixels) from the top of the actor.
6601 * This property adds a margin to the actor's preferred size; the margin
6602 * will be automatically taken into account when allocating the actor.
6606 obj_props[PROP_MARGIN_TOP] =
6607 g_param_spec_float ("margin-top",
6609 P_("Extra space at the top"),
6612 CLUTTER_PARAM_READWRITE);
6615 * ClutterActor:margin-bottom:
6617 * The margin (in pixels) from the bottom of the actor.
6619 * This property adds a margin to the actor's preferred size; the margin
6620 * will be automatically taken into account when allocating the actor.
6624 obj_props[PROP_MARGIN_BOTTOM] =
6625 g_param_spec_float ("margin-bottom",
6626 P_("Margin Bottom"),
6627 P_("Extra space at the bottom"),
6630 CLUTTER_PARAM_READWRITE);
6633 * ClutterActor:margin-left:
6635 * The margin (in pixels) from the left of the actor.
6637 * This property adds a margin to the actor's preferred size; the margin
6638 * will be automatically taken into account when allocating the actor.
6642 obj_props[PROP_MARGIN_LEFT] =
6643 g_param_spec_float ("margin-left",
6645 P_("Extra space at the left"),
6648 CLUTTER_PARAM_READWRITE);
6651 * ClutterActor:margin-right:
6653 * The margin (in pixels) from the right of the actor.
6655 * This property adds a margin to the actor's preferred size; the margin
6656 * will be automatically taken into account when allocating the actor.
6660 obj_props[PROP_MARGIN_RIGHT] =
6661 g_param_spec_float ("margin-right",
6663 P_("Extra space at the right"),
6666 CLUTTER_PARAM_READWRITE);
6669 * ClutterActor:background-color-set:
6671 * Whether the #ClutterActor:background-color property has been set.
6675 obj_props[PROP_BACKGROUND_COLOR_SET] =
6676 g_param_spec_boolean ("background-color-set",
6677 P_("Background Color Set"),
6678 P_("Whether the background color is set"),
6680 CLUTTER_PARAM_READABLE);
6683 * ClutterActor:background-color:
6685 * Paints a solid fill of the actor's allocation using the specified
6688 * The #ClutterActor:background-color property is animatable.
6692 obj_props[PROP_BACKGROUND_COLOR] =
6693 clutter_param_spec_color ("background-color",
6694 P_("Background color"),
6695 P_("The actor's background color"),
6696 CLUTTER_COLOR_Transparent,
6698 G_PARAM_STATIC_STRINGS |
6699 CLUTTER_PARAM_ANIMATABLE);
6702 * ClutterActor:first-child:
6704 * The actor's first child.
6708 obj_props[PROP_FIRST_CHILD] =
6709 g_param_spec_object ("first-child",
6711 P_("The actor's first child"),
6713 CLUTTER_PARAM_READABLE);
6716 * ClutterActor:last-child:
6718 * The actor's last child.
6722 obj_props[PROP_LAST_CHILD] =
6723 g_param_spec_object ("last-child",
6725 P_("The actor's last child"),
6727 CLUTTER_PARAM_READABLE);
6730 * ClutterActor:content:
6732 * The #ClutterContent implementation that controls the content
6737 obj_props[PROP_CONTENT] =
6738 g_param_spec_object ("content",
6740 P_("Delegate object for painting the actor's content"),
6741 CLUTTER_TYPE_CONTENT,
6742 CLUTTER_PARAM_READWRITE);
6745 * ClutterActor:content-gravity:
6747 * The alignment that should be honoured by the #ClutterContent
6748 * set with the #ClutterActor:content property.
6750 * Changing the value of this property will change the bounding box of
6751 * the content; you can use the #ClutterActor:content-box property to
6752 * get the position and size of the content within the actor's
6755 * This property is meaningful only for #ClutterContent implementations
6756 * that have a preferred size, and if the preferred size is smaller than
6757 * the actor's allocation.
6759 * The #ClutterActor:content-gravity property is animatable.
6763 obj_props[PROP_CONTENT_GRAVITY] =
6764 g_param_spec_enum ("content-gravity",
6765 P_("Content Gravity"),
6766 P_("Alignment of the actor's content"),
6767 CLUTTER_TYPE_CONTENT_GRAVITY,
6768 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6769 CLUTTER_PARAM_READWRITE);
6772 * ClutterActor:content-box:
6774 * The bounding box for the #ClutterContent used by the actor.
6776 * The value of this property is controlled by the #ClutterActor:allocation
6777 * and #ClutterActor:content-gravity properties of #ClutterActor.
6779 * The bounding box for the content is guaranteed to never exceed the
6780 * allocation's of the actor.
6784 obj_props[PROP_CONTENT_BOX] =
6785 g_param_spec_boxed ("content-box",
6787 P_("The bounding box of the actor's content"),
6788 CLUTTER_TYPE_ACTOR_BOX,
6790 G_PARAM_STATIC_STRINGS |
6791 CLUTTER_PARAM_ANIMATABLE);
6793 obj_props[PROP_MINIFICATION_FILTER] =
6794 g_param_spec_enum ("minification-filter",
6795 P_("Minification Filter"),
6796 P_("The filter used when reducing the size of the content"),
6797 CLUTTER_TYPE_SCALING_FILTER,
6798 CLUTTER_SCALING_FILTER_LINEAR,
6799 CLUTTER_PARAM_READWRITE);
6801 obj_props[PROP_MAGNIFICATION_FILTER] =
6802 g_param_spec_enum ("magnification-filter",
6803 P_("Magnification Filter"),
6804 P_("The filter used when increasing the size of the content"),
6805 CLUTTER_TYPE_SCALING_FILTER,
6806 CLUTTER_SCALING_FILTER_LINEAR,
6807 CLUTTER_PARAM_READWRITE);
6810 * ClutterActor:content-repeat:
6812 * The repeat policy for the actor's #ClutterActor:content.
6816 obj_props[PROP_CONTENT_REPEAT] =
6817 g_param_spec_flags ("content-repeat",
6818 P_("Content Repeat"),
6819 P_("The repeat policy for the actor's content"),
6820 CLUTTER_TYPE_CONTENT_REPEAT,
6821 CLUTTER_REPEAT_NONE,
6823 G_PARAM_STATIC_STRINGS);
6825 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6828 * ClutterActor::destroy:
6829 * @actor: the #ClutterActor which emitted the signal
6831 * The ::destroy signal notifies that all references held on the
6832 * actor which emitted it should be released.
6834 * The ::destroy signal should be used by all holders of a reference
6837 * This signal might result in the finalization of the #ClutterActor
6838 * if all references are released.
6840 * Composite actors and actors implementing the #ClutterContainer
6841 * interface should override the default implementation of the
6842 * class handler of this signal and call clutter_actor_destroy() on
6843 * their children. When overriding the default class handler, it is
6844 * required to chain up to the parent's implementation.
6848 actor_signals[DESTROY] =
6849 g_signal_new (I_("destroy"),
6850 G_TYPE_FROM_CLASS (object_class),
6851 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6852 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6854 _clutter_marshal_VOID__VOID,
6857 * ClutterActor::show:
6858 * @actor: the object which received the signal
6860 * The ::show signal is emitted when an actor is visible and
6861 * rendered on the stage.
6865 actor_signals[SHOW] =
6866 g_signal_new (I_("show"),
6867 G_TYPE_FROM_CLASS (object_class),
6869 G_STRUCT_OFFSET (ClutterActorClass, show),
6871 _clutter_marshal_VOID__VOID,
6874 * ClutterActor::hide:
6875 * @actor: the object which received the signal
6877 * The ::hide signal is emitted when an actor is no longer rendered
6882 actor_signals[HIDE] =
6883 g_signal_new (I_("hide"),
6884 G_TYPE_FROM_CLASS (object_class),
6886 G_STRUCT_OFFSET (ClutterActorClass, hide),
6888 _clutter_marshal_VOID__VOID,
6891 * ClutterActor::parent-set:
6892 * @actor: the object which received the signal
6893 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6895 * This signal is emitted when the parent of the actor changes.
6899 actor_signals[PARENT_SET] =
6900 g_signal_new (I_("parent-set"),
6901 G_TYPE_FROM_CLASS (object_class),
6903 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6905 _clutter_marshal_VOID__OBJECT,
6907 CLUTTER_TYPE_ACTOR);
6910 * ClutterActor::queue-redraw:
6911 * @actor: the actor we're bubbling the redraw request through
6912 * @origin: the actor which initiated the redraw request
6914 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6915 * is called on @origin.
6917 * The default implementation for #ClutterActor chains up to the
6918 * parent actor and queues a redraw on the parent, thus "bubbling"
6919 * the redraw queue up through the actor graph. The default
6920 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6921 * in a main loop idle handler.
6923 * Note that the @origin actor may be the stage, or a container; it
6924 * does not have to be a leaf node in the actor graph.
6926 * Toolkits embedding a #ClutterStage which require a redraw and
6927 * relayout cycle can stop the emission of this signal using the
6928 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6933 * on_redraw_complete (gpointer data)
6935 * ClutterStage *stage = data;
6937 * /* execute the Clutter drawing pipeline */
6938 * clutter_stage_ensure_redraw (stage);
6942 * on_stage_queue_redraw (ClutterStage *stage)
6944 * /* this prevents the default handler to run */
6945 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6947 * /* queue a redraw with the host toolkit and call
6948 * * a function when the redraw has been completed
6950 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6954 * <note><para>This signal is emitted before the Clutter paint
6955 * pipeline is executed. If you want to know when the pipeline has
6956 * been completed you should connect to the ::paint signal on the
6957 * Stage with g_signal_connect_after().</para></note>
6961 actor_signals[QUEUE_REDRAW] =
6962 g_signal_new (I_("queue-redraw"),
6963 G_TYPE_FROM_CLASS (object_class),
6966 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6968 _clutter_marshal_VOID__OBJECT,
6970 CLUTTER_TYPE_ACTOR);
6973 * ClutterActor::queue-relayout:
6974 * @actor: the actor being queued for relayout
6976 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6977 * is called on an actor.
6979 * The default implementation for #ClutterActor chains up to the
6980 * parent actor and queues a relayout on the parent, thus "bubbling"
6981 * the relayout queue up through the actor graph.
6983 * The main purpose of this signal is to allow relayout to be propagated
6984 * properly in the procense of #ClutterClone actors. Applications will
6985 * not normally need to connect to this signal.
6989 actor_signals[QUEUE_RELAYOUT] =
6990 g_signal_new (I_("queue-relayout"),
6991 G_TYPE_FROM_CLASS (object_class),
6994 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6996 _clutter_marshal_VOID__VOID,
7000 * ClutterActor::event:
7001 * @actor: the actor which received the event
7002 * @event: a #ClutterEvent
7004 * The ::event signal is emitted each time an event is received
7005 * by the @actor. This signal will be emitted on every actor,
7006 * following the hierarchy chain, until it reaches the top-level
7007 * container (the #ClutterStage).
7009 * Return value: %TRUE if the event has been handled by the actor,
7010 * or %FALSE to continue the emission.
7014 actor_signals[EVENT] =
7015 g_signal_new (I_("event"),
7016 G_TYPE_FROM_CLASS (object_class),
7018 G_STRUCT_OFFSET (ClutterActorClass, event),
7019 _clutter_boolean_handled_accumulator, NULL,
7020 _clutter_marshal_BOOLEAN__BOXED,
7022 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7024 * ClutterActor::button-press-event:
7025 * @actor: the actor which received the event
7026 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
7028 * The ::button-press-event signal is emitted each time a mouse button
7029 * is pressed on @actor.
7031 * Return value: %TRUE if the event has been handled by the actor,
7032 * or %FALSE to continue the emission.
7036 actor_signals[BUTTON_PRESS_EVENT] =
7037 g_signal_new (I_("button-press-event"),
7038 G_TYPE_FROM_CLASS (object_class),
7040 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
7041 _clutter_boolean_handled_accumulator, NULL,
7042 _clutter_marshal_BOOLEAN__BOXED,
7044 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7046 * ClutterActor::button-release-event:
7047 * @actor: the actor which received the event
7048 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
7050 * The ::button-release-event signal is emitted each time a mouse button
7051 * is released on @actor.
7053 * Return value: %TRUE if the event has been handled by the actor,
7054 * or %FALSE to continue the emission.
7058 actor_signals[BUTTON_RELEASE_EVENT] =
7059 g_signal_new (I_("button-release-event"),
7060 G_TYPE_FROM_CLASS (object_class),
7062 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
7063 _clutter_boolean_handled_accumulator, NULL,
7064 _clutter_marshal_BOOLEAN__BOXED,
7066 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7068 * ClutterActor::scroll-event:
7069 * @actor: the actor which received the event
7070 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
7072 * The ::scroll-event signal is emitted each time the mouse is
7073 * scrolled on @actor
7075 * Return value: %TRUE if the event has been handled by the actor,
7076 * or %FALSE to continue the emission.
7080 actor_signals[SCROLL_EVENT] =
7081 g_signal_new (I_("scroll-event"),
7082 G_TYPE_FROM_CLASS (object_class),
7084 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
7085 _clutter_boolean_handled_accumulator, NULL,
7086 _clutter_marshal_BOOLEAN__BOXED,
7088 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7090 * ClutterActor::key-press-event:
7091 * @actor: the actor which received the event
7092 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7094 * The ::key-press-event signal is emitted each time a keyboard button
7095 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
7097 * Return value: %TRUE if the event has been handled by the actor,
7098 * or %FALSE to continue the emission.
7102 actor_signals[KEY_PRESS_EVENT] =
7103 g_signal_new (I_("key-press-event"),
7104 G_TYPE_FROM_CLASS (object_class),
7106 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
7107 _clutter_boolean_handled_accumulator, NULL,
7108 _clutter_marshal_BOOLEAN__BOXED,
7110 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7112 * ClutterActor::key-release-event:
7113 * @actor: the actor which received the event
7114 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7116 * The ::key-release-event signal is emitted each time a keyboard button
7117 * is released while @actor has key focus (see
7118 * clutter_stage_set_key_focus()).
7120 * Return value: %TRUE if the event has been handled by the actor,
7121 * or %FALSE to continue the emission.
7125 actor_signals[KEY_RELEASE_EVENT] =
7126 g_signal_new (I_("key-release-event"),
7127 G_TYPE_FROM_CLASS (object_class),
7129 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
7130 _clutter_boolean_handled_accumulator, NULL,
7131 _clutter_marshal_BOOLEAN__BOXED,
7133 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7135 * ClutterActor::motion-event:
7136 * @actor: the actor which received the event
7137 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
7139 * The ::motion-event signal is emitted each time the mouse pointer is
7140 * moved over @actor.
7142 * Return value: %TRUE if the event has been handled by the actor,
7143 * or %FALSE to continue the emission.
7147 actor_signals[MOTION_EVENT] =
7148 g_signal_new (I_("motion-event"),
7149 G_TYPE_FROM_CLASS (object_class),
7151 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
7152 _clutter_boolean_handled_accumulator, NULL,
7153 _clutter_marshal_BOOLEAN__BOXED,
7155 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7158 * ClutterActor::key-focus-in:
7159 * @actor: the actor which now has key focus
7161 * The ::key-focus-in signal is emitted when @actor receives key focus.
7165 actor_signals[KEY_FOCUS_IN] =
7166 g_signal_new (I_("key-focus-in"),
7167 G_TYPE_FROM_CLASS (object_class),
7169 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
7171 _clutter_marshal_VOID__VOID,
7175 * ClutterActor::key-focus-out:
7176 * @actor: the actor which now has key focus
7178 * The ::key-focus-out signal is emitted when @actor loses key focus.
7182 actor_signals[KEY_FOCUS_OUT] =
7183 g_signal_new (I_("key-focus-out"),
7184 G_TYPE_FROM_CLASS (object_class),
7186 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
7188 _clutter_marshal_VOID__VOID,
7192 * ClutterActor::enter-event:
7193 * @actor: the actor which the pointer has entered.
7194 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7196 * The ::enter-event signal is emitted when the pointer enters the @actor
7198 * Return value: %TRUE if the event has been handled by the actor,
7199 * or %FALSE to continue the emission.
7203 actor_signals[ENTER_EVENT] =
7204 g_signal_new (I_("enter-event"),
7205 G_TYPE_FROM_CLASS (object_class),
7207 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
7208 _clutter_boolean_handled_accumulator, NULL,
7209 _clutter_marshal_BOOLEAN__BOXED,
7211 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7214 * ClutterActor::leave-event:
7215 * @actor: the actor which the pointer has left
7216 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7218 * The ::leave-event signal is emitted when the pointer leaves the @actor.
7220 * Return value: %TRUE if the event has been handled by the actor,
7221 * or %FALSE to continue the emission.
7225 actor_signals[LEAVE_EVENT] =
7226 g_signal_new (I_("leave-event"),
7227 G_TYPE_FROM_CLASS (object_class),
7229 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7230 _clutter_boolean_handled_accumulator, NULL,
7231 _clutter_marshal_BOOLEAN__BOXED,
7233 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7236 * ClutterActor::captured-event:
7237 * @actor: the actor which received the signal
7238 * @event: a #ClutterEvent
7240 * The ::captured-event signal is emitted when an event is captured
7241 * by Clutter. This signal will be emitted starting from the top-level
7242 * container (the #ClutterStage) to the actor which received the event
7243 * going down the hierarchy. This signal can be used to intercept every
7244 * event before the specialized events (like
7245 * ClutterActor::button-press-event or ::key-released-event) are
7248 * Return value: %TRUE if the event has been handled by the actor,
7249 * or %FALSE to continue the emission.
7253 actor_signals[CAPTURED_EVENT] =
7254 g_signal_new (I_("captured-event"),
7255 G_TYPE_FROM_CLASS (object_class),
7257 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7258 _clutter_boolean_handled_accumulator, NULL,
7259 _clutter_marshal_BOOLEAN__BOXED,
7261 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7264 * ClutterActor::paint:
7265 * @actor: the #ClutterActor that received the signal
7267 * The ::paint signal is emitted each time an actor is being painted.
7269 * Subclasses of #ClutterActor should override the class signal handler
7270 * and paint themselves in that function.
7272 * It is possible to connect a handler to the ::paint signal in order
7273 * to set up some custom aspect of a paint.
7277 actor_signals[PAINT] =
7278 g_signal_new (I_("paint"),
7279 G_TYPE_FROM_CLASS (object_class),
7282 G_STRUCT_OFFSET (ClutterActorClass, paint),
7284 _clutter_marshal_VOID__VOID,
7287 * ClutterActor::realize:
7288 * @actor: the #ClutterActor that received the signal
7290 * The ::realize signal is emitted each time an actor is being
7295 actor_signals[REALIZE] =
7296 g_signal_new (I_("realize"),
7297 G_TYPE_FROM_CLASS (object_class),
7299 G_STRUCT_OFFSET (ClutterActorClass, realize),
7301 _clutter_marshal_VOID__VOID,
7304 * ClutterActor::unrealize:
7305 * @actor: the #ClutterActor that received the signal
7307 * The ::unrealize signal is emitted each time an actor is being
7312 actor_signals[UNREALIZE] =
7313 g_signal_new (I_("unrealize"),
7314 G_TYPE_FROM_CLASS (object_class),
7316 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7318 _clutter_marshal_VOID__VOID,
7322 * ClutterActor::pick:
7323 * @actor: the #ClutterActor that received the signal
7324 * @color: the #ClutterColor to be used when picking
7326 * The ::pick signal is emitted each time an actor is being painted
7327 * in "pick mode". The pick mode is used to identify the actor during
7328 * the event handling phase, or by clutter_stage_get_actor_at_pos().
7329 * The actor should paint its shape using the passed @pick_color.
7331 * Subclasses of #ClutterActor should override the class signal handler
7332 * and paint themselves in that function.
7334 * It is possible to connect a handler to the ::pick signal in order
7335 * to set up some custom aspect of a paint in pick mode.
7339 actor_signals[PICK] =
7340 g_signal_new (I_("pick"),
7341 G_TYPE_FROM_CLASS (object_class),
7343 G_STRUCT_OFFSET (ClutterActorClass, pick),
7345 _clutter_marshal_VOID__BOXED,
7347 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7350 * ClutterActor::allocation-changed:
7351 * @actor: the #ClutterActor that emitted the signal
7352 * @box: a #ClutterActorBox with the new allocation
7353 * @flags: #ClutterAllocationFlags for the allocation
7355 * The ::allocation-changed signal is emitted when the
7356 * #ClutterActor:allocation property changes. Usually, application
7357 * code should just use the notifications for the :allocation property
7358 * but if you want to track the allocation flags as well, for instance
7359 * to know whether the absolute origin of @actor changed, then you might
7360 * want use this signal instead.
7364 actor_signals[ALLOCATION_CHANGED] =
7365 g_signal_new (I_("allocation-changed"),
7366 G_TYPE_FROM_CLASS (object_class),
7370 _clutter_marshal_VOID__BOXED_FLAGS,
7372 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7373 CLUTTER_TYPE_ALLOCATION_FLAGS);
7376 * ClutterActor::transitions-completed:
7377 * @actor: a #ClutterActor
7379 * The ::transitions-completed signal is emitted once all transitions
7380 * involving @actor are complete.
7384 actor_signals[TRANSITIONS_COMPLETED] =
7385 g_signal_new (I_("transitions-completed"),
7386 G_TYPE_FROM_CLASS (object_class),
7390 _clutter_marshal_VOID__VOID,
7395 clutter_actor_init (ClutterActor *self)
7397 ClutterActorPrivate *priv;
7399 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7401 priv->id = _clutter_context_acquire_id (self);
7404 priv->opacity = 0xff;
7405 priv->show_on_set_parent = TRUE;
7407 priv->needs_width_request = TRUE;
7408 priv->needs_height_request = TRUE;
7409 priv->needs_allocation = TRUE;
7411 priv->cached_width_age = 1;
7412 priv->cached_height_age = 1;
7414 priv->opacity_override = -1;
7415 priv->enable_model_view_transform = TRUE;
7417 /* Initialize an empty paint volume to start with */
7418 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7419 priv->last_paint_volume_valid = TRUE;
7421 priv->transform_valid = FALSE;
7423 /* the default is to stretch the content, to match the
7424 * current behaviour of basically all actors. also, it's
7425 * the easiest thing to compute.
7427 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7428 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7429 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7431 /* this flag will be set to TRUE if the actor gets a child
7432 * or if the [xy]-expand flags are explicitly set; until
7433 * then, the actor does not need to expand.
7435 * this also allows us to avoid computing the expand flag
7436 * when building up a scene.
7438 priv->needs_compute_expand = FALSE;
7440 clutter_actor_save_easing_state (self);
7441 clutter_actor_set_easing_duration (self, 0);
7445 * clutter_actor_new:
7447 * Creates a new #ClutterActor.
7449 * A newly created actor has a floating reference, which will be sunk
7450 * when it is added to another actor.
7452 * Return value: (transfer full): the newly created #ClutterActor
7457 clutter_actor_new (void)
7459 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7463 * clutter_actor_destroy:
7464 * @self: a #ClutterActor
7466 * Destroys an actor. When an actor is destroyed, it will break any
7467 * references it holds to other objects. If the actor is inside a
7468 * container, the actor will be removed.
7470 * When you destroy a container, its children will be destroyed as well.
7472 * Note: you cannot destroy the #ClutterStage returned by
7473 * clutter_stage_get_default().
7476 clutter_actor_destroy (ClutterActor *self)
7478 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7480 g_object_ref (self);
7482 /* avoid recursion while destroying */
7483 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7485 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7487 g_object_run_dispose (G_OBJECT (self));
7489 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7492 g_object_unref (self);
7496 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7497 ClutterPaintVolume *clip)
7499 ClutterActorPrivate *priv = self->priv;
7500 ClutterPaintVolume *pv;
7503 /* Remove queue entry early in the process, otherwise a new
7504 queue_redraw() during signal handling could put back this
7505 object in the stage redraw list (but the entry is freed as
7506 soon as we return from this function, causing a segfault
7509 priv->queue_redraw_entry = NULL;
7511 /* If we've been explicitly passed a clip volume then there's
7512 * nothing more to calculate, but otherwise the only thing we know
7513 * is that the change is constrained to the given actor.
7515 * The idea is that if we know the paint volume for where the actor
7516 * was last drawn (in eye coordinates) and we also have the paint
7517 * volume for where it will be drawn next (in actor coordinates)
7518 * then if we queue a redraw for both these volumes that will cover
7519 * everything that needs to be redrawn to clear the old view and
7520 * show the latest view of the actor.
7522 * Don't clip this redraw if we don't know what position we had for
7523 * the previous redraw since we don't know where to set the clip so
7524 * it will clear the actor as it is currently.
7528 _clutter_actor_set_queue_redraw_clip (self, clip);
7531 else if (G_LIKELY (priv->last_paint_volume_valid))
7533 pv = _clutter_actor_get_paint_volume_mutable (self);
7536 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7538 /* make sure we redraw the actors old position... */
7539 _clutter_actor_set_queue_redraw_clip (stage,
7540 &priv->last_paint_volume);
7541 _clutter_actor_signal_queue_redraw (stage, stage);
7542 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7544 /* XXX: Ideally the redraw signal would take a clip volume
7545 * argument, but that would be an ABI break. Until we can
7546 * break the ABI we pass the argument out-of-band
7549 /* setup the clip for the actors new position... */
7550 _clutter_actor_set_queue_redraw_clip (self, pv);
7559 _clutter_actor_signal_queue_redraw (self, self);
7561 /* Just in case anyone is manually firing redraw signals without
7562 * using the public queue_redraw() API we are careful to ensure that
7563 * our out-of-band clip member is cleared before returning...
7565 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7567 if (G_LIKELY (clipped))
7568 _clutter_actor_set_queue_redraw_clip (self, NULL);
7572 _clutter_actor_get_allocation_clip (ClutterActor *self,
7573 ClutterActorBox *clip)
7575 ClutterActorBox allocation;
7577 /* XXX: we don't care if we get an out of date allocation here
7578 * because clutter_actor_queue_redraw_with_clip knows to ignore
7579 * the clip if the actor's allocation is invalid.
7581 * This is noted because clutter_actor_get_allocation_box does some
7582 * unnecessary work to support buggy code with a comment suggesting
7583 * that it could be changed later which would be good for this use
7586 clutter_actor_get_allocation_box (self, &allocation);
7588 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7589 * actor's own coordinate space but the allocation is in parent
7593 clip->x2 = allocation.x2 - allocation.x1;
7594 clip->y2 = allocation.y2 - allocation.y1;
7598 _clutter_actor_queue_redraw_full (ClutterActor *self,
7599 ClutterRedrawFlags flags,
7600 ClutterPaintVolume *volume,
7601 ClutterEffect *effect)
7603 ClutterActorPrivate *priv = self->priv;
7604 ClutterPaintVolume allocation_pv;
7605 ClutterPaintVolume *pv;
7606 gboolean should_free_pv;
7607 ClutterActor *stage;
7609 /* Here's an outline of the actor queue redraw mechanism:
7611 * The process starts in one of the following two functions which
7612 * are wrappers for this function:
7613 * clutter_actor_queue_redraw
7614 * _clutter_actor_queue_redraw_with_clip
7616 * additionally, an effect can queue a redraw by wrapping this
7617 * function in clutter_effect_queue_rerun
7619 * This functions queues an entry in a list associated with the
7620 * stage which is a list of actors that queued a redraw while
7621 * updating the timelines, performing layouting and processing other
7622 * mainloop sources before the next paint starts.
7624 * We aim to minimize the processing done at this point because
7625 * there is a good chance other events will happen while updating
7626 * the scenegraph that would invalidate any expensive work we might
7627 * otherwise try to do here. For example we don't try and resolve
7628 * the screen space bounding box of an actor at this stage so as to
7629 * minimize how much of the screen redraw because it's possible
7630 * something else will happen which will force a full redraw anyway.
7632 * When all updates are complete and we come to paint the stage then
7633 * we iterate this list and actually emit the "queue-redraw" signals
7634 * for each of the listed actors which will bubble up to the stage
7635 * for each actor and at that point we will transform the actors
7636 * paint volume into screen coordinates to determine the clip region
7637 * for what needs to be redrawn in the next paint.
7639 * Besides minimizing redundant work another reason for this
7640 * deferred design is that it's more likely we will be able to
7641 * determine the paint volume of an actor once we've finished
7642 * updating the scenegraph because its allocation should be up to
7643 * date. NB: If we can't determine an actors paint volume then we
7644 * can't automatically queue a clipped redraw which can make a big
7645 * difference to performance.
7647 * So the control flow goes like this:
7648 * One of clutter_actor_queue_redraw,
7649 * _clutter_actor_queue_redraw_with_clip
7650 * or clutter_effect_queue_rerun
7652 * then control moves to:
7653 * _clutter_stage_queue_actor_redraw
7655 * later during _clutter_stage_do_update, once relayouting is done
7656 * and the scenegraph has been updated we will call:
7657 * _clutter_stage_finish_queue_redraws
7659 * _clutter_stage_finish_queue_redraws will call
7660 * _clutter_actor_finish_queue_redraw for each listed actor.
7661 * Note: actors *are* allowed to queue further redraws during this
7662 * process (considering clone actors or texture_new_from_actor which
7663 * respond to their source queueing a redraw by queuing a redraw
7664 * themselves). We repeat the process until the list is empty.
7666 * This will result in the "queue-redraw" signal being fired for
7667 * each actor which will pass control to the default signal handler:
7668 * clutter_actor_real_queue_redraw
7670 * This will bubble up to the stages handler:
7671 * clutter_stage_real_queue_redraw
7673 * clutter_stage_real_queue_redraw will transform the actors paint
7674 * volume into screen space and add it as a clip region for the next
7678 /* ignore queueing a redraw for actors being destroyed */
7679 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7682 stage = _clutter_actor_get_stage_internal (self);
7684 /* Ignore queueing a redraw for actors not descended from a stage */
7688 /* ignore queueing a redraw on stages that are being destroyed */
7689 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7692 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7694 ClutterActorBox allocation_clip;
7695 ClutterVertex origin;
7697 /* If the actor doesn't have a valid allocation then we will
7698 * queue a full stage redraw. */
7699 if (priv->needs_allocation)
7701 /* NB: NULL denotes an undefined clip which will result in a
7703 _clutter_actor_set_queue_redraw_clip (self, NULL);
7704 _clutter_actor_signal_queue_redraw (self, self);
7708 _clutter_paint_volume_init_static (&allocation_pv, self);
7709 pv = &allocation_pv;
7711 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7713 origin.x = allocation_clip.x1;
7714 origin.y = allocation_clip.y1;
7716 clutter_paint_volume_set_origin (pv, &origin);
7717 clutter_paint_volume_set_width (pv,
7718 allocation_clip.x2 - allocation_clip.x1);
7719 clutter_paint_volume_set_height (pv,
7720 allocation_clip.y2 -
7721 allocation_clip.y1);
7722 should_free_pv = TRUE;
7727 should_free_pv = FALSE;
7730 self->priv->queue_redraw_entry =
7731 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7732 priv->queue_redraw_entry,
7737 clutter_paint_volume_free (pv);
7739 /* If this is the first redraw queued then we can directly use the
7741 if (!priv->is_dirty)
7742 priv->effect_to_redraw = effect;
7743 /* Otherwise we need to merge it with the existing effect parameter */
7744 else if (effect != NULL)
7746 /* If there's already an effect then we need to use whichever is
7747 later in the chain of actors. Otherwise a full redraw has
7748 already been queued on the actor so we need to ignore the
7750 if (priv->effect_to_redraw != NULL)
7752 if (priv->effects == NULL)
7753 g_warning ("Redraw queued with an effect that is "
7754 "not applied to the actor");
7759 for (l = _clutter_meta_group_peek_metas (priv->effects);
7763 if (l->data == priv->effect_to_redraw ||
7765 priv->effect_to_redraw = l->data;
7772 /* If no effect is specified then we need to redraw the whole
7774 priv->effect_to_redraw = NULL;
7777 priv->is_dirty = TRUE;
7781 * clutter_actor_queue_redraw:
7782 * @self: A #ClutterActor
7784 * Queues up a redraw of an actor and any children. The redraw occurs
7785 * once the main loop becomes idle (after the current batch of events
7786 * has been processed, roughly).
7788 * Applications rarely need to call this, as redraws are handled
7789 * automatically by modification functions.
7791 * This function will not do anything if @self is not visible, or
7792 * if the actor is inside an invisible part of the scenegraph.
7794 * Also be aware that painting is a NOP for actors with an opacity of
7797 * When you are implementing a custom actor you must queue a redraw
7798 * whenever some private state changes that will affect painting or
7799 * picking of your actor.
7802 clutter_actor_queue_redraw (ClutterActor *self)
7804 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7806 _clutter_actor_queue_redraw_full (self,
7808 NULL, /* clip volume */
7813 * _clutter_actor_queue_redraw_with_clip:
7814 * @self: A #ClutterActor
7815 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7816 * this queue redraw.
7817 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7818 * redrawn or %NULL if you are just using a @flag to state your
7821 * Queues up a clipped redraw of an actor and any children. The redraw
7822 * occurs once the main loop becomes idle (after the current batch of
7823 * events has been processed, roughly).
7825 * If no flags are given the clip volume is defined by @volume
7826 * specified in actor coordinates and tells Clutter that only content
7827 * within this volume has been changed so Clutter can optionally
7828 * optimize the redraw.
7830 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7831 * should be %NULL and this tells Clutter to use the actor's current
7832 * allocation as a clip box. This flag can only be used for 2D actors,
7833 * because any actor with depth may be projected outside its
7836 * Applications rarely need to call this, as redraws are handled
7837 * automatically by modification functions.
7839 * This function will not do anything if @self is not visible, or if
7840 * the actor is inside an invisible part of the scenegraph.
7842 * Also be aware that painting is a NOP for actors with an opacity of
7845 * When you are implementing a custom actor you must queue a redraw
7846 * whenever some private state changes that will affect painting or
7847 * picking of your actor.
7850 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7851 ClutterRedrawFlags flags,
7852 ClutterPaintVolume *volume)
7854 _clutter_actor_queue_redraw_full (self,
7856 volume, /* clip volume */
7861 _clutter_actor_queue_only_relayout (ClutterActor *self)
7863 ClutterActorPrivate *priv = self->priv;
7865 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7868 if (priv->needs_width_request &&
7869 priv->needs_height_request &&
7870 priv->needs_allocation)
7871 return; /* save some cpu cycles */
7873 #if CLUTTER_ENABLE_DEBUG
7874 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7876 g_warning ("The actor '%s' is currently inside an allocation "
7877 "cycle; calling clutter_actor_queue_relayout() is "
7879 _clutter_actor_get_debug_name (self));
7881 #endif /* CLUTTER_ENABLE_DEBUG */
7883 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7887 * clutter_actor_queue_redraw_with_clip:
7888 * @self: a #ClutterActor
7889 * @clip: (allow-none): a rectangular clip region, or %NULL
7891 * Queues a redraw on @self limited to a specific, actor-relative
7894 * If @clip is %NULL this function is equivalent to
7895 * clutter_actor_queue_redraw().
7900 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7901 const cairo_rectangle_int_t *clip)
7903 ClutterPaintVolume volume;
7904 ClutterVertex origin;
7906 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7910 clutter_actor_queue_redraw (self);
7914 _clutter_paint_volume_init_static (&volume, self);
7920 clutter_paint_volume_set_origin (&volume, &origin);
7921 clutter_paint_volume_set_width (&volume, clip->width);
7922 clutter_paint_volume_set_height (&volume, clip->height);
7924 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7926 clutter_paint_volume_free (&volume);
7930 * clutter_actor_queue_relayout:
7931 * @self: A #ClutterActor
7933 * Indicates that the actor's size request or other layout-affecting
7934 * properties may have changed. This function is used inside #ClutterActor
7935 * subclass implementations, not by applications directly.
7937 * Queueing a new layout automatically queues a redraw as well.
7942 clutter_actor_queue_relayout (ClutterActor *self)
7944 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7946 _clutter_actor_queue_only_relayout (self);
7947 clutter_actor_queue_redraw (self);
7951 * clutter_actor_get_preferred_size:
7952 * @self: a #ClutterActor
7953 * @min_width_p: (out) (allow-none): return location for the minimum
7955 * @min_height_p: (out) (allow-none): return location for the minimum
7957 * @natural_width_p: (out) (allow-none): return location for the natural
7959 * @natural_height_p: (out) (allow-none): return location for the natural
7962 * Computes the preferred minimum and natural size of an actor, taking into
7963 * account the actor's geometry management (either height-for-width
7964 * or width-for-height).
7966 * The width and height used to compute the preferred height and preferred
7967 * width are the actor's natural ones.
7969 * If you need to control the height for the preferred width, or the width for
7970 * the preferred height, you should use clutter_actor_get_preferred_width()
7971 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7972 * geometry management using the #ClutterActor:request-mode property.
7977 clutter_actor_get_preferred_size (ClutterActor *self,
7978 gfloat *min_width_p,
7979 gfloat *min_height_p,
7980 gfloat *natural_width_p,
7981 gfloat *natural_height_p)
7983 ClutterActorPrivate *priv;
7984 gfloat min_width, min_height;
7985 gfloat natural_width, natural_height;
7987 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7991 min_width = min_height = 0;
7992 natural_width = natural_height = 0;
7994 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7996 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7997 clutter_actor_get_preferred_width (self, -1,
8000 clutter_actor_get_preferred_height (self, natural_width,
8006 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
8007 clutter_actor_get_preferred_height (self, -1,
8010 clutter_actor_get_preferred_width (self, natural_height,
8016 *min_width_p = min_width;
8019 *min_height_p = min_height;
8021 if (natural_width_p)
8022 *natural_width_p = natural_width;
8024 if (natural_height_p)
8025 *natural_height_p = natural_height;
8030 * @align: a #ClutterActorAlign
8031 * @direction: a #ClutterTextDirection
8033 * Retrieves the correct alignment depending on the text direction
8035 * Return value: the effective alignment
8037 static ClutterActorAlign
8038 effective_align (ClutterActorAlign align,
8039 ClutterTextDirection direction)
8041 ClutterActorAlign res;
8045 case CLUTTER_ACTOR_ALIGN_START:
8046 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
8047 ? CLUTTER_ACTOR_ALIGN_END
8048 : CLUTTER_ACTOR_ALIGN_START;
8051 case CLUTTER_ACTOR_ALIGN_END:
8052 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
8053 ? CLUTTER_ACTOR_ALIGN_START
8054 : CLUTTER_ACTOR_ALIGN_END;
8066 * _clutter_actor_get_effective_x_align:
8067 * @self: a #ClutterActor
8069 * Retrieves the effective horizontal alignment, taking into
8070 * consideration the text direction of @self.
8072 * Return value: the effective horizontal alignment
8075 _clutter_actor_get_effective_x_align (ClutterActor *self)
8077 return effective_align (clutter_actor_get_x_align (self),
8078 clutter_actor_get_text_direction (self));
8082 adjust_for_margin (float margin_start,
8084 float *minimum_size,
8085 float *natural_size,
8086 float *allocated_start,
8087 float *allocated_end)
8089 *minimum_size -= (margin_start + margin_end);
8090 *natural_size -= (margin_start + margin_end);
8091 *allocated_start += margin_start;
8092 *allocated_end -= margin_end;
8096 adjust_for_alignment (ClutterActorAlign alignment,
8098 float *allocated_start,
8099 float *allocated_end)
8101 float allocated_size = *allocated_end - *allocated_start;
8105 case CLUTTER_ACTOR_ALIGN_FILL:
8109 case CLUTTER_ACTOR_ALIGN_START:
8111 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
8114 case CLUTTER_ACTOR_ALIGN_END:
8115 if (allocated_size > natural_size)
8117 *allocated_start += (allocated_size - natural_size);
8118 *allocated_end = *allocated_start + natural_size;
8122 case CLUTTER_ACTOR_ALIGN_CENTER:
8123 if (allocated_size > natural_size)
8125 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
8126 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
8133 * clutter_actor_adjust_width:
8134 * @self: a #ClutterActor
8135 * @minimum_width: (inout): the actor's preferred minimum width, which
8136 * will be adjusted depending on the margin
8137 * @natural_width: (inout): the actor's preferred natural width, which
8138 * will be adjusted depending on the margin
8139 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
8140 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
8142 * Adjusts the preferred and allocated position and size of an actor,
8143 * depending on the margin and alignment properties.
8146 clutter_actor_adjust_width (ClutterActor *self,
8147 gfloat *minimum_width,
8148 gfloat *natural_width,
8149 gfloat *adjusted_x1,
8150 gfloat *adjusted_x2)
8152 ClutterTextDirection text_dir;
8153 const ClutterLayoutInfo *info;
8155 info = _clutter_actor_get_layout_info_or_defaults (self);
8156 text_dir = clutter_actor_get_text_direction (self);
8158 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
8160 /* this will tweak natural_width to remove the margin, so that
8161 * adjust_for_alignment() will use the correct size
8163 adjust_for_margin (info->margin.left, info->margin.right,
8164 minimum_width, natural_width,
8165 adjusted_x1, adjusted_x2);
8167 adjust_for_alignment (effective_align (info->x_align, text_dir),
8169 adjusted_x1, adjusted_x2);
8173 * clutter_actor_adjust_height:
8174 * @self: a #ClutterActor
8175 * @minimum_height: (inout): the actor's preferred minimum height, which
8176 * will be adjusted depending on the margin
8177 * @natural_height: (inout): the actor's preferred natural height, which
8178 * will be adjusted depending on the margin
8179 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
8180 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
8182 * Adjusts the preferred and allocated position and size of an actor,
8183 * depending on the margin and alignment properties.
8186 clutter_actor_adjust_height (ClutterActor *self,
8187 gfloat *minimum_height,
8188 gfloat *natural_height,
8189 gfloat *adjusted_y1,
8190 gfloat *adjusted_y2)
8192 const ClutterLayoutInfo *info;
8194 info = _clutter_actor_get_layout_info_or_defaults (self);
8196 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
8198 /* this will tweak natural_height to remove the margin, so that
8199 * adjust_for_alignment() will use the correct size
8201 adjust_for_margin (info->margin.top, info->margin.bottom,
8202 minimum_height, natural_height,
8206 /* we don't use effective_align() here, because text direction
8207 * only affects the horizontal axis
8209 adjust_for_alignment (info->y_align,
8216 /* looks for a cached size request for this for_size. If not
8217 * found, returns the oldest entry so it can be overwritten */
8219 _clutter_actor_get_cached_size_request (gfloat for_size,
8220 SizeRequest *cached_size_requests,
8221 SizeRequest **result)
8225 *result = &cached_size_requests[0];
8227 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
8231 sr = &cached_size_requests[i];
8234 sr->for_size == for_size)
8236 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8240 else if (sr->age < (*result)->age)
8246 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8252 * clutter_actor_get_preferred_width:
8253 * @self: A #ClutterActor
8254 * @for_height: available height when computing the preferred width,
8255 * or a negative value to indicate that no height is defined
8256 * @min_width_p: (out) (allow-none): return location for minimum width,
8258 * @natural_width_p: (out) (allow-none): return location for the natural
8261 * Computes the requested minimum and natural widths for an actor,
8262 * optionally depending on the specified height, or if they are
8263 * already computed, returns the cached values.
8265 * An actor may not get its request - depending on the layout
8266 * manager that's in effect.
8268 * A request should not incorporate the actor's scale or anchor point;
8269 * those transformations do not affect layout, only rendering.
8274 clutter_actor_get_preferred_width (ClutterActor *self,
8276 gfloat *min_width_p,
8277 gfloat *natural_width_p)
8279 float request_min_width, request_natural_width;
8280 SizeRequest *cached_size_request;
8281 const ClutterLayoutInfo *info;
8282 ClutterActorPrivate *priv;
8283 gboolean found_in_cache;
8285 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8289 info = _clutter_actor_get_layout_info_or_defaults (self);
8291 /* we shortcircuit the case of a fixed size set using set_width() */
8292 if (priv->min_width_set && priv->natural_width_set)
8294 if (min_width_p != NULL)
8295 *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8297 if (natural_width_p != NULL)
8298 *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8303 /* the remaining cases are:
8305 * - either min_width or natural_width have been set
8306 * - neither min_width or natural_width have been set
8308 * in both cases, we go through the cache (and through the actor in case
8309 * of cache misses) and determine the authoritative value depending on
8313 if (!priv->needs_width_request)
8316 _clutter_actor_get_cached_size_request (for_height,
8317 priv->width_requests,
8318 &cached_size_request);
8322 /* if the actor needs a width request we use the first slot */
8323 found_in_cache = FALSE;
8324 cached_size_request = &priv->width_requests[0];
8327 if (!found_in_cache)
8329 gfloat minimum_width, natural_width;
8330 ClutterActorClass *klass;
8332 minimum_width = natural_width = 0;
8334 /* adjust for the margin */
8335 if (for_height >= 0)
8337 for_height -= (info->margin.top + info->margin.bottom);
8342 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8344 klass = CLUTTER_ACTOR_GET_CLASS (self);
8345 klass->get_preferred_width (self, for_height,
8349 /* adjust for the margin */
8350 minimum_width += (info->margin.left + info->margin.right);
8351 natural_width += (info->margin.left + info->margin.right);
8353 /* Due to accumulated float errors, it's better not to warn
8354 * on this, but just fix it.
8356 if (natural_width < minimum_width)
8357 natural_width = minimum_width;
8359 cached_size_request->min_size = minimum_width;
8360 cached_size_request->natural_size = natural_width;
8361 cached_size_request->for_size = for_height;
8362 cached_size_request->age = priv->cached_width_age;
8364 priv->cached_width_age += 1;
8365 priv->needs_width_request = FALSE;
8368 if (!priv->min_width_set)
8369 request_min_width = cached_size_request->min_size;
8371 request_min_width = info->margin.left
8372 + info->minimum.width
8373 + info->margin.right;
8375 if (!priv->natural_width_set)
8376 request_natural_width = cached_size_request->natural_size;
8378 request_natural_width = info->margin.left
8379 + info->natural.width
8380 + info->margin.right;
8383 *min_width_p = request_min_width;
8385 if (natural_width_p)
8386 *natural_width_p = request_natural_width;
8390 * clutter_actor_get_preferred_height:
8391 * @self: A #ClutterActor
8392 * @for_width: available width to assume in computing desired height,
8393 * or a negative value to indicate that no width is defined
8394 * @min_height_p: (out) (allow-none): return location for minimum height,
8396 * @natural_height_p: (out) (allow-none): return location for natural
8399 * Computes the requested minimum and natural heights for an actor,
8400 * or if they are already computed, returns the cached values.
8402 * An actor may not get its request - depending on the layout
8403 * manager that's in effect.
8405 * A request should not incorporate the actor's scale or anchor point;
8406 * those transformations do not affect layout, only rendering.
8411 clutter_actor_get_preferred_height (ClutterActor *self,
8413 gfloat *min_height_p,
8414 gfloat *natural_height_p)
8416 float request_min_height, request_natural_height;
8417 SizeRequest *cached_size_request;
8418 const ClutterLayoutInfo *info;
8419 ClutterActorPrivate *priv;
8420 gboolean found_in_cache;
8422 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8426 info = _clutter_actor_get_layout_info_or_defaults (self);
8428 /* we shortcircuit the case of a fixed size set using set_height() */
8429 if (priv->min_height_set && priv->natural_height_set)
8431 if (min_height_p != NULL)
8432 *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8434 if (natural_height_p != NULL)
8435 *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8440 /* the remaining cases are:
8442 * - either min_height or natural_height have been set
8443 * - neither min_height or natural_height have been set
8445 * in both cases, we go through the cache (and through the actor in case
8446 * of cache misses) and determine the authoritative value depending on
8450 if (!priv->needs_height_request)
8453 _clutter_actor_get_cached_size_request (for_width,
8454 priv->height_requests,
8455 &cached_size_request);
8459 found_in_cache = FALSE;
8460 cached_size_request = &priv->height_requests[0];
8463 if (!found_in_cache)
8465 gfloat minimum_height, natural_height;
8466 ClutterActorClass *klass;
8468 minimum_height = natural_height = 0;
8470 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8472 /* adjust for margin */
8475 for_width -= (info->margin.left + info->margin.right);
8480 klass = CLUTTER_ACTOR_GET_CLASS (self);
8481 klass->get_preferred_height (self, for_width,
8485 /* adjust for margin */
8486 minimum_height += (info->margin.top + info->margin.bottom);
8487 natural_height += (info->margin.top + info->margin.bottom);
8489 /* Due to accumulated float errors, it's better not to warn
8490 * on this, but just fix it.
8492 if (natural_height < minimum_height)
8493 natural_height = minimum_height;
8495 cached_size_request->min_size = minimum_height;
8496 cached_size_request->natural_size = natural_height;
8497 cached_size_request->for_size = for_width;
8498 cached_size_request->age = priv->cached_height_age;
8500 priv->cached_height_age += 1;
8501 priv->needs_height_request = FALSE;
8504 if (!priv->min_height_set)
8505 request_min_height = cached_size_request->min_size;
8507 request_min_height = info->margin.top
8508 + info->minimum.height
8509 + info->margin.bottom;
8511 if (!priv->natural_height_set)
8512 request_natural_height = cached_size_request->natural_size;
8514 request_natural_height = info->margin.top
8515 + info->natural.height
8516 + info->margin.bottom;
8519 *min_height_p = request_min_height;
8521 if (natural_height_p)
8522 *natural_height_p = request_natural_height;
8526 * clutter_actor_get_allocation_box:
8527 * @self: A #ClutterActor
8528 * @box: (out): the function fills this in with the actor's allocation
8530 * Gets the layout box an actor has been assigned. The allocation can
8531 * only be assumed valid inside a paint() method; anywhere else, it
8532 * may be out-of-date.
8534 * An allocation does not incorporate the actor's scale or anchor point;
8535 * those transformations do not affect layout, only rendering.
8537 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8538 * of functions inside the implementation of the get_preferred_width()
8539 * or get_preferred_height() virtual functions.</note>
8544 clutter_actor_get_allocation_box (ClutterActor *self,
8545 ClutterActorBox *box)
8547 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8549 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8550 * which limits calling get_allocation to inside paint() basically; or
8551 * we can 2) force a layout, which could be expensive if someone calls
8552 * get_allocation somewhere silly; or we can 3) just return the latest
8553 * value, allowing it to be out-of-date, and assume people know what
8556 * The least-surprises approach that keeps existing code working is
8557 * likely to be 2). People can end up doing some inefficient things,
8558 * though, and in general code that requires 2) is probably broken.
8561 /* this implements 2) */
8562 if (G_UNLIKELY (self->priv->needs_allocation))
8564 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8566 /* do not queue a relayout on an unparented actor */
8568 _clutter_stage_maybe_relayout (stage);
8571 /* commenting out the code above and just keeping this assigment
8574 *box = self->priv->allocation;
8578 * clutter_actor_get_allocation_geometry:
8579 * @self: A #ClutterActor
8580 * @geom: (out): allocation geometry in pixels
8582 * Gets the layout box an actor has been assigned. The allocation can
8583 * only be assumed valid inside a paint() method; anywhere else, it
8584 * may be out-of-date.
8586 * An allocation does not incorporate the actor's scale or anchor point;
8587 * those transformations do not affect layout, only rendering.
8589 * The returned rectangle is in pixels.
8594 clutter_actor_get_allocation_geometry (ClutterActor *self,
8595 ClutterGeometry *geom)
8597 ClutterActorBox box;
8599 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8600 g_return_if_fail (geom != NULL);
8602 clutter_actor_get_allocation_box (self, &box);
8604 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8605 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8606 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8607 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8611 clutter_actor_update_constraints (ClutterActor *self,
8612 ClutterActorBox *allocation)
8614 ClutterActorPrivate *priv = self->priv;
8615 const GList *constraints, *l;
8617 if (priv->constraints == NULL)
8620 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8621 for (l = constraints; l != NULL; l = l->next)
8623 ClutterConstraint *constraint = l->data;
8624 ClutterActorMeta *meta = l->data;
8626 if (clutter_actor_meta_get_enabled (meta))
8628 _clutter_constraint_update_allocation (constraint,
8632 CLUTTER_NOTE (LAYOUT,
8633 "Allocation of '%s' after constraint '%s': "
8634 "{ %.2f, %.2f, %.2f, %.2f }",
8635 _clutter_actor_get_debug_name (self),
8636 _clutter_actor_meta_get_debug_name (meta),
8646 * clutter_actor_adjust_allocation:
8647 * @self: a #ClutterActor
8648 * @allocation: (inout): the allocation to adjust
8650 * Adjusts the passed allocation box taking into account the actor's
8651 * layout information, like alignment, expansion, and margin.
8654 clutter_actor_adjust_allocation (ClutterActor *self,
8655 ClutterActorBox *allocation)
8657 ClutterActorBox adj_allocation;
8658 float alloc_width, alloc_height;
8659 float min_width, min_height;
8660 float nat_width, nat_height;
8661 ClutterRequestMode req_mode;
8663 adj_allocation = *allocation;
8665 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8667 /* we want to hit the cache, so we use the public API */
8668 req_mode = clutter_actor_get_request_mode (self);
8670 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8672 clutter_actor_get_preferred_width (self, -1,
8675 clutter_actor_get_preferred_height (self, alloc_width,
8679 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8681 clutter_actor_get_preferred_height (self, -1,
8684 clutter_actor_get_preferred_width (self, alloc_height,
8689 #ifdef CLUTTER_ENABLE_DEBUG
8690 /* warn about underallocations */
8691 if (_clutter_diagnostic_enabled () &&
8692 (floorf (min_width - alloc_width) > 0 ||
8693 floorf (min_height - alloc_height) > 0))
8695 ClutterActor *parent = clutter_actor_get_parent (self);
8697 /* the only actors that are allowed to be underallocated are the Stage,
8698 * as it doesn't have an implicit size, and Actors that specifically
8699 * told us that they want to opt-out from layout control mechanisms
8700 * through the NO_LAYOUT escape hatch.
8702 if (parent != NULL &&
8703 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8705 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8706 "of %.2f x %.2f from its parent actor '%s', but its "
8707 "requested minimum size is of %.2f x %.2f",
8708 _clutter_actor_get_debug_name (self),
8709 alloc_width, alloc_height,
8710 _clutter_actor_get_debug_name (parent),
8711 min_width, min_height);
8716 clutter_actor_adjust_width (self,
8720 &adj_allocation.x2);
8722 clutter_actor_adjust_height (self,
8726 &adj_allocation.y2);
8728 /* we maintain the invariant that an allocation cannot be adjusted
8729 * to be outside the parent-given box
8731 if (adj_allocation.x1 < allocation->x1 ||
8732 adj_allocation.y1 < allocation->y1 ||
8733 adj_allocation.x2 > allocation->x2 ||
8734 adj_allocation.y2 > allocation->y2)
8736 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8737 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8738 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8739 _clutter_actor_get_debug_name (self),
8740 adj_allocation.x1, adj_allocation.y1,
8741 adj_allocation.x2 - adj_allocation.x1,
8742 adj_allocation.y2 - adj_allocation.y1,
8743 allocation->x1, allocation->y1,
8744 allocation->x2 - allocation->x1,
8745 allocation->y2 - allocation->y1);
8749 *allocation = adj_allocation;
8753 clutter_actor_allocate_internal (ClutterActor *self,
8754 const ClutterActorBox *allocation,
8755 ClutterAllocationFlags flags)
8757 ClutterActorClass *klass;
8759 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8761 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8762 _clutter_actor_get_debug_name (self));
8764 klass = CLUTTER_ACTOR_GET_CLASS (self);
8765 klass->allocate (self, allocation, flags);
8767 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8769 clutter_actor_queue_redraw (self);
8773 * clutter_actor_allocate:
8774 * @self: A #ClutterActor
8775 * @box: new allocation of the actor, in parent-relative coordinates
8776 * @flags: flags that control the allocation
8778 * Called by the parent of an actor to assign the actor its size.
8779 * Should never be called by applications (except when implementing
8780 * a container or layout manager).
8782 * Actors can know from their allocation box whether they have moved
8783 * with respect to their parent actor. The @flags parameter describes
8784 * additional information about the allocation, for instance whether
8785 * the parent has moved with respect to the stage, for example because
8786 * a grandparent's origin has moved.
8791 clutter_actor_allocate (ClutterActor *self,
8792 const ClutterActorBox *box,
8793 ClutterAllocationFlags flags)
8795 ClutterActorBox old_allocation, real_allocation;
8796 gboolean origin_changed, child_moved, size_changed;
8797 gboolean stage_allocation_changed;
8798 ClutterActorPrivate *priv;
8800 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8801 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8803 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8804 "which isn't a descendent of the stage!\n",
8805 self, _clutter_actor_get_debug_name (self));
8811 old_allocation = priv->allocation;
8812 real_allocation = *box;
8814 /* constraints are allowed to modify the allocation only here; we do
8815 * this prior to all the other checks so that we can bail out if the
8816 * allocation did not change
8818 clutter_actor_update_constraints (self, &real_allocation);
8820 /* adjust the allocation depending on the align/margin properties */
8821 clutter_actor_adjust_allocation (self, &real_allocation);
8823 if (real_allocation.x2 < real_allocation.x1 ||
8824 real_allocation.y2 < real_allocation.y1)
8826 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8827 _clutter_actor_get_debug_name (self),
8828 real_allocation.x2 - real_allocation.x1,
8829 real_allocation.y2 - real_allocation.y1);
8832 /* we allow 0-sized actors, but not negative-sized ones */
8833 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8834 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8836 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8838 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8839 real_allocation.y1 != old_allocation.y1);
8841 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8842 real_allocation.y2 != old_allocation.y2);
8844 if (origin_changed || child_moved || size_changed)
8845 stage_allocation_changed = TRUE;
8847 stage_allocation_changed = FALSE;
8849 /* If we get an allocation "out of the blue"
8850 * (we did not queue relayout), then we want to
8851 * ignore it. But if we have needs_allocation set,
8852 * we want to guarantee that allocate() virtual
8853 * method is always called, i.e. that queue_relayout()
8854 * always results in an allocate() invocation on
8857 * The optimization here is to avoid re-allocating
8858 * actors that did not queue relayout and were
8861 if (!priv->needs_allocation && !stage_allocation_changed)
8863 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8867 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8868 * clutter_actor_allocate(), it indicates whether the parent has its
8869 * absolute origin moved; when passed in to ClutterActor::allocate()
8870 * virtual method though, it indicates whether the child has its
8871 * absolute origin moved. So we set it when child_moved is TRUE
8874 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8876 /* store the flags here, so that they can be propagated by the
8879 self->priv->allocation_flags = flags;
8881 if (_clutter_actor_get_transition (self, obj_props[PROP_ALLOCATION]) == NULL)
8883 _clutter_actor_create_transition (self, obj_props[PROP_ALLOCATION],
8888 _clutter_actor_update_transition (self, obj_props[PROP_ALLOCATION],
8893 * clutter_actor_set_allocation:
8894 * @self: a #ClutterActor
8895 * @box: a #ClutterActorBox
8896 * @flags: allocation flags
8898 * Stores the allocation of @self as defined by @box.
8900 * This function can only be called from within the implementation of
8901 * the #ClutterActorClass.allocate() virtual function.
8903 * The allocation should have been adjusted to take into account constraints,
8904 * alignment, and margin properties. If you are implementing a #ClutterActor
8905 * subclass that provides its own layout management policy for its children
8906 * instead of using a #ClutterLayoutManager delegate, you should not call
8907 * this function on the children of @self; instead, you should call
8908 * clutter_actor_allocate(), which will adjust the allocation box for
8911 * This function should only be used by subclasses of #ClutterActor
8912 * that wish to store their allocation but cannot chain up to the
8913 * parent's implementation; the default implementation of the
8914 * #ClutterActorClass.allocate() virtual function will call this
8917 * It is important to note that, while chaining up was the recommended
8918 * behaviour for #ClutterActor subclasses prior to the introduction of
8919 * this function, it is recommended to call clutter_actor_set_allocation()
8922 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8923 * to handle the allocation of its children, this function will call
8924 * the clutter_layout_manager_allocate() function only if the
8925 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8926 * expected that the subclass will call clutter_layout_manager_allocate()
8927 * by itself. For instance, the following code:
8931 * my_actor_allocate (ClutterActor *actor,
8932 * const ClutterActorBox *allocation,
8933 * ClutterAllocationFlags flags)
8935 * ClutterActorBox new_alloc;
8936 * ClutterAllocationFlags new_flags;
8938 * adjust_allocation (allocation, &new_alloc);
8940 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8942 * /* this will use the layout manager set on the actor */
8943 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8947 * is equivalent to this:
8951 * my_actor_allocate (ClutterActor *actor,
8952 * const ClutterActorBox *allocation,
8953 * ClutterAllocationFlags flags)
8955 * ClutterLayoutManager *layout;
8956 * ClutterActorBox new_alloc;
8958 * adjust_allocation (allocation, &new_alloc);
8960 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8962 * layout = clutter_actor_get_layout_manager (actor);
8963 * clutter_layout_manager_allocate (layout,
8964 * CLUTTER_CONTAINER (actor),
8973 clutter_actor_set_allocation (ClutterActor *self,
8974 const ClutterActorBox *box,
8975 ClutterAllocationFlags flags)
8977 ClutterActorPrivate *priv;
8980 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8981 g_return_if_fail (box != NULL);
8983 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8985 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8986 "can only be called from within the implementation of "
8987 "the ClutterActor::allocate() virtual function.");
8993 g_object_freeze_notify (G_OBJECT (self));
8995 changed = clutter_actor_set_allocation_internal (self, box, flags);
8997 /* we allocate our children before we notify changes in our geometry,
8998 * so that people connecting to properties will be able to get valid
8999 * data out of the sub-tree of the scene graph that has this actor at
9002 clutter_actor_maybe_layout_children (self, box, flags);
9006 ClutterActorBox signal_box = priv->allocation;
9007 ClutterAllocationFlags signal_flags = priv->allocation_flags;
9009 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
9014 g_object_thaw_notify (G_OBJECT (self));
9018 * clutter_actor_set_geometry:
9019 * @self: A #ClutterActor
9020 * @geometry: A #ClutterGeometry
9022 * Sets the actor's fixed position and forces its minimum and natural
9023 * size, in pixels. This means the untransformed actor will have the
9024 * given geometry. This is the same as calling clutter_actor_set_position()
9025 * and clutter_actor_set_size().
9027 * Deprecated: 1.10: Use clutter_actor_set_position() and
9028 * clutter_actor_set_size() instead.
9031 clutter_actor_set_geometry (ClutterActor *self,
9032 const ClutterGeometry *geometry)
9034 g_object_freeze_notify (G_OBJECT (self));
9036 clutter_actor_set_position (self, geometry->x, geometry->y);
9037 clutter_actor_set_size (self, geometry->width, geometry->height);
9039 g_object_thaw_notify (G_OBJECT (self));
9043 * clutter_actor_get_geometry:
9044 * @self: A #ClutterActor
9045 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
9047 * Gets the size and position of an actor relative to its parent
9048 * actor. This is the same as calling clutter_actor_get_position() and
9049 * clutter_actor_get_size(). It tries to "do what you mean" and get the
9050 * requested size and position if the actor's allocation is invalid.
9052 * Deprecated: 1.10: Use clutter_actor_get_position() and
9053 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
9057 clutter_actor_get_geometry (ClutterActor *self,
9058 ClutterGeometry *geometry)
9060 gfloat x, y, width, height;
9062 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9063 g_return_if_fail (geometry != NULL);
9065 clutter_actor_get_position (self, &x, &y);
9066 clutter_actor_get_size (self, &width, &height);
9068 geometry->x = (int) x;
9069 geometry->y = (int) y;
9070 geometry->width = (int) width;
9071 geometry->height = (int) height;
9075 * clutter_actor_set_position:
9076 * @self: A #ClutterActor
9077 * @x: New left position of actor in pixels.
9078 * @y: New top position of actor in pixels.
9080 * Sets the actor's fixed position in pixels relative to any parent
9083 * If a layout manager is in use, this position will override the
9084 * layout manager and force a fixed position.
9087 clutter_actor_set_position (ClutterActor *self,
9091 ClutterPoint new_position;
9093 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9095 clutter_point_init (&new_position, x, y);
9097 if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
9099 ClutterPoint cur_position;
9101 cur_position.x = clutter_actor_get_x (self);
9102 cur_position.y = clutter_actor_get_y (self);
9104 _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
9109 _clutter_actor_update_transition (self,
9110 obj_props[PROP_POSITION],
9113 clutter_actor_queue_relayout (self);
9117 * clutter_actor_get_fixed_position_set:
9118 * @self: A #ClutterActor
9120 * Checks whether an actor has a fixed position set (and will thus be
9121 * unaffected by any layout manager).
9123 * Return value: %TRUE if the fixed position is set on the actor
9128 clutter_actor_get_fixed_position_set (ClutterActor *self)
9130 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9132 return self->priv->position_set;
9136 * clutter_actor_set_fixed_position_set:
9137 * @self: A #ClutterActor
9138 * @is_set: whether to use fixed position
9140 * Sets whether an actor has a fixed position set (and will thus be
9141 * unaffected by any layout manager).
9146 clutter_actor_set_fixed_position_set (ClutterActor *self,
9149 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9151 if (self->priv->position_set == (is_set != FALSE))
9156 ClutterLayoutInfo *info;
9158 /* Ensure we set back the default fixed position of 0,0 so that setting
9159 just one of x/y always atomically gets 0 for the other */
9160 info = _clutter_actor_peek_layout_info (self);
9163 info->fixed_pos.x = 0;
9164 info->fixed_pos.y = 0;
9168 self->priv->position_set = is_set != FALSE;
9169 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9171 clutter_actor_queue_relayout (self);
9175 * clutter_actor_move_by:
9176 * @self: A #ClutterActor
9177 * @dx: Distance to move Actor on X axis.
9178 * @dy: Distance to move Actor on Y axis.
9180 * Moves an actor by the specified distance relative to its current
9181 * position in pixels.
9183 * This function modifies the fixed position of an actor and thus removes
9184 * it from any layout management. Another way to move an actor is with an
9185 * anchor point, see clutter_actor_set_anchor_point().
9190 clutter_actor_move_by (ClutterActor *self,
9194 const ClutterLayoutInfo *info;
9197 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9199 info = _clutter_actor_get_layout_info_or_defaults (self);
9200 x = info->fixed_pos.x;
9201 y = info->fixed_pos.y;
9203 clutter_actor_set_position (self, x + dx, y + dy);
9207 clutter_actor_set_min_width (ClutterActor *self,
9210 ClutterActorPrivate *priv = self->priv;
9211 ClutterActorBox old = { 0, };
9212 ClutterLayoutInfo *info;
9214 /* if we are setting the size on a top-level actor and the
9215 * backend only supports static top-levels (e.g. framebuffers)
9216 * then we ignore the passed value and we override it with
9217 * the stage implementation's preferred size.
9219 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9220 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9223 info = _clutter_actor_get_layout_info (self);
9225 if (priv->min_width_set && min_width == info->minimum.width)
9228 g_object_freeze_notify (G_OBJECT (self));
9230 clutter_actor_store_old_geometry (self, &old);
9232 info->minimum.width = min_width;
9233 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9234 clutter_actor_set_min_width_set (self, TRUE);
9236 clutter_actor_notify_if_geometry_changed (self, &old);
9238 g_object_thaw_notify (G_OBJECT (self));
9240 clutter_actor_queue_relayout (self);
9244 clutter_actor_set_min_height (ClutterActor *self,
9248 ClutterActorPrivate *priv = self->priv;
9249 ClutterActorBox old = { 0, };
9250 ClutterLayoutInfo *info;
9252 /* if we are setting the size on a top-level actor and the
9253 * backend only supports static top-levels (e.g. framebuffers)
9254 * then we ignore the passed value and we override it with
9255 * the stage implementation's preferred size.
9257 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9258 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9261 info = _clutter_actor_get_layout_info (self);
9263 if (priv->min_height_set && min_height == info->minimum.height)
9266 g_object_freeze_notify (G_OBJECT (self));
9268 clutter_actor_store_old_geometry (self, &old);
9270 info->minimum.height = min_height;
9271 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9272 clutter_actor_set_min_height_set (self, TRUE);
9274 clutter_actor_notify_if_geometry_changed (self, &old);
9276 g_object_thaw_notify (G_OBJECT (self));
9278 clutter_actor_queue_relayout (self);
9282 clutter_actor_set_natural_width (ClutterActor *self,
9283 gfloat natural_width)
9285 ClutterActorPrivate *priv = self->priv;
9286 ClutterActorBox old = { 0, };
9287 ClutterLayoutInfo *info;
9289 /* if we are setting the size on a top-level actor and the
9290 * backend only supports static top-levels (e.g. framebuffers)
9291 * then we ignore the passed value and we override it with
9292 * the stage implementation's preferred size.
9294 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9295 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9298 info = _clutter_actor_get_layout_info (self);
9300 if (priv->natural_width_set && natural_width == info->natural.width)
9303 g_object_freeze_notify (G_OBJECT (self));
9305 clutter_actor_store_old_geometry (self, &old);
9307 info->natural.width = natural_width;
9308 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9309 clutter_actor_set_natural_width_set (self, TRUE);
9311 clutter_actor_notify_if_geometry_changed (self, &old);
9313 g_object_thaw_notify (G_OBJECT (self));
9315 clutter_actor_queue_relayout (self);
9319 clutter_actor_set_natural_height (ClutterActor *self,
9320 gfloat natural_height)
9322 ClutterActorPrivate *priv = self->priv;
9323 ClutterActorBox old = { 0, };
9324 ClutterLayoutInfo *info;
9326 /* if we are setting the size on a top-level actor and the
9327 * backend only supports static top-levels (e.g. framebuffers)
9328 * then we ignore the passed value and we override it with
9329 * the stage implementation's preferred size.
9331 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9332 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9335 info = _clutter_actor_get_layout_info (self);
9337 if (priv->natural_height_set && natural_height == info->natural.height)
9340 g_object_freeze_notify (G_OBJECT (self));
9342 clutter_actor_store_old_geometry (self, &old);
9344 info->natural.height = natural_height;
9345 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9346 clutter_actor_set_natural_height_set (self, TRUE);
9348 clutter_actor_notify_if_geometry_changed (self, &old);
9350 g_object_thaw_notify (G_OBJECT (self));
9352 clutter_actor_queue_relayout (self);
9356 clutter_actor_set_min_width_set (ClutterActor *self,
9357 gboolean use_min_width)
9359 ClutterActorPrivate *priv = self->priv;
9360 ClutterActorBox old = { 0, };
9362 if (priv->min_width_set == (use_min_width != FALSE))
9365 clutter_actor_store_old_geometry (self, &old);
9367 priv->min_width_set = use_min_width != FALSE;
9368 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9370 clutter_actor_notify_if_geometry_changed (self, &old);
9372 clutter_actor_queue_relayout (self);
9376 clutter_actor_set_min_height_set (ClutterActor *self,
9377 gboolean use_min_height)
9379 ClutterActorPrivate *priv = self->priv;
9380 ClutterActorBox old = { 0, };
9382 if (priv->min_height_set == (use_min_height != FALSE))
9385 clutter_actor_store_old_geometry (self, &old);
9387 priv->min_height_set = use_min_height != FALSE;
9388 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9390 clutter_actor_notify_if_geometry_changed (self, &old);
9392 clutter_actor_queue_relayout (self);
9396 clutter_actor_set_natural_width_set (ClutterActor *self,
9397 gboolean use_natural_width)
9399 ClutterActorPrivate *priv = self->priv;
9400 ClutterActorBox old = { 0, };
9402 if (priv->natural_width_set == (use_natural_width != FALSE))
9405 clutter_actor_store_old_geometry (self, &old);
9407 priv->natural_width_set = use_natural_width != FALSE;
9408 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9410 clutter_actor_notify_if_geometry_changed (self, &old);
9412 clutter_actor_queue_relayout (self);
9416 clutter_actor_set_natural_height_set (ClutterActor *self,
9417 gboolean use_natural_height)
9419 ClutterActorPrivate *priv = self->priv;
9420 ClutterActorBox old = { 0, };
9422 if (priv->natural_height_set == (use_natural_height != FALSE))
9425 clutter_actor_store_old_geometry (self, &old);
9427 priv->natural_height_set = use_natural_height != FALSE;
9428 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9430 clutter_actor_notify_if_geometry_changed (self, &old);
9432 clutter_actor_queue_relayout (self);
9436 * clutter_actor_set_request_mode:
9437 * @self: a #ClutterActor
9438 * @mode: the request mode
9440 * Sets the geometry request mode of @self.
9442 * The @mode determines the order for invoking
9443 * clutter_actor_get_preferred_width() and
9444 * clutter_actor_get_preferred_height()
9449 clutter_actor_set_request_mode (ClutterActor *self,
9450 ClutterRequestMode mode)
9452 ClutterActorPrivate *priv;
9454 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9458 if (priv->request_mode == mode)
9461 priv->request_mode = mode;
9463 priv->needs_width_request = TRUE;
9464 priv->needs_height_request = TRUE;
9466 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9468 clutter_actor_queue_relayout (self);
9472 * clutter_actor_get_request_mode:
9473 * @self: a #ClutterActor
9475 * Retrieves the geometry request mode of @self
9477 * Return value: the request mode for the actor
9482 clutter_actor_get_request_mode (ClutterActor *self)
9484 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9485 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9487 return self->priv->request_mode;
9490 /* variant of set_width() without checks and without notification
9491 * freeze+thaw, for internal usage only
9494 clutter_actor_set_width_internal (ClutterActor *self,
9499 /* the Stage will use the :min-width to control the minimum
9500 * width to be resized to, so we should not be setting it
9501 * along with the :natural-width
9503 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9504 clutter_actor_set_min_width (self, width);
9506 clutter_actor_set_natural_width (self, width);
9510 /* we only unset the :natural-width for the Stage */
9511 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9512 clutter_actor_set_min_width_set (self, FALSE);
9514 clutter_actor_set_natural_width_set (self, FALSE);
9518 /* variant of set_height() without checks and without notification
9519 * freeze+thaw, for internal usage only
9522 clutter_actor_set_height_internal (ClutterActor *self,
9527 /* see the comment above in set_width_internal() */
9528 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9529 clutter_actor_set_min_height (self, height);
9531 clutter_actor_set_natural_height (self, height);
9535 /* see the comment above in set_width_internal() */
9536 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9537 clutter_actor_set_min_height_set (self, FALSE);
9539 clutter_actor_set_natural_height_set (self, FALSE);
9544 clutter_actor_set_size_internal (ClutterActor *self,
9545 const ClutterSize *size)
9549 clutter_actor_set_width_internal (self, size->width);
9550 clutter_actor_set_height_internal (self, size->height);
9554 clutter_actor_set_width_internal (self, -1);
9555 clutter_actor_set_height_internal (self, -1);
9560 * clutter_actor_set_size:
9561 * @self: A #ClutterActor
9562 * @width: New width of actor in pixels, or -1
9563 * @height: New height of actor in pixels, or -1
9565 * Sets the actor's size request in pixels. This overrides any
9566 * "normal" size request the actor would have. For example
9567 * a text actor might normally request the size of the text;
9568 * this function would force a specific size instead.
9570 * If @width and/or @height are -1 the actor will use its
9571 * "normal" size request instead of overriding it, i.e.
9572 * you can "unset" the size with -1.
9574 * This function sets or unsets both the minimum and natural size.
9577 clutter_actor_set_size (ClutterActor *self,
9581 ClutterSize new_size;
9583 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9585 clutter_size_init (&new_size, width, height);
9587 if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9589 /* minor optimization: if we don't have a duration then we can
9590 * skip the get_size() below, to avoid the chance of going through
9591 * get_preferred_width() and get_preferred_height() just to jump to
9592 * a new desired size
9594 if (clutter_actor_get_easing_duration (self) == 0)
9596 g_object_freeze_notify (G_OBJECT (self));
9598 clutter_actor_set_size_internal (self, &new_size);
9600 g_object_thaw_notify (G_OBJECT (self));
9606 ClutterSize cur_size;
9608 clutter_size_init (&cur_size,
9609 clutter_actor_get_width (self),
9610 clutter_actor_get_height (self));
9612 _clutter_actor_create_transition (self,
9613 obj_props[PROP_SIZE],
9619 _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9621 clutter_actor_queue_relayout (self);
9625 * clutter_actor_get_size:
9626 * @self: A #ClutterActor
9627 * @width: (out) (allow-none): return location for the width, or %NULL.
9628 * @height: (out) (allow-none): return location for the height, or %NULL.
9630 * This function tries to "do what you mean" and return
9631 * the size an actor will have. If the actor has a valid
9632 * allocation, the allocation will be returned; otherwise,
9633 * the actors natural size request will be returned.
9635 * If you care whether you get the request vs. the allocation, you
9636 * should probably call a different function like
9637 * clutter_actor_get_allocation_box() or
9638 * clutter_actor_get_preferred_width().
9643 clutter_actor_get_size (ClutterActor *self,
9647 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9650 *width = clutter_actor_get_width (self);
9653 *height = clutter_actor_get_height (self);
9657 * clutter_actor_get_position:
9658 * @self: a #ClutterActor
9659 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9660 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9662 * This function tries to "do what you mean" and tell you where the
9663 * actor is, prior to any transformations. Retrieves the fixed
9664 * position of an actor in pixels, if one has been set; otherwise, if
9665 * the allocation is valid, returns the actor's allocated position;
9666 * otherwise, returns 0,0.
9668 * The returned position is in pixels.
9673 clutter_actor_get_position (ClutterActor *self,
9677 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9680 *x = clutter_actor_get_x (self);
9683 *y = clutter_actor_get_y (self);
9687 * clutter_actor_get_transformed_position:
9688 * @self: A #ClutterActor
9689 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9690 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9692 * Gets the absolute position of an actor, in pixels relative to the stage.
9697 clutter_actor_get_transformed_position (ClutterActor *self,
9704 v1.x = v1.y = v1.z = 0;
9705 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9715 * clutter_actor_get_transformed_size:
9716 * @self: A #ClutterActor
9717 * @width: (out) (allow-none): return location for the width, or %NULL
9718 * @height: (out) (allow-none): return location for the height, or %NULL
9720 * Gets the absolute size of an actor in pixels, taking into account the
9723 * If the actor has a valid allocation, the allocated size will be used.
9724 * If the actor has not a valid allocation then the preferred size will
9725 * be transformed and returned.
9727 * If you want the transformed allocation, see
9728 * clutter_actor_get_abs_allocation_vertices() instead.
9730 * <note>When the actor (or one of its ancestors) is rotated around the
9731 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9732 * as a generic quadrangle; in that case this function returns the size
9733 * of the smallest rectangle that encapsulates the entire quad. Please
9734 * note that in this case no assumptions can be made about the relative
9735 * position of this envelope to the absolute position of the actor, as
9736 * returned by clutter_actor_get_transformed_position(); if you need this
9737 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9738 * to get the coords of the actual quadrangle.</note>
9743 clutter_actor_get_transformed_size (ClutterActor *self,
9747 ClutterActorPrivate *priv;
9749 gfloat x_min, x_max, y_min, y_max;
9752 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9756 /* if the actor hasn't been allocated yet, get the preferred
9757 * size and transform that
9759 if (priv->needs_allocation)
9761 gfloat natural_width, natural_height;
9762 ClutterActorBox box;
9764 /* Make a fake allocation to transform.
9766 * NB: _clutter_actor_transform_and_project_box expects a box in
9767 * the actor's coordinate space... */
9772 natural_width = natural_height = 0;
9773 clutter_actor_get_preferred_size (self, NULL, NULL,
9777 box.x2 = natural_width;
9778 box.y2 = natural_height;
9780 _clutter_actor_transform_and_project_box (self, &box, v);
9783 clutter_actor_get_abs_allocation_vertices (self, v);
9785 x_min = x_max = v[0].x;
9786 y_min = y_max = v[0].y;
9788 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9804 *width = x_max - x_min;
9807 *height = y_max - y_min;
9811 * clutter_actor_get_width:
9812 * @self: A #ClutterActor
9814 * Retrieves the width of a #ClutterActor.
9816 * If the actor has a valid allocation, this function will return the
9817 * width of the allocated area given to the actor.
9819 * If the actor does not have a valid allocation, this function will
9820 * return the actor's natural width, that is the preferred width of
9823 * If you care whether you get the preferred width or the width that
9824 * has been assigned to the actor, you should probably call a different
9825 * function like clutter_actor_get_allocation_box() to retrieve the
9826 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9829 * If an actor has a fixed width, for instance a width that has been
9830 * assigned using clutter_actor_set_width(), the width returned will
9831 * be the same value.
9833 * Return value: the width of the actor, in pixels
9836 clutter_actor_get_width (ClutterActor *self)
9838 ClutterActorPrivate *priv;
9840 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9844 if (priv->needs_allocation)
9846 gfloat natural_width = 0;
9848 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9849 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9852 gfloat natural_height = 0;
9854 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9855 clutter_actor_get_preferred_width (self, natural_height,
9860 return natural_width;
9863 return priv->allocation.x2 - priv->allocation.x1;
9867 * clutter_actor_get_height:
9868 * @self: A #ClutterActor
9870 * Retrieves the height of a #ClutterActor.
9872 * If the actor has a valid allocation, this function will return the
9873 * height of the allocated area given to the actor.
9875 * If the actor does not have a valid allocation, this function will
9876 * return the actor's natural height, that is the preferred height of
9879 * If you care whether you get the preferred height or the height that
9880 * has been assigned to the actor, you should probably call a different
9881 * function like clutter_actor_get_allocation_box() to retrieve the
9882 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9885 * If an actor has a fixed height, for instance a height that has been
9886 * assigned using clutter_actor_set_height(), the height returned will
9887 * be the same value.
9889 * Return value: the height of the actor, in pixels
9892 clutter_actor_get_height (ClutterActor *self)
9894 ClutterActorPrivate *priv;
9896 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9900 if (priv->needs_allocation)
9902 gfloat natural_height = 0;
9904 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9906 gfloat natural_width = 0;
9908 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9909 clutter_actor_get_preferred_height (self, natural_width,
9910 NULL, &natural_height);
9913 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9915 return natural_height;
9918 return priv->allocation.y2 - priv->allocation.y1;
9922 * clutter_actor_set_width:
9923 * @self: A #ClutterActor
9924 * @width: Requested new width for the actor, in pixels, or -1
9926 * Forces a width on an actor, causing the actor's preferred width
9927 * and height (if any) to be ignored.
9929 * If @width is -1 the actor will use its preferred width request
9930 * instead of overriding it, i.e. you can "unset" the width with -1.
9932 * This function sets both the minimum and natural size of the actor.
9937 clutter_actor_set_width (ClutterActor *self,
9940 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9942 if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9946 /* minor optimization: if we don't have a duration
9947 * then we can skip the get_width() below, to avoid
9948 * the chance of going through get_preferred_width()
9949 * just to jump to a new desired width.
9951 if (clutter_actor_get_easing_duration (self) == 0)
9953 g_object_freeze_notify (G_OBJECT (self));
9955 clutter_actor_set_width_internal (self, width);
9957 g_object_thaw_notify (G_OBJECT (self));
9962 cur_size = clutter_actor_get_width (self);
9964 _clutter_actor_create_transition (self,
9965 obj_props[PROP_WIDTH],
9970 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9974 * clutter_actor_set_height:
9975 * @self: A #ClutterActor
9976 * @height: Requested new height for the actor, in pixels, or -1
9978 * Forces a height on an actor, causing the actor's preferred width
9979 * and height (if any) to be ignored.
9981 * If @height is -1 the actor will use its preferred height instead of
9982 * overriding it, i.e. you can "unset" the height with -1.
9984 * This function sets both the minimum and natural size of the actor.
9989 clutter_actor_set_height (ClutterActor *self,
9992 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9994 if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9998 /* see the comment in clutter_actor_set_width() above */
9999 if (clutter_actor_get_easing_duration (self) == 0)
10001 g_object_freeze_notify (G_OBJECT (self));
10003 clutter_actor_set_height_internal (self, height);
10005 g_object_thaw_notify (G_OBJECT (self));
10010 cur_size = clutter_actor_get_height (self);
10012 _clutter_actor_create_transition (self,
10013 obj_props[PROP_HEIGHT],
10018 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
10022 clutter_actor_set_x_internal (ClutterActor *self,
10025 ClutterActorPrivate *priv = self->priv;
10026 ClutterLayoutInfo *linfo;
10027 ClutterActorBox old = { 0, };
10029 linfo = _clutter_actor_get_layout_info (self);
10031 if (priv->position_set && linfo->fixed_pos.x == x)
10034 clutter_actor_store_old_geometry (self, &old);
10036 linfo->fixed_pos.x = x;
10037 clutter_actor_set_fixed_position_set (self, TRUE);
10039 clutter_actor_notify_if_geometry_changed (self, &old);
10041 clutter_actor_queue_relayout (self);
10045 clutter_actor_set_y_internal (ClutterActor *self,
10048 ClutterActorPrivate *priv = self->priv;
10049 ClutterLayoutInfo *linfo;
10050 ClutterActorBox old = { 0, };
10052 linfo = _clutter_actor_get_layout_info (self);
10054 if (priv->position_set && linfo->fixed_pos.y == y)
10057 clutter_actor_store_old_geometry (self, &old);
10059 linfo->fixed_pos.y = y;
10060 clutter_actor_set_fixed_position_set (self, TRUE);
10062 clutter_actor_notify_if_geometry_changed (self, &old);
10064 clutter_actor_queue_relayout (self);
10068 clutter_actor_set_position_internal (ClutterActor *self,
10069 const ClutterPoint *position)
10071 ClutterActorPrivate *priv = self->priv;
10072 ClutterLayoutInfo *linfo;
10073 ClutterActorBox old = { 0, };
10075 linfo = _clutter_actor_get_layout_info (self);
10077 if (priv->position_set &&
10078 clutter_point_equals (position, &linfo->fixed_pos))
10081 clutter_actor_store_old_geometry (self, &old);
10083 if (position != NULL)
10085 linfo->fixed_pos = *position;
10086 clutter_actor_set_fixed_position_set (self, TRUE);
10089 clutter_actor_set_fixed_position_set (self, FALSE);
10091 clutter_actor_notify_if_geometry_changed (self, &old);
10093 clutter_actor_queue_relayout (self);
10097 * clutter_actor_set_x:
10098 * @self: a #ClutterActor
10099 * @x: the actor's position on the X axis
10101 * Sets the actor's X coordinate, relative to its parent, in pixels.
10103 * Overrides any layout manager and forces a fixed position for
10106 * The #ClutterActor:x property is animatable.
10111 clutter_actor_set_x (ClutterActor *self,
10114 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10116 if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
10118 float cur_position = clutter_actor_get_x (self);
10120 _clutter_actor_create_transition (self, obj_props[PROP_X],
10125 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
10129 * clutter_actor_set_y:
10130 * @self: a #ClutterActor
10131 * @y: the actor's position on the Y axis
10133 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
10135 * Overrides any layout manager and forces a fixed position for
10138 * The #ClutterActor:y property is animatable.
10143 clutter_actor_set_y (ClutterActor *self,
10146 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10148 if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
10150 float cur_position = clutter_actor_get_y (self);
10152 _clutter_actor_create_transition (self, obj_props[PROP_Y],
10157 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
10161 * clutter_actor_get_x:
10162 * @self: A #ClutterActor
10164 * Retrieves the X coordinate of a #ClutterActor.
10166 * This function tries to "do what you mean", by returning the
10167 * correct value depending on the actor's state.
10169 * If the actor has a valid allocation, this function will return
10170 * the X coordinate of the origin of the allocation box.
10172 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10173 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10174 * function will return that coordinate.
10176 * If both the allocation and a fixed position are missing, this function
10179 * Return value: the X coordinate, in pixels, ignoring any
10180 * transformation (i.e. scaling, rotation)
10183 clutter_actor_get_x (ClutterActor *self)
10185 ClutterActorPrivate *priv;
10187 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10191 if (priv->needs_allocation)
10193 if (priv->position_set)
10195 const ClutterLayoutInfo *info;
10197 info = _clutter_actor_get_layout_info_or_defaults (self);
10199 return info->fixed_pos.x;
10205 return priv->allocation.x1;
10209 * clutter_actor_get_y:
10210 * @self: A #ClutterActor
10212 * Retrieves the Y coordinate of a #ClutterActor.
10214 * This function tries to "do what you mean", by returning the
10215 * correct value depending on the actor's state.
10217 * If the actor has a valid allocation, this function will return
10218 * the Y coordinate of the origin of the allocation box.
10220 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10221 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10222 * function will return that coordinate.
10224 * If both the allocation and a fixed position are missing, this function
10227 * Return value: the Y coordinate, in pixels, ignoring any
10228 * transformation (i.e. scaling, rotation)
10231 clutter_actor_get_y (ClutterActor *self)
10233 ClutterActorPrivate *priv;
10235 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10239 if (priv->needs_allocation)
10241 if (priv->position_set)
10243 const ClutterLayoutInfo *info;
10245 info = _clutter_actor_get_layout_info_or_defaults (self);
10247 return info->fixed_pos.y;
10253 return priv->allocation.y1;
10257 * clutter_actor_set_scale:
10258 * @self: A #ClutterActor
10259 * @scale_x: double factor to scale actor by horizontally.
10260 * @scale_y: double factor to scale actor by vertically.
10262 * Scales an actor with the given factors. The scaling is relative to
10263 * the scale center and the anchor point. The scale center is
10264 * unchanged by this function and defaults to 0,0.
10266 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10272 clutter_actor_set_scale (ClutterActor *self,
10276 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10278 g_object_freeze_notify (G_OBJECT (self));
10280 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10281 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10283 g_object_thaw_notify (G_OBJECT (self));
10287 * clutter_actor_set_scale_full:
10288 * @self: A #ClutterActor
10289 * @scale_x: double factor to scale actor by horizontally.
10290 * @scale_y: double factor to scale actor by vertically.
10291 * @center_x: X coordinate of the center of the scale.
10292 * @center_y: Y coordinate of the center of the scale
10294 * Scales an actor with the given factors around the given center
10295 * point. The center point is specified in pixels relative to the
10296 * anchor point (usually the top left corner of the actor).
10298 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10304 clutter_actor_set_scale_full (ClutterActor *self,
10310 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10312 g_object_freeze_notify (G_OBJECT (self));
10314 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10315 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10316 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10317 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10319 g_object_thaw_notify (G_OBJECT (self));
10323 * clutter_actor_set_scale_with_gravity:
10324 * @self: A #ClutterActor
10325 * @scale_x: double factor to scale actor by horizontally.
10326 * @scale_y: double factor to scale actor by vertically.
10327 * @gravity: the location of the scale center expressed as a compass
10330 * Scales an actor with the given factors around the given
10331 * center point. The center point is specified as one of the compass
10332 * directions in #ClutterGravity. For example, setting it to north
10333 * will cause the top of the actor to remain unchanged and the rest of
10334 * the actor to expand left, right and downwards.
10336 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10342 clutter_actor_set_scale_with_gravity (ClutterActor *self,
10345 ClutterGravity gravity)
10347 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10349 g_object_freeze_notify (G_OBJECT (self));
10351 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10352 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10353 clutter_actor_set_scale_gravity (self, gravity);
10355 g_object_thaw_notify (G_OBJECT (self));
10359 * clutter_actor_get_scale:
10360 * @self: A #ClutterActor
10361 * @scale_x: (out) (allow-none): Location to store horizonal
10362 * scale factor, or %NULL.
10363 * @scale_y: (out) (allow-none): Location to store vertical
10364 * scale factor, or %NULL.
10366 * Retrieves an actors scale factors.
10371 clutter_actor_get_scale (ClutterActor *self,
10375 const ClutterTransformInfo *info;
10377 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10379 info = _clutter_actor_get_transform_info_or_defaults (self);
10382 *scale_x = info->scale_x;
10385 *scale_y = info->scale_y;
10389 * clutter_actor_get_scale_center:
10390 * @self: A #ClutterActor
10391 * @center_x: (out) (allow-none): Location to store the X position
10392 * of the scale center, or %NULL.
10393 * @center_y: (out) (allow-none): Location to store the Y position
10394 * of the scale center, or %NULL.
10396 * Retrieves the scale center coordinate in pixels relative to the top
10397 * left corner of the actor. If the scale center was specified using a
10398 * #ClutterGravity this will calculate the pixel offset using the
10399 * current size of the actor.
10404 clutter_actor_get_scale_center (ClutterActor *self,
10408 const ClutterTransformInfo *info;
10410 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10412 info = _clutter_actor_get_transform_info_or_defaults (self);
10414 clutter_anchor_coord_get_units (self, &info->scale_center,
10421 * clutter_actor_get_scale_gravity:
10422 * @self: A #ClutterActor
10424 * Retrieves the scale center as a compass direction. If the scale
10425 * center was specified in pixels or units this will return
10426 * %CLUTTER_GRAVITY_NONE.
10428 * Return value: the scale gravity
10433 clutter_actor_get_scale_gravity (ClutterActor *self)
10435 const ClutterTransformInfo *info;
10437 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10439 info = _clutter_actor_get_transform_info_or_defaults (self);
10441 return clutter_anchor_coord_get_gravity (&info->scale_center);
10445 clutter_actor_set_opacity_internal (ClutterActor *self,
10448 ClutterActorPrivate *priv = self->priv;
10450 if (priv->opacity != opacity)
10452 priv->opacity = opacity;
10454 /* Queue a redraw from the flatten effect so that it can use
10455 its cached image if available instead of having to redraw the
10456 actual actor. If it doesn't end up using the FBO then the
10457 effect is still able to continue the paint anyway. If there
10458 is no flatten effect yet then this is equivalent to queueing
10460 _clutter_actor_queue_redraw_full (self,
10463 priv->flatten_effect);
10465 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10470 * clutter_actor_set_opacity:
10471 * @self: A #ClutterActor
10472 * @opacity: New opacity value for the actor.
10474 * Sets the actor's opacity, with zero being completely transparent and
10475 * 255 (0xff) being fully opaque.
10477 * The #ClutterActor:opacity property is animatable.
10480 clutter_actor_set_opacity (ClutterActor *self,
10483 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10485 if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10487 _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10488 self->priv->opacity,
10492 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10496 * clutter_actor_get_paint_opacity_internal:
10497 * @self: a #ClutterActor
10499 * Retrieves the absolute opacity of the actor, as it appears on the stage
10501 * This function does not do type checks
10503 * Return value: the absolute opacity of the actor
10506 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10508 ClutterActorPrivate *priv = self->priv;
10509 ClutterActor *parent;
10511 /* override the top-level opacity to always be 255; even in
10512 * case of ClutterStage:use-alpha being TRUE we want the rest
10513 * of the scene to be painted
10515 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10518 if (priv->opacity_override >= 0)
10519 return priv->opacity_override;
10521 parent = priv->parent;
10523 /* Factor in the actual actors opacity with parents */
10524 if (parent != NULL)
10526 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10528 if (opacity != 0xff)
10529 return (opacity * priv->opacity) / 0xff;
10532 return priv->opacity;
10537 * clutter_actor_get_paint_opacity:
10538 * @self: A #ClutterActor
10540 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10542 * This function traverses the hierarchy chain and composites the opacity of
10543 * the actor with that of its parents.
10545 * This function is intended for subclasses to use in the paint virtual
10546 * function, to paint themselves with the correct opacity.
10548 * Return value: The actor opacity value.
10553 clutter_actor_get_paint_opacity (ClutterActor *self)
10555 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10557 return clutter_actor_get_paint_opacity_internal (self);
10561 * clutter_actor_get_opacity:
10562 * @self: a #ClutterActor
10564 * Retrieves the opacity value of an actor, as set by
10565 * clutter_actor_set_opacity().
10567 * For retrieving the absolute opacity of the actor inside a paint
10568 * virtual function, see clutter_actor_get_paint_opacity().
10570 * Return value: the opacity of the actor
10573 clutter_actor_get_opacity (ClutterActor *self)
10575 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10577 return self->priv->opacity;
10581 * clutter_actor_set_offscreen_redirect:
10582 * @self: A #ClutterActor
10583 * @redirect: New offscreen redirect flags for the actor.
10585 * Defines the circumstances where the actor should be redirected into
10586 * an offscreen image. The offscreen image is used to flatten the
10587 * actor into a single image while painting for two main reasons.
10588 * Firstly, when the actor is painted a second time without any of its
10589 * contents changing it can simply repaint the cached image without
10590 * descending further down the actor hierarchy. Secondly, it will make
10591 * the opacity look correct even if there are overlapping primitives
10594 * Caching the actor could in some cases be a performance win and in
10595 * some cases be a performance lose so it is important to determine
10596 * which value is right for an actor before modifying this value. For
10597 * example, there is never any reason to flatten an actor that is just
10598 * a single texture (such as a #ClutterTexture) because it is
10599 * effectively already cached in an image so the offscreen would be
10600 * redundant. Also if the actor contains primitives that are far apart
10601 * with a large transparent area in the middle (such as a large
10602 * CluterGroup with a small actor in the top left and a small actor in
10603 * the bottom right) then the cached image will contain the entire
10604 * image of the large area and the paint will waste time blending all
10605 * of the transparent pixels in the middle.
10607 * The default method of implementing opacity on a container simply
10608 * forwards on the opacity to all of the children. If the children are
10609 * overlapping then it will appear as if they are two separate glassy
10610 * objects and there will be a break in the color where they
10611 * overlap. By redirecting to an offscreen buffer it will be as if the
10612 * two opaque objects are combined into one and then made transparent
10613 * which is usually what is expected.
10615 * The image below demonstrates the difference between redirecting and
10616 * not. The image shows two Clutter groups, each containing a red and
10617 * a green rectangle which overlap. The opacity on the group is set to
10618 * 128 (which is 50%). When the offscreen redirect is not used, the
10619 * red rectangle can be seen through the blue rectangle as if the two
10620 * rectangles were separately transparent. When the redirect is used
10621 * the group as a whole is transparent instead so the red rectangle is
10622 * not visible where they overlap.
10624 * <figure id="offscreen-redirect">
10625 * <title>Sample of using an offscreen redirect for transparency</title>
10626 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10629 * The default value for this property is 0, so we effectively will
10630 * never redirect an actor offscreen by default. This means that there
10631 * are times that transparent actors may look glassy as described
10632 * above. The reason this is the default is because there is a
10633 * performance trade off between quality and performance here. In many
10634 * cases the default form of glassy opacity looks good enough, but if
10635 * it's not you will need to set the
10636 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10637 * redirection for opacity.
10639 * Custom actors that don't contain any overlapping primitives are
10640 * recommended to override the has_overlaps() virtual to return %FALSE
10641 * for maximum efficiency.
10646 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10647 ClutterOffscreenRedirect redirect)
10649 ClutterActorPrivate *priv;
10651 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10655 if (priv->offscreen_redirect != redirect)
10657 priv->offscreen_redirect = redirect;
10659 /* Queue a redraw from the effect so that it can use its cached
10660 image if available instead of having to redraw the actual
10661 actor. If it doesn't end up using the FBO then the effect is
10662 still able to continue the paint anyway. If there is no
10663 effect then this is equivalent to queuing a full redraw */
10664 _clutter_actor_queue_redraw_full (self,
10667 priv->flatten_effect);
10669 g_object_notify_by_pspec (G_OBJECT (self),
10670 obj_props[PROP_OFFSCREEN_REDIRECT]);
10675 * clutter_actor_get_offscreen_redirect:
10676 * @self: a #ClutterActor
10678 * Retrieves whether to redirect the actor to an offscreen buffer, as
10679 * set by clutter_actor_set_offscreen_redirect().
10681 * Return value: the value of the offscreen-redirect property of the actor
10685 ClutterOffscreenRedirect
10686 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10688 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10690 return self->priv->offscreen_redirect;
10694 * clutter_actor_set_name:
10695 * @self: A #ClutterActor
10696 * @name: Textual tag to apply to actor
10698 * Sets the given name to @self. The name can be used to identify
10702 clutter_actor_set_name (ClutterActor *self,
10705 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10707 g_free (self->priv->name);
10708 self->priv->name = g_strdup (name);
10710 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10714 * clutter_actor_get_name:
10715 * @self: A #ClutterActor
10717 * Retrieves the name of @self.
10719 * Return value: the name of the actor, or %NULL. The returned string is
10720 * owned by the actor and should not be modified or freed.
10723 clutter_actor_get_name (ClutterActor *self)
10725 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10727 return self->priv->name;
10731 * clutter_actor_get_gid:
10732 * @self: A #ClutterActor
10734 * Retrieves the unique id for @self.
10736 * Return value: Globally unique value for this object instance.
10740 * Deprecated: 1.8: The id is not used any longer.
10743 clutter_actor_get_gid (ClutterActor *self)
10745 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10747 return self->priv->id;
10751 clutter_actor_set_depth_internal (ClutterActor *self,
10754 ClutterTransformInfo *info;
10756 info = _clutter_actor_get_transform_info (self);
10758 if (info->depth != depth)
10760 /* Sets Z value - XXX 2.0: should we invert? */
10761 info->depth = depth;
10763 self->priv->transform_valid = FALSE;
10765 /* FIXME - remove this crap; sadly, there are still containers
10766 * in Clutter that depend on this utter brain damage
10768 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10770 clutter_actor_queue_redraw (self);
10772 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10777 * clutter_actor_set_depth:
10778 * @self: a #ClutterActor
10781 * Sets the Z coordinate of @self to @depth.
10783 * The unit used by @depth is dependant on the perspective setup. See
10784 * also clutter_stage_set_perspective().
10787 clutter_actor_set_depth (ClutterActor *self,
10790 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10792 if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10794 const ClutterTransformInfo *info;
10796 info = _clutter_actor_get_transform_info_or_defaults (self);
10798 _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10803 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10805 clutter_actor_queue_redraw (self);
10809 * clutter_actor_get_depth:
10810 * @self: a #ClutterActor
10812 * Retrieves the depth of @self.
10814 * Return value: the depth of the actor
10817 clutter_actor_get_depth (ClutterActor *self)
10819 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10821 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10825 * clutter_actor_set_rotation:
10826 * @self: a #ClutterActor
10827 * @axis: the axis of rotation
10828 * @angle: the angle of rotation
10829 * @x: X coordinate of the rotation center
10830 * @y: Y coordinate of the rotation center
10831 * @z: Z coordinate of the rotation center
10833 * Sets the rotation angle of @self around the given axis.
10835 * The rotation center coordinates used depend on the value of @axis:
10837 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10838 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10839 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10842 * The rotation coordinates are relative to the anchor point of the
10843 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10844 * point is set, the upper left corner is assumed as the origin.
10849 clutter_actor_set_rotation (ClutterActor *self,
10850 ClutterRotateAxis axis,
10858 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10864 g_object_freeze_notify (G_OBJECT (self));
10866 clutter_actor_set_rotation_angle (self, axis, angle);
10867 clutter_actor_set_rotation_center_internal (self, axis, &v);
10869 g_object_thaw_notify (G_OBJECT (self));
10873 * clutter_actor_set_z_rotation_from_gravity:
10874 * @self: a #ClutterActor
10875 * @angle: the angle of rotation
10876 * @gravity: the center point of the rotation
10878 * Sets the rotation angle of @self around the Z axis using the center
10879 * point specified as a compass point. For example to rotate such that
10880 * the center of the actor remains static you can use
10881 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10882 * will move accordingly.
10887 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10889 ClutterGravity gravity)
10891 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10893 if (gravity == CLUTTER_GRAVITY_NONE)
10894 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10897 GObject *obj = G_OBJECT (self);
10898 ClutterTransformInfo *info;
10900 info = _clutter_actor_get_transform_info (self);
10902 g_object_freeze_notify (obj);
10904 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10906 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10907 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10908 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10910 g_object_thaw_notify (obj);
10915 * clutter_actor_get_rotation:
10916 * @self: a #ClutterActor
10917 * @axis: the axis of rotation
10918 * @x: (out): return value for the X coordinate of the center of rotation
10919 * @y: (out): return value for the Y coordinate of the center of rotation
10920 * @z: (out): return value for the Z coordinate of the center of rotation
10922 * Retrieves the angle and center of rotation on the given axis,
10923 * set using clutter_actor_set_rotation().
10925 * Return value: the angle of rotation
10930 clutter_actor_get_rotation (ClutterActor *self,
10931 ClutterRotateAxis axis,
10936 const ClutterTransformInfo *info;
10937 const AnchorCoord *anchor_coord;
10938 gdouble retval = 0;
10940 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10942 info = _clutter_actor_get_transform_info_or_defaults (self);
10946 case CLUTTER_X_AXIS:
10947 anchor_coord = &info->rx_center;
10948 retval = info->rx_angle;
10951 case CLUTTER_Y_AXIS:
10952 anchor_coord = &info->ry_center;
10953 retval = info->ry_angle;
10956 case CLUTTER_Z_AXIS:
10957 anchor_coord = &info->rz_center;
10958 retval = info->rz_angle;
10962 anchor_coord = NULL;
10967 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10973 * clutter_actor_get_z_rotation_gravity:
10974 * @self: A #ClutterActor
10976 * Retrieves the center for the rotation around the Z axis as a
10977 * compass direction. If the center was specified in pixels or units
10978 * this will return %CLUTTER_GRAVITY_NONE.
10980 * Return value: the Z rotation center
10985 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10987 const ClutterTransformInfo *info;
10989 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10991 info = _clutter_actor_get_transform_info_or_defaults (self);
10993 return clutter_anchor_coord_get_gravity (&info->rz_center);
10997 * clutter_actor_set_clip:
10998 * @self: A #ClutterActor
10999 * @xoff: X offset of the clip rectangle
11000 * @yoff: Y offset of the clip rectangle
11001 * @width: Width of the clip rectangle
11002 * @height: Height of the clip rectangle
11004 * Sets clip area for @self. The clip area is always computed from the
11005 * upper left corner of the actor, even if the anchor point is set
11011 clutter_actor_set_clip (ClutterActor *self,
11017 ClutterActorPrivate *priv;
11019 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11023 if (priv->has_clip &&
11024 priv->clip.x == xoff &&
11025 priv->clip.y == yoff &&
11026 priv->clip.width == width &&
11027 priv->clip.height == height)
11030 priv->clip.x = xoff;
11031 priv->clip.y = yoff;
11032 priv->clip.width = width;
11033 priv->clip.height = height;
11035 priv->has_clip = TRUE;
11037 clutter_actor_queue_redraw (self);
11039 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
11040 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
11044 * clutter_actor_remove_clip:
11045 * @self: A #ClutterActor
11047 * Removes clip area from @self.
11050 clutter_actor_remove_clip (ClutterActor *self)
11052 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11054 if (!self->priv->has_clip)
11057 self->priv->has_clip = FALSE;
11059 clutter_actor_queue_redraw (self);
11061 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
11065 * clutter_actor_has_clip:
11066 * @self: a #ClutterActor
11068 * Determines whether the actor has a clip area set or not.
11070 * Return value: %TRUE if the actor has a clip area set.
11075 clutter_actor_has_clip (ClutterActor *self)
11077 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11079 return self->priv->has_clip;
11083 * clutter_actor_get_clip:
11084 * @self: a #ClutterActor
11085 * @xoff: (out) (allow-none): return location for the X offset of
11086 * the clip rectangle, or %NULL
11087 * @yoff: (out) (allow-none): return location for the Y offset of
11088 * the clip rectangle, or %NULL
11089 * @width: (out) (allow-none): return location for the width of
11090 * the clip rectangle, or %NULL
11091 * @height: (out) (allow-none): return location for the height of
11092 * the clip rectangle, or %NULL
11094 * Gets the clip area for @self, if any is set
11099 clutter_actor_get_clip (ClutterActor *self,
11105 ClutterActorPrivate *priv;
11107 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11111 if (!priv->has_clip)
11115 *xoff = priv->clip.x;
11118 *yoff = priv->clip.y;
11121 *width = priv->clip.width;
11123 if (height != NULL)
11124 *height = priv->clip.height;
11128 * clutter_actor_get_children:
11129 * @self: a #ClutterActor
11131 * Retrieves the list of children of @self.
11133 * Return value: (transfer container) (element-type ClutterActor): A newly
11134 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
11140 clutter_actor_get_children (ClutterActor *self)
11142 ClutterActor *iter;
11145 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11147 /* we walk the list backward so that we can use prepend(),
11150 for (iter = self->priv->last_child, res = NULL;
11152 iter = iter->priv->prev_sibling)
11154 res = g_list_prepend (res, iter);
11161 * insert_child_at_depth:
11162 * @self: a #ClutterActor
11163 * @child: a #ClutterActor
11165 * Inserts @child inside the list of children held by @self, using
11166 * the depth as the insertion criteria.
11168 * This sadly makes the insertion not O(1), but we can keep the
11169 * list sorted so that the painters algorithm we use for painting
11170 * the children will work correctly.
11173 insert_child_at_depth (ClutterActor *self,
11174 ClutterActor *child,
11175 gpointer dummy G_GNUC_UNUSED)
11177 ClutterActor *iter;
11180 child->priv->parent = self;
11183 _clutter_actor_get_transform_info_or_defaults (child)->depth;
11185 /* special-case the first child */
11186 if (self->priv->n_children == 0)
11188 self->priv->first_child = child;
11189 self->priv->last_child = child;
11191 child->priv->next_sibling = NULL;
11192 child->priv->prev_sibling = NULL;
11197 /* Find the right place to insert the child so that it will still be
11198 sorted and the child will be after all of the actors at the same
11200 for (iter = self->priv->first_child;
11202 iter = iter->priv->next_sibling)
11207 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11209 if (iter_depth > child_depth)
11215 ClutterActor *tmp = iter->priv->prev_sibling;
11218 tmp->priv->next_sibling = child;
11220 /* Insert the node before the found one */
11221 child->priv->prev_sibling = iter->priv->prev_sibling;
11222 child->priv->next_sibling = iter;
11223 iter->priv->prev_sibling = child;
11227 ClutterActor *tmp = self->priv->last_child;
11230 tmp->priv->next_sibling = child;
11232 /* insert the node at the end of the list */
11233 child->priv->prev_sibling = self->priv->last_child;
11234 child->priv->next_sibling = NULL;
11237 if (child->priv->prev_sibling == NULL)
11238 self->priv->first_child = child;
11240 if (child->priv->next_sibling == NULL)
11241 self->priv->last_child = child;
11245 insert_child_at_index (ClutterActor *self,
11246 ClutterActor *child,
11249 gint index_ = GPOINTER_TO_INT (data_);
11251 child->priv->parent = self;
11255 ClutterActor *tmp = self->priv->first_child;
11258 tmp->priv->prev_sibling = child;
11260 child->priv->prev_sibling = NULL;
11261 child->priv->next_sibling = tmp;
11263 else if (index_ < 0 || index_ >= self->priv->n_children)
11265 ClutterActor *tmp = self->priv->last_child;
11268 tmp->priv->next_sibling = child;
11270 child->priv->prev_sibling = tmp;
11271 child->priv->next_sibling = NULL;
11275 ClutterActor *iter;
11278 for (iter = self->priv->first_child, i = 0;
11280 iter = iter->priv->next_sibling, i += 1)
11284 ClutterActor *tmp = iter->priv->prev_sibling;
11286 child->priv->prev_sibling = tmp;
11287 child->priv->next_sibling = iter;
11289 iter->priv->prev_sibling = child;
11292 tmp->priv->next_sibling = child;
11299 if (child->priv->prev_sibling == NULL)
11300 self->priv->first_child = child;
11302 if (child->priv->next_sibling == NULL)
11303 self->priv->last_child = child;
11307 insert_child_above (ClutterActor *self,
11308 ClutterActor *child,
11311 ClutterActor *sibling = data;
11313 child->priv->parent = self;
11315 if (sibling == NULL)
11316 sibling = self->priv->last_child;
11318 child->priv->prev_sibling = sibling;
11320 if (sibling != NULL)
11322 ClutterActor *tmp = sibling->priv->next_sibling;
11324 child->priv->next_sibling = tmp;
11327 tmp->priv->prev_sibling = child;
11329 sibling->priv->next_sibling = child;
11332 child->priv->next_sibling = NULL;
11334 if (child->priv->prev_sibling == NULL)
11335 self->priv->first_child = child;
11337 if (child->priv->next_sibling == NULL)
11338 self->priv->last_child = child;
11342 insert_child_below (ClutterActor *self,
11343 ClutterActor *child,
11346 ClutterActor *sibling = data;
11348 child->priv->parent = self;
11350 if (sibling == NULL)
11351 sibling = self->priv->first_child;
11353 child->priv->next_sibling = sibling;
11355 if (sibling != NULL)
11357 ClutterActor *tmp = sibling->priv->prev_sibling;
11359 child->priv->prev_sibling = tmp;
11362 tmp->priv->next_sibling = child;
11364 sibling->priv->prev_sibling = child;
11367 child->priv->prev_sibling = NULL;
11369 if (child->priv->prev_sibling == NULL)
11370 self->priv->first_child = child;
11372 if (child->priv->next_sibling == NULL)
11373 self->priv->last_child = child;
11376 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11377 ClutterActor *child,
11381 ADD_CHILD_CREATE_META = 1 << 0,
11382 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
11383 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
11384 ADD_CHILD_CHECK_STATE = 1 << 3,
11385 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
11386 ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11388 /* default flags for public API */
11389 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
11390 ADD_CHILD_EMIT_PARENT_SET |
11391 ADD_CHILD_EMIT_ACTOR_ADDED |
11392 ADD_CHILD_CHECK_STATE |
11393 ADD_CHILD_NOTIFY_FIRST_LAST |
11394 ADD_CHILD_SHOW_ON_SET_PARENT,
11396 /* flags for legacy/deprecated API */
11397 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
11398 ADD_CHILD_CHECK_STATE |
11399 ADD_CHILD_NOTIFY_FIRST_LAST |
11400 ADD_CHILD_SHOW_ON_SET_PARENT
11401 } ClutterActorAddChildFlags;
11404 * clutter_actor_add_child_internal:
11405 * @self: a #ClutterActor
11406 * @child: a #ClutterActor
11407 * @flags: control flags for actions
11408 * @add_func: delegate function
11409 * @data: (closure): data to pass to @add_func
11411 * Adds @child to the list of children of @self.
11413 * The actual insertion inside the list is delegated to @add_func: this
11414 * function will just set up the state, perform basic checks, and emit
11417 * The @flags argument is used to perform additional operations.
11420 clutter_actor_add_child_internal (ClutterActor *self,
11421 ClutterActor *child,
11422 ClutterActorAddChildFlags flags,
11423 ClutterActorAddChildFunc add_func,
11426 ClutterTextDirection text_dir;
11427 gboolean create_meta;
11428 gboolean emit_parent_set, emit_actor_added;
11429 gboolean check_state;
11430 gboolean notify_first_last;
11431 gboolean show_on_set_parent;
11432 ClutterActor *old_first_child, *old_last_child;
11434 if (child->priv->parent != NULL)
11436 g_warning ("The actor '%s' already has a parent, '%s'. You must "
11437 "use clutter_actor_remove_child() first.",
11438 _clutter_actor_get_debug_name (child),
11439 _clutter_actor_get_debug_name (child->priv->parent));
11443 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11445 g_warning ("The actor '%s' is a top-level actor, and cannot be "
11446 "a child of another actor.",
11447 _clutter_actor_get_debug_name (child));
11452 /* XXX - this check disallows calling methods that change the stacking
11453 * order within the destruction sequence, by triggering a critical
11454 * warning first, and leaving the actor in an undefined state, which
11455 * then ends up being caught by an assertion.
11457 * the reproducible sequence is:
11459 * - actor gets destroyed;
11460 * - another actor, linked to the first, will try to change the
11461 * stacking order of the first actor;
11462 * - changing the stacking order is a composite operation composed
11463 * by the following steps:
11464 * 1. ref() the child;
11465 * 2. remove_child_internal(), which removes the reference;
11466 * 3. add_child_internal(), which adds a reference;
11467 * - the state of the actor is not changed between (2) and (3), as
11468 * it could be an expensive recomputation;
11469 * - if (3) bails out, then the actor is in an undefined state, but
11471 * - the destruction sequence terminates, but the actor is unparented
11472 * while its state indicates being parented instead.
11473 * - assertion failure.
11475 * the obvious fix would be to decompose each set_child_*_sibling()
11476 * method into proper remove_child()/add_child(), with state validation;
11477 * this may cause excessive work, though, and trigger a cascade of other
11478 * bugs in code that assumes that a change in the stacking order is an
11479 * atomic operation.
11481 * another potential fix is to just remove this check here, and let
11482 * code doing stacking order changes inside the destruction sequence
11483 * of an actor continue doing the work.
11485 * the third fix is to silently bail out early from every
11486 * set_child_*_sibling() and set_child_at_index() method, and avoid
11489 * I have a preference for the second solution, since it involves the
11490 * least amount of work, and the least amount of code duplication.
11492 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11494 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11496 g_warning ("The actor '%s' is currently being destroyed, and "
11497 "cannot be added as a child of another actor.",
11498 _clutter_actor_get_debug_name (child));
11503 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11504 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11505 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11506 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11507 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11508 show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11510 old_first_child = self->priv->first_child;
11511 old_last_child = self->priv->last_child;
11513 g_object_freeze_notify (G_OBJECT (self));
11516 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11518 g_object_ref_sink (child);
11519 child->priv->parent = NULL;
11520 child->priv->next_sibling = NULL;
11521 child->priv->prev_sibling = NULL;
11523 /* delegate the actual insertion */
11524 add_func (self, child, data);
11526 g_assert (child->priv->parent == self);
11528 self->priv->n_children += 1;
11530 self->priv->age += 1;
11532 /* if push_internal() has been called then we automatically set
11533 * the flag on the actor
11535 if (self->priv->internal_child)
11536 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11538 /* children may cause their parent to expand, if they are set
11539 * to expand; if a child is not expanded then it cannot change
11540 * its parent's state. any further change later on will queue
11541 * an expand state check.
11543 * this check, with the initial state of the needs_compute_expand
11544 * flag set to FALSE, should avoid recomputing the expand flags
11545 * state while building the actor tree.
11547 if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11548 (child->priv->needs_compute_expand ||
11549 child->priv->needs_x_expand ||
11550 child->priv->needs_y_expand))
11552 clutter_actor_queue_compute_expand (self);
11555 /* clutter_actor_reparent() will emit ::parent-set for us */
11556 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11557 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11561 /* If parent is mapped or realized, we need to also be mapped or
11562 * realized once we're inside the parent.
11564 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11566 /* propagate the parent's text direction to the child */
11567 text_dir = clutter_actor_get_text_direction (self);
11568 clutter_actor_set_text_direction (child, text_dir);
11571 if (show_on_set_parent && child->priv->show_on_set_parent)
11572 clutter_actor_show (child);
11574 if (CLUTTER_ACTOR_IS_MAPPED (child))
11575 clutter_actor_queue_redraw (child);
11577 /* maintain the invariant that if an actor needs layout,
11578 * its parents do as well
11580 if (child->priv->needs_width_request ||
11581 child->priv->needs_height_request ||
11582 child->priv->needs_allocation)
11584 /* we work around the short-circuiting we do
11585 * in clutter_actor_queue_relayout() since we
11586 * want to force a relayout
11588 child->priv->needs_width_request = TRUE;
11589 child->priv->needs_height_request = TRUE;
11590 child->priv->needs_allocation = TRUE;
11592 clutter_actor_queue_relayout (child->priv->parent);
11595 if (emit_actor_added)
11596 g_signal_emit_by_name (self, "actor-added", child);
11598 if (notify_first_last)
11600 if (old_first_child != self->priv->first_child)
11601 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11603 if (old_last_child != self->priv->last_child)
11604 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11607 g_object_thaw_notify (G_OBJECT (self));
11611 * clutter_actor_add_child:
11612 * @self: a #ClutterActor
11613 * @child: a #ClutterActor
11615 * Adds @child to the children of @self.
11617 * This function will acquire a reference on @child that will only
11618 * be released when calling clutter_actor_remove_child().
11620 * This function will take into consideration the #ClutterActor:depth
11621 * of @child, and will keep the list of children sorted.
11623 * This function will emit the #ClutterContainer::actor-added signal
11629 clutter_actor_add_child (ClutterActor *self,
11630 ClutterActor *child)
11632 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11633 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11634 g_return_if_fail (self != child);
11635 g_return_if_fail (child->priv->parent == NULL);
11637 clutter_actor_add_child_internal (self, child,
11638 ADD_CHILD_DEFAULT_FLAGS,
11639 insert_child_at_depth,
11644 * clutter_actor_insert_child_at_index:
11645 * @self: a #ClutterActor
11646 * @child: a #ClutterActor
11647 * @index_: the index
11649 * Inserts @child into the list of children of @self, using the
11650 * given @index_. If @index_ is greater than the number of children
11651 * in @self, or is less than 0, then the new child is added at the end.
11653 * This function will acquire a reference on @child that will only
11654 * be released when calling clutter_actor_remove_child().
11656 * This function will not take into consideration the #ClutterActor:depth
11659 * This function will emit the #ClutterContainer::actor-added signal
11665 clutter_actor_insert_child_at_index (ClutterActor *self,
11666 ClutterActor *child,
11669 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11670 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11671 g_return_if_fail (self != child);
11672 g_return_if_fail (child->priv->parent == NULL);
11674 clutter_actor_add_child_internal (self, child,
11675 ADD_CHILD_DEFAULT_FLAGS,
11676 insert_child_at_index,
11677 GINT_TO_POINTER (index_));
11681 * clutter_actor_insert_child_above:
11682 * @self: a #ClutterActor
11683 * @child: a #ClutterActor
11684 * @sibling: (allow-none): a child of @self, or %NULL
11686 * Inserts @child into the list of children of @self, above another
11687 * child of @self or, if @sibling is %NULL, above all the children
11690 * This function will acquire a reference on @child that will only
11691 * be released when calling clutter_actor_remove_child().
11693 * This function will not take into consideration the #ClutterActor:depth
11696 * This function will emit the #ClutterContainer::actor-added signal
11702 clutter_actor_insert_child_above (ClutterActor *self,
11703 ClutterActor *child,
11704 ClutterActor *sibling)
11706 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11707 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11708 g_return_if_fail (self != child);
11709 g_return_if_fail (child != sibling);
11710 g_return_if_fail (child->priv->parent == NULL);
11711 g_return_if_fail (sibling == NULL ||
11712 (CLUTTER_IS_ACTOR (sibling) &&
11713 sibling->priv->parent == self));
11715 clutter_actor_add_child_internal (self, child,
11716 ADD_CHILD_DEFAULT_FLAGS,
11717 insert_child_above,
11722 * clutter_actor_insert_child_below:
11723 * @self: a #ClutterActor
11724 * @child: a #ClutterActor
11725 * @sibling: (allow-none): a child of @self, or %NULL
11727 * Inserts @child into the list of children of @self, below another
11728 * child of @self or, if @sibling is %NULL, below all the children
11731 * This function will acquire a reference on @child that will only
11732 * be released when calling clutter_actor_remove_child().
11734 * This function will not take into consideration the #ClutterActor:depth
11737 * This function will emit the #ClutterContainer::actor-added signal
11743 clutter_actor_insert_child_below (ClutterActor *self,
11744 ClutterActor *child,
11745 ClutterActor *sibling)
11747 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11748 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11749 g_return_if_fail (self != child);
11750 g_return_if_fail (child != sibling);
11751 g_return_if_fail (child->priv->parent == NULL);
11752 g_return_if_fail (sibling == NULL ||
11753 (CLUTTER_IS_ACTOR (sibling) &&
11754 sibling->priv->parent == self));
11756 clutter_actor_add_child_internal (self, child,
11757 ADD_CHILD_DEFAULT_FLAGS,
11758 insert_child_below,
11763 * clutter_actor_set_parent:
11764 * @self: A #ClutterActor
11765 * @parent: A new #ClutterActor parent
11767 * Sets the parent of @self to @parent.
11769 * This function will result in @parent acquiring a reference on @self,
11770 * eventually by sinking its floating reference first. The reference
11771 * will be released by clutter_actor_unparent().
11773 * This function should only be called by legacy #ClutterActor<!-- -->s
11774 * implementing the #ClutterContainer interface.
11776 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11779 clutter_actor_set_parent (ClutterActor *self,
11780 ClutterActor *parent)
11782 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11783 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11784 g_return_if_fail (self != parent);
11785 g_return_if_fail (self->priv->parent == NULL);
11787 /* as this function will be called inside ClutterContainer::add
11788 * implementations or when building up a composite actor, we have
11789 * to preserve the old behaviour, and not create child meta or
11790 * emit the ::actor-added signal, to avoid recursion or double
11793 clutter_actor_add_child_internal (parent, self,
11794 ADD_CHILD_LEGACY_FLAGS,
11795 insert_child_at_depth,
11800 * clutter_actor_get_parent:
11801 * @self: A #ClutterActor
11803 * Retrieves the parent of @self.
11805 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11806 * if no parent is set
11809 clutter_actor_get_parent (ClutterActor *self)
11811 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11813 return self->priv->parent;
11817 * clutter_actor_get_paint_visibility:
11818 * @self: A #ClutterActor
11820 * Retrieves the 'paint' visibility of an actor recursively checking for non
11823 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11825 * Return Value: %TRUE if the actor is visibile and will be painted.
11830 clutter_actor_get_paint_visibility (ClutterActor *actor)
11832 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11834 return CLUTTER_ACTOR_IS_MAPPED (actor);
11838 * clutter_actor_remove_child:
11839 * @self: a #ClutterActor
11840 * @child: a #ClutterActor
11842 * Removes @child from the children of @self.
11844 * This function will release the reference added by
11845 * clutter_actor_add_child(), so if you want to keep using @child
11846 * you will have to acquire a referenced on it before calling this
11849 * This function will emit the #ClutterContainer::actor-removed
11855 clutter_actor_remove_child (ClutterActor *self,
11856 ClutterActor *child)
11858 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11859 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11860 g_return_if_fail (self != child);
11861 g_return_if_fail (child->priv->parent != NULL);
11862 g_return_if_fail (child->priv->parent == self);
11864 clutter_actor_remove_child_internal (self, child,
11865 REMOVE_CHILD_DEFAULT_FLAGS);
11869 * clutter_actor_remove_all_children:
11870 * @self: a #ClutterActor
11872 * Removes all children of @self.
11874 * This function releases the reference added by inserting a child actor
11875 * in the list of children of @self.
11877 * If the reference count of a child drops to zero, the child will be
11878 * destroyed. If you want to ensure the destruction of all the children
11879 * of @self, use clutter_actor_destroy_all_children().
11884 clutter_actor_remove_all_children (ClutterActor *self)
11886 ClutterActorIter iter;
11888 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11890 if (self->priv->n_children == 0)
11893 g_object_freeze_notify (G_OBJECT (self));
11895 clutter_actor_iter_init (&iter, self);
11896 while (clutter_actor_iter_next (&iter, NULL))
11897 clutter_actor_iter_remove (&iter);
11899 g_object_thaw_notify (G_OBJECT (self));
11902 g_assert (self->priv->first_child == NULL);
11903 g_assert (self->priv->last_child == NULL);
11904 g_assert (self->priv->n_children == 0);
11908 * clutter_actor_destroy_all_children:
11909 * @self: a #ClutterActor
11911 * Destroys all children of @self.
11913 * This function releases the reference added by inserting a child
11914 * actor in the list of children of @self, and ensures that the
11915 * #ClutterActor::destroy signal is emitted on each child of the
11918 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11919 * when its reference count drops to 0; the default handler of the
11920 * #ClutterActor::destroy signal will destroy all the children of an
11921 * actor. This function ensures that all children are destroyed, instead
11922 * of just removed from @self, unlike clutter_actor_remove_all_children()
11923 * which will merely release the reference and remove each child.
11925 * Unless you acquired an additional reference on each child of @self
11926 * prior to calling clutter_actor_remove_all_children() and want to reuse
11927 * the actors, you should use clutter_actor_destroy_all_children() in
11928 * order to make sure that children are destroyed and signal handlers
11929 * are disconnected even in cases where circular references prevent this
11930 * from automatically happening through reference counting alone.
11935 clutter_actor_destroy_all_children (ClutterActor *self)
11937 ClutterActorIter iter;
11939 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11941 if (self->priv->n_children == 0)
11944 g_object_freeze_notify (G_OBJECT (self));
11946 clutter_actor_iter_init (&iter, self);
11947 while (clutter_actor_iter_next (&iter, NULL))
11948 clutter_actor_iter_destroy (&iter);
11950 g_object_thaw_notify (G_OBJECT (self));
11953 g_assert (self->priv->first_child == NULL);
11954 g_assert (self->priv->last_child == NULL);
11955 g_assert (self->priv->n_children == 0);
11958 typedef struct _InsertBetweenData {
11959 ClutterActor *prev_sibling;
11960 ClutterActor *next_sibling;
11961 } InsertBetweenData;
11964 insert_child_between (ClutterActor *self,
11965 ClutterActor *child,
11968 InsertBetweenData *data = data_;
11969 ClutterActor *prev_sibling = data->prev_sibling;
11970 ClutterActor *next_sibling = data->next_sibling;
11972 child->priv->parent = self;
11973 child->priv->prev_sibling = prev_sibling;
11974 child->priv->next_sibling = next_sibling;
11976 if (prev_sibling != NULL)
11977 prev_sibling->priv->next_sibling = child;
11979 if (next_sibling != NULL)
11980 next_sibling->priv->prev_sibling = child;
11982 if (child->priv->prev_sibling == NULL)
11983 self->priv->first_child = child;
11985 if (child->priv->next_sibling == NULL)
11986 self->priv->last_child = child;
11990 * clutter_actor_replace_child:
11991 * @self: a #ClutterActor
11992 * @old_child: the child of @self to replace
11993 * @new_child: the #ClutterActor to replace @old_child
11995 * Replaces @old_child with @new_child in the list of children of @self.
12000 clutter_actor_replace_child (ClutterActor *self,
12001 ClutterActor *old_child,
12002 ClutterActor *new_child)
12004 ClutterActor *prev_sibling, *next_sibling;
12005 InsertBetweenData clos;
12007 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12008 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
12009 g_return_if_fail (old_child->priv->parent == self);
12010 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
12011 g_return_if_fail (old_child != new_child);
12012 g_return_if_fail (new_child != self);
12013 g_return_if_fail (new_child->priv->parent == NULL);
12015 prev_sibling = old_child->priv->prev_sibling;
12016 next_sibling = old_child->priv->next_sibling;
12017 clutter_actor_remove_child_internal (self, old_child,
12018 REMOVE_CHILD_DEFAULT_FLAGS);
12020 clos.prev_sibling = prev_sibling;
12021 clos.next_sibling = next_sibling;
12022 clutter_actor_add_child_internal (self, new_child,
12023 ADD_CHILD_DEFAULT_FLAGS,
12024 insert_child_between,
12029 * clutter_actor_unparent:
12030 * @self: a #ClutterActor
12032 * Removes the parent of @self.
12034 * This will cause the parent of @self to release the reference
12035 * acquired when calling clutter_actor_set_parent(), so if you
12036 * want to keep @self you will have to acquire a reference of
12037 * your own, through g_object_ref().
12039 * This function should only be called by legacy #ClutterActor<!-- -->s
12040 * implementing the #ClutterContainer interface.
12044 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
12047 clutter_actor_unparent (ClutterActor *self)
12049 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12051 if (self->priv->parent == NULL)
12054 clutter_actor_remove_child_internal (self->priv->parent, self,
12055 REMOVE_CHILD_LEGACY_FLAGS);
12059 * clutter_actor_reparent:
12060 * @self: a #ClutterActor
12061 * @new_parent: the new #ClutterActor parent
12063 * Resets the parent actor of @self.
12065 * This function is logically equivalent to calling clutter_actor_unparent()
12066 * and clutter_actor_set_parent(), but more efficiently implemented, as it
12067 * ensures the child is not finalized when unparented, and emits the
12068 * #ClutterActor::parent-set signal only once.
12070 * In reality, calling this function is less useful than it sounds, as some
12071 * application code may rely on changes in the intermediate state between
12072 * removal and addition of the actor from its old parent to the @new_parent.
12073 * Thus, it is strongly encouraged to avoid using this function in application
12078 * Deprecated: 1.10: Use clutter_actor_remove_child() and
12079 * clutter_actor_add_child() instead; remember to take a reference on
12080 * the actor being removed before calling clutter_actor_remove_child()
12081 * to avoid the reference count dropping to zero and the actor being
12085 clutter_actor_reparent (ClutterActor *self,
12086 ClutterActor *new_parent)
12088 ClutterActorPrivate *priv;
12090 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12091 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
12092 g_return_if_fail (self != new_parent);
12094 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
12096 g_warning ("Cannot set a parent on a toplevel actor");
12100 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
12102 g_warning ("Cannot set a parent currently being destroyed");
12108 if (priv->parent != new_parent)
12110 ClutterActor *old_parent;
12112 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12114 old_parent = priv->parent;
12116 g_object_ref (self);
12118 if (old_parent != NULL)
12120 /* go through the Container implementation if this is a regular
12121 * child and not an internal one
12123 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12125 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
12127 /* this will have to call unparent() */
12128 clutter_container_remove_actor (parent, self);
12131 clutter_actor_remove_child_internal (old_parent, self,
12132 REMOVE_CHILD_LEGACY_FLAGS);
12135 /* Note, will call set_parent() */
12136 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12137 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
12139 clutter_actor_add_child_internal (new_parent, self,
12140 ADD_CHILD_LEGACY_FLAGS,
12141 insert_child_at_depth,
12144 /* we emit the ::parent-set signal once */
12145 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
12147 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12149 /* the IN_REPARENT flag suspends state updates */
12150 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
12152 g_object_unref (self);
12157 * clutter_actor_contains:
12158 * @self: A #ClutterActor
12159 * @descendant: A #ClutterActor, possibly contained in @self
12161 * Determines if @descendant is contained inside @self (either as an
12162 * immediate child, or as a deeper descendant). If @self and
12163 * @descendant point to the same actor then it will also return %TRUE.
12165 * Return value: whether @descendent is contained within @self
12170 clutter_actor_contains (ClutterActor *self,
12171 ClutterActor *descendant)
12173 ClutterActor *actor;
12175 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12176 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12178 for (actor = descendant; actor; actor = actor->priv->parent)
12186 * clutter_actor_set_child_above_sibling:
12187 * @self: a #ClutterActor
12188 * @child: a #ClutterActor child of @self
12189 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12191 * Sets @child to be above @sibling in the list of children of @self.
12193 * If @sibling is %NULL, @child will be the new last child of @self.
12195 * This function is logically equivalent to removing @child and using
12196 * clutter_actor_insert_child_above(), but it will not emit signals
12197 * or change state on @child.
12202 clutter_actor_set_child_above_sibling (ClutterActor *self,
12203 ClutterActor *child,
12204 ClutterActor *sibling)
12206 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12207 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12208 g_return_if_fail (child->priv->parent == self);
12209 g_return_if_fail (child != sibling);
12210 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12212 if (sibling != NULL)
12213 g_return_if_fail (sibling->priv->parent == self);
12215 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12216 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12217 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12220 /* we don't want to change the state of child, or emit signals, or
12221 * regenerate ChildMeta instances here, but we still want to follow
12222 * the correct sequence of steps encoded in remove_child() and
12223 * add_child(), so that correctness is ensured, and we only go
12224 * through one known code path.
12226 g_object_ref (child);
12227 clutter_actor_remove_child_internal (self, child, 0);
12228 clutter_actor_add_child_internal (self, child,
12229 ADD_CHILD_NOTIFY_FIRST_LAST,
12230 insert_child_above,
12233 clutter_actor_queue_relayout (self);
12237 * clutter_actor_set_child_below_sibling:
12238 * @self: a #ClutterActor
12239 * @child: a #ClutterActor child of @self
12240 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12242 * Sets @child to be below @sibling in the list of children of @self.
12244 * If @sibling is %NULL, @child will be the new first child of @self.
12246 * This function is logically equivalent to removing @self and using
12247 * clutter_actor_insert_child_below(), but it will not emit signals
12248 * or change state on @child.
12253 clutter_actor_set_child_below_sibling (ClutterActor *self,
12254 ClutterActor *child,
12255 ClutterActor *sibling)
12257 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12258 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12259 g_return_if_fail (child->priv->parent == self);
12260 g_return_if_fail (child != sibling);
12261 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12263 if (sibling != NULL)
12264 g_return_if_fail (sibling->priv->parent == self);
12266 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12267 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12268 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12271 /* see the comment in set_child_above_sibling() */
12272 g_object_ref (child);
12273 clutter_actor_remove_child_internal (self, child, 0);
12274 clutter_actor_add_child_internal (self, child,
12275 ADD_CHILD_NOTIFY_FIRST_LAST,
12276 insert_child_below,
12279 clutter_actor_queue_relayout (self);
12283 * clutter_actor_set_child_at_index:
12284 * @self: a #ClutterActor
12285 * @child: a #ClutterActor child of @self
12286 * @index_: the new index for @child
12288 * Changes the index of @child in the list of children of @self.
12290 * This function is logically equivalent to removing @child and
12291 * calling clutter_actor_insert_child_at_index(), but it will not
12292 * emit signals or change state on @child.
12297 clutter_actor_set_child_at_index (ClutterActor *self,
12298 ClutterActor *child,
12301 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12302 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12303 g_return_if_fail (child->priv->parent == self);
12304 g_return_if_fail (index_ <= self->priv->n_children);
12306 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12307 CLUTTER_ACTOR_IN_DESTRUCTION (child))
12310 g_object_ref (child);
12311 clutter_actor_remove_child_internal (self, child, 0);
12312 clutter_actor_add_child_internal (self, child,
12313 ADD_CHILD_NOTIFY_FIRST_LAST,
12314 insert_child_at_index,
12315 GINT_TO_POINTER (index_));
12317 clutter_actor_queue_relayout (self);
12321 * clutter_actor_raise:
12322 * @self: A #ClutterActor
12323 * @below: (allow-none): A #ClutterActor to raise above.
12325 * Puts @self above @below.
12327 * Both actors must have the same parent, and the parent must implement
12328 * the #ClutterContainer interface
12330 * This function calls clutter_container_raise_child() internally.
12332 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12335 clutter_actor_raise (ClutterActor *self,
12336 ClutterActor *below)
12338 ClutterActor *parent;
12340 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12342 parent = clutter_actor_get_parent (self);
12343 if (parent == NULL)
12345 g_warning ("%s: Actor '%s' is not inside a container",
12347 _clutter_actor_get_debug_name (self));
12353 if (parent != clutter_actor_get_parent (below))
12355 g_warning ("%s Actor '%s' is not in the same container as "
12358 _clutter_actor_get_debug_name (self),
12359 _clutter_actor_get_debug_name (below));
12364 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12368 * clutter_actor_lower:
12369 * @self: A #ClutterActor
12370 * @above: (allow-none): A #ClutterActor to lower below
12372 * Puts @self below @above.
12374 * Both actors must have the same parent, and the parent must implement
12375 * the #ClutterContainer interface.
12377 * This function calls clutter_container_lower_child() internally.
12379 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12382 clutter_actor_lower (ClutterActor *self,
12383 ClutterActor *above)
12385 ClutterActor *parent;
12387 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12389 parent = clutter_actor_get_parent (self);
12390 if (parent == NULL)
12392 g_warning ("%s: Actor of type %s is not inside a container",
12394 _clutter_actor_get_debug_name (self));
12400 if (parent != clutter_actor_get_parent (above))
12402 g_warning ("%s: Actor '%s' is not in the same container as "
12405 _clutter_actor_get_debug_name (self),
12406 _clutter_actor_get_debug_name (above));
12411 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12415 * clutter_actor_raise_top:
12416 * @self: A #ClutterActor
12418 * Raises @self to the top.
12420 * This function calls clutter_actor_raise() internally.
12422 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12423 * a %NULL sibling, instead.
12426 clutter_actor_raise_top (ClutterActor *self)
12428 clutter_actor_raise (self, NULL);
12432 * clutter_actor_lower_bottom:
12433 * @self: A #ClutterActor
12435 * Lowers @self to the bottom.
12437 * This function calls clutter_actor_lower() internally.
12439 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12440 * a %NULL sibling, instead.
12443 clutter_actor_lower_bottom (ClutterActor *self)
12445 clutter_actor_lower (self, NULL);
12453 * clutter_actor_event:
12454 * @actor: a #ClutterActor
12455 * @event: a #ClutterEvent
12456 * @capture: TRUE if event in in capture phase, FALSE otherwise.
12458 * This function is used to emit an event on the main stage.
12459 * You should rarely need to use this function, except for
12460 * synthetising events.
12462 * Return value: the return value from the signal emission: %TRUE
12463 * if the actor handled the event, or %FALSE if the event was
12469 clutter_actor_event (ClutterActor *actor,
12470 ClutterEvent *event,
12473 gboolean retval = FALSE;
12474 gint signal_num = -1;
12476 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12477 g_return_val_if_fail (event != NULL, FALSE);
12479 g_object_ref (actor);
12483 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12489 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12493 switch (event->type)
12495 case CLUTTER_NOTHING:
12497 case CLUTTER_BUTTON_PRESS:
12498 signal_num = BUTTON_PRESS_EVENT;
12500 case CLUTTER_BUTTON_RELEASE:
12501 signal_num = BUTTON_RELEASE_EVENT;
12503 case CLUTTER_SCROLL:
12504 signal_num = SCROLL_EVENT;
12506 case CLUTTER_KEY_PRESS:
12507 signal_num = KEY_PRESS_EVENT;
12509 case CLUTTER_KEY_RELEASE:
12510 signal_num = KEY_RELEASE_EVENT;
12512 case CLUTTER_MOTION:
12513 signal_num = MOTION_EVENT;
12515 case CLUTTER_ENTER:
12516 signal_num = ENTER_EVENT;
12518 case CLUTTER_LEAVE:
12519 signal_num = LEAVE_EVENT;
12521 case CLUTTER_DELETE:
12522 case CLUTTER_DESTROY_NOTIFY:
12523 case CLUTTER_CLIENT_MESSAGE:
12529 if (signal_num != -1)
12530 g_signal_emit (actor, actor_signals[signal_num], 0,
12535 g_object_unref (actor);
12541 * clutter_actor_set_reactive:
12542 * @actor: a #ClutterActor
12543 * @reactive: whether the actor should be reactive to events
12545 * Sets @actor as reactive. Reactive actors will receive events.
12550 clutter_actor_set_reactive (ClutterActor *actor,
12553 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12555 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12559 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12561 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12563 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12567 * clutter_actor_get_reactive:
12568 * @actor: a #ClutterActor
12570 * Checks whether @actor is marked as reactive.
12572 * Return value: %TRUE if the actor is reactive
12577 clutter_actor_get_reactive (ClutterActor *actor)
12579 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12581 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12585 * clutter_actor_get_anchor_point:
12586 * @self: a #ClutterActor
12587 * @anchor_x: (out): return location for the X coordinate of the anchor point
12588 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12590 * Gets the current anchor point of the @actor in pixels.
12595 clutter_actor_get_anchor_point (ClutterActor *self,
12599 const ClutterTransformInfo *info;
12601 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12603 info = _clutter_actor_get_transform_info_or_defaults (self);
12604 clutter_anchor_coord_get_units (self, &info->anchor,
12611 * clutter_actor_set_anchor_point:
12612 * @self: a #ClutterActor
12613 * @anchor_x: X coordinate of the anchor point
12614 * @anchor_y: Y coordinate of the anchor point
12616 * Sets an anchor point for @self. The anchor point is a point in the
12617 * coordinate space of an actor to which the actor position within its
12618 * parent is relative; the default is (0, 0), i.e. the top-left corner
12624 clutter_actor_set_anchor_point (ClutterActor *self,
12628 ClutterTransformInfo *info;
12629 ClutterActorPrivate *priv;
12630 gboolean changed = FALSE;
12631 gfloat old_anchor_x, old_anchor_y;
12634 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12636 obj = G_OBJECT (self);
12638 info = _clutter_actor_get_transform_info (self);
12640 g_object_freeze_notify (obj);
12642 clutter_anchor_coord_get_units (self, &info->anchor,
12647 if (info->anchor.is_fractional)
12648 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12650 if (old_anchor_x != anchor_x)
12652 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12656 if (old_anchor_y != anchor_y)
12658 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12662 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12666 priv->transform_valid = FALSE;
12667 clutter_actor_queue_redraw (self);
12670 g_object_thaw_notify (obj);
12674 * clutter_actor_get_anchor_point_gravity:
12675 * @self: a #ClutterActor
12677 * Retrieves the anchor position expressed as a #ClutterGravity. If
12678 * the anchor point was specified using pixels or units this will
12679 * return %CLUTTER_GRAVITY_NONE.
12681 * Return value: the #ClutterGravity used by the anchor point
12686 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12688 const ClutterTransformInfo *info;
12690 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12692 info = _clutter_actor_get_transform_info_or_defaults (self);
12694 return clutter_anchor_coord_get_gravity (&info->anchor);
12698 * clutter_actor_move_anchor_point:
12699 * @self: a #ClutterActor
12700 * @anchor_x: X coordinate of the anchor point
12701 * @anchor_y: Y coordinate of the anchor point
12703 * Sets an anchor point for the actor, and adjusts the actor postion so that
12704 * the relative position of the actor toward its parent remains the same.
12709 clutter_actor_move_anchor_point (ClutterActor *self,
12713 gfloat old_anchor_x, old_anchor_y;
12714 const ClutterTransformInfo *info;
12716 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12718 info = _clutter_actor_get_transform_info (self);
12719 clutter_anchor_coord_get_units (self, &info->anchor,
12724 g_object_freeze_notify (G_OBJECT (self));
12726 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12728 if (self->priv->position_set)
12729 clutter_actor_move_by (self,
12730 anchor_x - old_anchor_x,
12731 anchor_y - old_anchor_y);
12733 g_object_thaw_notify (G_OBJECT (self));
12737 * clutter_actor_move_anchor_point_from_gravity:
12738 * @self: a #ClutterActor
12739 * @gravity: #ClutterGravity.
12741 * Sets an anchor point on the actor based on the given gravity, adjusting the
12742 * actor postion so that its relative position within its parent remains
12745 * Since version 1.0 the anchor point will be stored as a gravity so
12746 * that if the actor changes size then the anchor point will move. For
12747 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12748 * and later double the size of the actor, the anchor point will move
12749 * to the bottom right.
12754 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12755 ClutterGravity gravity)
12757 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12758 const ClutterTransformInfo *info;
12759 ClutterActorPrivate *priv;
12761 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12764 info = _clutter_actor_get_transform_info (self);
12766 g_object_freeze_notify (G_OBJECT (self));
12768 clutter_anchor_coord_get_units (self, &info->anchor,
12772 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12773 clutter_anchor_coord_get_units (self, &info->anchor,
12778 if (priv->position_set)
12779 clutter_actor_move_by (self,
12780 new_anchor_x - old_anchor_x,
12781 new_anchor_y - old_anchor_y);
12783 g_object_thaw_notify (G_OBJECT (self));
12787 * clutter_actor_set_anchor_point_from_gravity:
12788 * @self: a #ClutterActor
12789 * @gravity: #ClutterGravity.
12791 * Sets an anchor point on the actor, based on the given gravity (this is a
12792 * convenience function wrapping clutter_actor_set_anchor_point()).
12794 * Since version 1.0 the anchor point will be stored as a gravity so
12795 * that if the actor changes size then the anchor point will move. For
12796 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12797 * and later double the size of the actor, the anchor point will move
12798 * to the bottom right.
12803 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12804 ClutterGravity gravity)
12806 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12808 if (gravity == CLUTTER_GRAVITY_NONE)
12809 clutter_actor_set_anchor_point (self, 0, 0);
12812 GObject *obj = G_OBJECT (self);
12813 ClutterTransformInfo *info;
12815 g_object_freeze_notify (obj);
12817 info = _clutter_actor_get_transform_info (self);
12818 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12820 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12821 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12822 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12824 self->priv->transform_valid = FALSE;
12826 clutter_actor_queue_redraw (self);
12828 g_object_thaw_notify (obj);
12833 clutter_actor_store_content_box (ClutterActor *self,
12834 const ClutterActorBox *box)
12838 self->priv->content_box = *box;
12839 self->priv->content_box_valid = TRUE;
12842 self->priv->content_box_valid = FALSE;
12844 clutter_actor_queue_redraw (self);
12846 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12850 clutter_container_iface_init (ClutterContainerIface *iface)
12852 /* we don't override anything, as ClutterContainer already has a default
12853 * implementation that we can use, and which calls into our own API.
12868 parse_units (ClutterActor *self,
12869 ParseDimension dimension,
12872 GValue value = G_VALUE_INIT;
12875 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12878 json_node_get_value (node, &value);
12880 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12882 retval = (gfloat) g_value_get_int64 (&value);
12884 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12886 retval = g_value_get_double (&value);
12888 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12890 ClutterUnits units;
12893 res = clutter_units_from_string (&units, g_value_get_string (&value));
12895 retval = clutter_units_to_pixels (&units);
12898 g_warning ("Invalid value '%s': integers, strings or floating point "
12899 "values can be used for the x, y, width and height "
12900 "properties. Valid modifiers for strings are 'px', 'mm', "
12902 g_value_get_string (&value));
12908 g_warning ("Invalid value of type '%s': integers, strings of floating "
12909 "point values can be used for the x, y, width, height "
12910 "anchor-x and anchor-y properties.",
12911 g_type_name (G_VALUE_TYPE (&value)));
12914 g_value_unset (&value);
12920 ClutterRotateAxis axis;
12929 static inline gboolean
12930 parse_rotation_array (ClutterActor *actor,
12932 RotationInfo *info)
12936 if (json_array_get_length (array) != 2)
12940 element = json_array_get_element (array, 0);
12941 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12942 info->angle = json_node_get_double (element);
12947 element = json_array_get_element (array, 1);
12948 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12950 JsonArray *center = json_node_get_array (element);
12952 if (json_array_get_length (center) != 2)
12955 switch (info->axis)
12957 case CLUTTER_X_AXIS:
12958 info->center_y = parse_units (actor, PARSE_Y,
12959 json_array_get_element (center, 0));
12960 info->center_z = parse_units (actor, PARSE_Y,
12961 json_array_get_element (center, 1));
12964 case CLUTTER_Y_AXIS:
12965 info->center_x = parse_units (actor, PARSE_X,
12966 json_array_get_element (center, 0));
12967 info->center_z = parse_units (actor, PARSE_X,
12968 json_array_get_element (center, 1));
12971 case CLUTTER_Z_AXIS:
12972 info->center_x = parse_units (actor, PARSE_X,
12973 json_array_get_element (center, 0));
12974 info->center_y = parse_units (actor, PARSE_Y,
12975 json_array_get_element (center, 1));
12984 parse_rotation (ClutterActor *actor,
12986 RotationInfo *info)
12990 gboolean retval = FALSE;
12992 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12994 g_warning ("Invalid node of type '%s' found, expecting an array",
12995 json_node_type_name (node));
12999 array = json_node_get_array (node);
13000 len = json_array_get_length (array);
13002 for (i = 0; i < len; i++)
13004 JsonNode *element = json_array_get_element (array, i);
13005 JsonObject *object;
13008 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
13010 g_warning ("Invalid node of type '%s' found, expecting an object",
13011 json_node_type_name (element));
13015 object = json_node_get_object (element);
13017 if (json_object_has_member (object, "x-axis"))
13019 member = json_object_get_member (object, "x-axis");
13021 info->axis = CLUTTER_X_AXIS;
13023 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
13025 info->angle = json_node_get_double (member);
13028 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13029 retval = parse_rotation_array (actor,
13030 json_node_get_array (member),
13035 else if (json_object_has_member (object, "y-axis"))
13037 member = json_object_get_member (object, "y-axis");
13039 info->axis = CLUTTER_Y_AXIS;
13041 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
13043 info->angle = json_node_get_double (member);
13046 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13047 retval = parse_rotation_array (actor,
13048 json_node_get_array (member),
13053 else if (json_object_has_member (object, "z-axis"))
13055 member = json_object_get_member (object, "z-axis");
13057 info->axis = CLUTTER_Z_AXIS;
13059 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
13061 info->angle = json_node_get_double (member);
13064 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13065 retval = parse_rotation_array (actor,
13066 json_node_get_array (member),
13077 parse_actor_metas (ClutterScript *script,
13078 ClutterActor *actor,
13081 GList *elements, *l;
13082 GSList *retval = NULL;
13084 if (!JSON_NODE_HOLDS_ARRAY (node))
13087 elements = json_array_get_elements (json_node_get_array (node));
13089 for (l = elements; l != NULL; l = l->next)
13091 JsonNode *element = l->data;
13092 const gchar *id_ = _clutter_script_get_id_from_node (element);
13095 if (id_ == NULL || *id_ == '\0')
13098 meta = clutter_script_get_object (script, id_);
13102 retval = g_slist_prepend (retval, meta);
13105 g_list_free (elements);
13107 return g_slist_reverse (retval);
13111 parse_behaviours (ClutterScript *script,
13112 ClutterActor *actor,
13115 GList *elements, *l;
13116 GSList *retval = NULL;
13118 if (!JSON_NODE_HOLDS_ARRAY (node))
13121 elements = json_array_get_elements (json_node_get_array (node));
13123 for (l = elements; l != NULL; l = l->next)
13125 JsonNode *element = l->data;
13126 const gchar *id_ = _clutter_script_get_id_from_node (element);
13127 GObject *behaviour;
13129 if (id_ == NULL || *id_ == '\0')
13132 behaviour = clutter_script_get_object (script, id_);
13133 if (behaviour == NULL)
13136 retval = g_slist_prepend (retval, behaviour);
13139 g_list_free (elements);
13141 return g_slist_reverse (retval);
13144 static ClutterMargin *
13145 parse_margin (ClutterActor *self,
13148 ClutterMargin *margin;
13151 if (!JSON_NODE_HOLDS_ARRAY (node))
13153 g_warning ("The margin property must be an array of 1 to 4 elements");
13157 margin = clutter_margin_new ();
13158 array = json_node_get_array (node);
13159 switch (json_array_get_length (array))
13162 margin->top = margin->right = margin->bottom = margin->left =
13163 parse_units (self, 0, json_array_get_element (array, 0));
13167 margin->top = margin->bottom =
13168 parse_units (self, 0, json_array_get_element (array, 0));
13169 margin->right = margin->left =
13170 parse_units (self, 0, json_array_get_element (array, 1));
13175 parse_units (self, 0, json_array_get_element (array, 0));
13176 margin->right = margin->left =
13177 parse_units (self, 0, json_array_get_element (array, 1));
13179 parse_units (self, 0, json_array_get_element (array, 2));
13184 parse_units (self, 0, json_array_get_element (array, 0));
13186 parse_units (self, 0, json_array_get_element (array, 1));
13188 parse_units (self, 0, json_array_get_element (array, 2));
13190 parse_units (self, 0, json_array_get_element (array, 3));
13194 g_warning ("The margin property must be an array of 1 to 4 elements");
13195 clutter_margin_free (margin);
13202 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
13203 ClutterScript *script,
13208 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13209 gboolean retval = FALSE;
13211 if ((name[0] == 'x' && name[1] == '\0') ||
13212 (name[0] == 'y' && name[1] == '\0') ||
13213 (strcmp (name, "width") == 0) ||
13214 (strcmp (name, "height") == 0) ||
13215 (strcmp (name, "anchor_x") == 0) ||
13216 (strcmp (name, "anchor_y") == 0))
13218 ParseDimension dimension;
13221 if (name[0] == 'x')
13222 dimension = PARSE_X;
13223 else if (name[0] == 'y')
13224 dimension = PARSE_Y;
13225 else if (name[0] == 'w')
13226 dimension = PARSE_WIDTH;
13227 else if (name[0] == 'h')
13228 dimension = PARSE_HEIGHT;
13229 else if (name[0] == 'a' && name[7] == 'x')
13230 dimension = PARSE_ANCHOR_X;
13231 else if (name[0] == 'a' && name[7] == 'y')
13232 dimension = PARSE_ANCHOR_Y;
13236 units = parse_units (actor, dimension, node);
13238 /* convert back to pixels: all properties are pixel-based */
13239 g_value_init (value, G_TYPE_FLOAT);
13240 g_value_set_float (value, units);
13244 else if (strcmp (name, "rotation") == 0)
13246 RotationInfo *info;
13248 info = g_slice_new0 (RotationInfo);
13249 retval = parse_rotation (actor, node, info);
13253 g_value_init (value, G_TYPE_POINTER);
13254 g_value_set_pointer (value, info);
13257 g_slice_free (RotationInfo, info);
13259 else if (strcmp (name, "behaviours") == 0)
13263 #ifdef CLUTTER_ENABLE_DEBUG
13264 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13265 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13266 "and it should not be used in newly "
13267 "written ClutterScript definitions.");
13270 l = parse_behaviours (script, actor, node);
13272 g_value_init (value, G_TYPE_POINTER);
13273 g_value_set_pointer (value, l);
13277 else if (strcmp (name, "actions") == 0 ||
13278 strcmp (name, "constraints") == 0 ||
13279 strcmp (name, "effects") == 0)
13283 l = parse_actor_metas (script, actor, node);
13285 g_value_init (value, G_TYPE_POINTER);
13286 g_value_set_pointer (value, l);
13290 else if (strcmp (name, "margin") == 0)
13292 ClutterMargin *margin = parse_margin (actor, node);
13296 g_value_init (value, CLUTTER_TYPE_MARGIN);
13297 g_value_set_boxed (value, margin);
13306 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13307 ClutterScript *script,
13309 const GValue *value)
13311 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13313 #ifdef CLUTTER_ENABLE_DEBUG
13314 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13316 gchar *tmp = g_strdup_value_contents (value);
13318 CLUTTER_NOTE (SCRIPT,
13319 "in ClutterActor::set_custom_property('%s') = %s",
13325 #endif /* CLUTTER_ENABLE_DEBUG */
13327 if (strcmp (name, "rotation") == 0)
13329 RotationInfo *info;
13331 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13334 info = g_value_get_pointer (value);
13336 clutter_actor_set_rotation (actor,
13337 info->axis, info->angle,
13342 g_slice_free (RotationInfo, info);
13347 if (strcmp (name, "behaviours") == 0)
13349 GSList *behaviours, *l;
13351 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13354 behaviours = g_value_get_pointer (value);
13355 for (l = behaviours; l != NULL; l = l->next)
13357 ClutterBehaviour *behaviour = l->data;
13359 clutter_behaviour_apply (behaviour, actor);
13362 g_slist_free (behaviours);
13367 if (strcmp (name, "actions") == 0 ||
13368 strcmp (name, "constraints") == 0 ||
13369 strcmp (name, "effects") == 0)
13373 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13376 metas = g_value_get_pointer (value);
13377 for (l = metas; l != NULL; l = l->next)
13379 if (name[0] == 'a')
13380 clutter_actor_add_action (actor, l->data);
13382 if (name[0] == 'c')
13383 clutter_actor_add_constraint (actor, l->data);
13385 if (name[0] == 'e')
13386 clutter_actor_add_effect (actor, l->data);
13389 g_slist_free (metas);
13393 if (strcmp (name, "margin") == 0)
13395 clutter_actor_set_margin (actor, g_value_get_boxed (value));
13399 g_object_set_property (G_OBJECT (scriptable), name, value);
13403 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13405 iface->parse_custom_node = clutter_actor_parse_custom_node;
13406 iface->set_custom_property = clutter_actor_set_custom_property;
13409 static ClutterActorMeta *
13410 get_meta_from_animation_property (ClutterActor *actor,
13414 ClutterActorPrivate *priv = actor->priv;
13415 ClutterActorMeta *meta = NULL;
13418 /* if this is not a special property, fall through */
13419 if (name[0] != '@')
13422 /* detect the properties named using the following spec:
13424 * @<section>.<meta-name>.<property-name>
13426 * where <section> can be one of the following:
13432 * and <meta-name> is the name set on a specific ActorMeta
13435 tokens = g_strsplit (name + 1, ".", -1);
13436 if (tokens == NULL || g_strv_length (tokens) != 3)
13438 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13440 g_strfreev (tokens);
13444 if (strcmp (tokens[0], "actions") == 0)
13445 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13447 if (strcmp (tokens[0], "constraints") == 0)
13448 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13450 if (strcmp (tokens[0], "effects") == 0)
13451 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13453 if (name_p != NULL)
13454 *name_p = g_strdup (tokens[2]);
13456 CLUTTER_NOTE (ANIMATION,
13457 "Looking for property '%s' of object '%s' in section '%s'",
13462 g_strfreev (tokens);
13467 static GParamSpec *
13468 clutter_actor_find_property (ClutterAnimatable *animatable,
13469 const gchar *property_name)
13471 ClutterActorMeta *meta = NULL;
13472 GObjectClass *klass = NULL;
13473 GParamSpec *pspec = NULL;
13474 gchar *p_name = NULL;
13476 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13482 klass = G_OBJECT_GET_CLASS (meta);
13484 pspec = g_object_class_find_property (klass, p_name);
13488 klass = G_OBJECT_GET_CLASS (animatable);
13490 pspec = g_object_class_find_property (klass, property_name);
13499 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13500 const gchar *property_name,
13503 ClutterActorMeta *meta = NULL;
13504 gchar *p_name = NULL;
13506 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13511 g_object_get_property (G_OBJECT (meta), p_name, initial);
13513 g_object_get_property (G_OBJECT (animatable), property_name, initial);
13519 * clutter_actor_set_animatable_property:
13520 * @actor: a #ClutterActor
13521 * @prop_id: the paramspec id
13522 * @value: the value to set
13523 * @pspec: the paramspec
13525 * Sets values of animatable properties.
13527 * This is a variant of clutter_actor_set_property() that gets called
13528 * by the #ClutterAnimatable implementation of #ClutterActor for the
13529 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13532 * Unlike the implementation of #GObjectClass.set_property(), this
13533 * function will not update the interval if a transition involving an
13534 * animatable property is in progress - this avoids cycles with the
13535 * transition API calling the public API.
13538 clutter_actor_set_animatable_property (ClutterActor *actor,
13540 const GValue *value,
13543 GObject *obj = G_OBJECT (actor);
13545 g_object_freeze_notify (obj);
13550 clutter_actor_set_x_internal (actor, g_value_get_float (value));
13554 clutter_actor_set_y_internal (actor, g_value_get_float (value));
13557 case PROP_POSITION:
13558 clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13562 clutter_actor_set_width_internal (actor, g_value_get_float (value));
13566 clutter_actor_set_height_internal (actor, g_value_get_float (value));
13570 clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13573 case PROP_ALLOCATION:
13574 clutter_actor_allocate_internal (actor,
13575 g_value_get_boxed (value),
13576 actor->priv->allocation_flags);
13580 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13584 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13587 case PROP_BACKGROUND_COLOR:
13588 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13592 clutter_actor_set_scale_factor_internal (actor,
13593 g_value_get_double (value),
13598 clutter_actor_set_scale_factor_internal (actor,
13599 g_value_get_double (value),
13603 case PROP_ROTATION_ANGLE_X:
13604 clutter_actor_set_rotation_angle_internal (actor,
13606 g_value_get_double (value));
13609 case PROP_ROTATION_ANGLE_Y:
13610 clutter_actor_set_rotation_angle_internal (actor,
13612 g_value_get_double (value));
13615 case PROP_ROTATION_ANGLE_Z:
13616 clutter_actor_set_rotation_angle_internal (actor,
13618 g_value_get_double (value));
13621 case PROP_CONTENT_BOX:
13622 clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13626 g_object_set_property (obj, pspec->name, value);
13630 g_object_thaw_notify (obj);
13634 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13635 const gchar *property_name,
13636 const GValue *final)
13638 ClutterActor *actor = CLUTTER_ACTOR (animatable);
13639 ClutterActorMeta *meta = NULL;
13640 gchar *p_name = NULL;
13642 meta = get_meta_from_animation_property (actor,
13646 g_object_set_property (G_OBJECT (meta), p_name, final);
13649 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13652 pspec = g_object_class_find_property (obj_class, property_name);
13654 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13656 /* XXX - I'm going to the special hell for this */
13657 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13660 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13667 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13669 iface->find_property = clutter_actor_find_property;
13670 iface->get_initial_state = clutter_actor_get_initial_state;
13671 iface->set_final_state = clutter_actor_set_final_state;
13675 * clutter_actor_transform_stage_point:
13676 * @self: A #ClutterActor
13677 * @x: (in): x screen coordinate of the point to unproject
13678 * @y: (in): y screen coordinate of the point to unproject
13679 * @x_out: (out): return location for the unprojected x coordinance
13680 * @y_out: (out): return location for the unprojected y coordinance
13682 * This function translates screen coordinates (@x, @y) to
13683 * coordinates relative to the actor. For example, it can be used to translate
13684 * screen events from global screen coordinates into actor-local coordinates.
13686 * The conversion can fail, notably if the transform stack results in the
13687 * actor being projected on the screen as a mere line.
13689 * The conversion should not be expected to be pixel-perfect due to the
13690 * nature of the operation. In general the error grows when the skewing
13691 * of the actor rectangle on screen increases.
13693 * <note><para>This function can be computationally intensive.</para></note>
13695 * <note><para>This function only works when the allocation is up-to-date,
13696 * i.e. inside of paint().</para></note>
13698 * Return value: %TRUE if conversion was successful.
13703 clutter_actor_transform_stage_point (ClutterActor *self,
13709 ClutterVertex v[4];
13712 int du, dv, xi, yi;
13714 float xf, yf, wf, det;
13715 ClutterActorPrivate *priv;
13717 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13721 /* This implementation is based on the quad -> quad projection algorithm
13722 * described by Paul Heckbert in:
13724 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13726 * and the sample implementation at:
13728 * http://www.cs.cmu.edu/~ph/src/texfund/
13730 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13731 * quad to rectangle only, which significantly simplifies things; the
13732 * function calls have been unrolled, and most of the math is done in fixed
13736 clutter_actor_get_abs_allocation_vertices (self, v);
13738 /* Keeping these as ints simplifies the multiplication (no significant
13739 * loss of precision here).
13741 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13742 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13747 #define UX2FP(x) (x)
13748 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13750 /* First, find mapping from unit uv square to xy quadrilateral; this
13751 * equivalent to the pmap_square_quad() functions in the sample
13752 * implementation, which we can simplify, since our target is always
13755 px = v[0].x - v[1].x + v[3].x - v[2].x;
13756 py = v[0].y - v[1].y + v[3].y - v[2].y;
13760 /* affine transform */
13761 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13762 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13763 RQ[2][0] = UX2FP (v[0].x);
13764 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13765 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13766 RQ[2][1] = UX2FP (v[0].y);
13773 /* projective transform */
13774 double dx1, dx2, dy1, dy2, del;
13776 dx1 = UX2FP (v[1].x - v[3].x);
13777 dx2 = UX2FP (v[2].x - v[3].x);
13778 dy1 = UX2FP (v[1].y - v[3].y);
13779 dy2 = UX2FP (v[2].y - v[3].y);
13781 del = DET2FP (dx1, dx2, dy1, dy2);
13786 * The division here needs to be done in floating point for
13787 * precisions reasons.
13789 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13790 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13791 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13793 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13794 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13795 RQ[2][0] = UX2FP (v[0].x);
13796 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13797 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13798 RQ[2][1] = UX2FP (v[0].y);
13802 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13803 * square. Since our rectangle is based at 0,0 we only need to scale.
13813 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13816 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13817 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13818 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13819 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13820 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13821 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13822 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13823 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13824 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13827 * Check the resulting matrix is OK.
13829 det = (RQ[0][0] * ST[0][0])
13830 + (RQ[0][1] * ST[0][1])
13831 + (RQ[0][2] * ST[0][2]);
13836 * Now transform our point with the ST matrix; the notional w
13837 * coordinate is 1, hence the last part is simply added.
13842 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13843 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13844 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13859 * clutter_actor_is_rotated:
13860 * @self: a #ClutterActor
13862 * Checks whether any rotation is applied to the actor.
13864 * Return value: %TRUE if the actor is rotated.
13869 clutter_actor_is_rotated (ClutterActor *self)
13871 const ClutterTransformInfo *info;
13873 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13875 info = _clutter_actor_get_transform_info_or_defaults (self);
13877 if (info->rx_angle || info->ry_angle || info->rz_angle)
13884 * clutter_actor_is_scaled:
13885 * @self: a #ClutterActor
13887 * Checks whether the actor is scaled in either dimension.
13889 * Return value: %TRUE if the actor is scaled.
13894 clutter_actor_is_scaled (ClutterActor *self)
13896 const ClutterTransformInfo *info;
13898 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13900 info = _clutter_actor_get_transform_info_or_defaults (self);
13902 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13909 _clutter_actor_get_stage_internal (ClutterActor *actor)
13911 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13912 actor = actor->priv->parent;
13918 * clutter_actor_get_stage:
13919 * @actor: a #ClutterActor
13921 * Retrieves the #ClutterStage where @actor is contained.
13923 * Return value: (transfer none) (type Clutter.Stage): the stage
13924 * containing the actor, or %NULL
13929 clutter_actor_get_stage (ClutterActor *actor)
13931 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13933 return _clutter_actor_get_stage_internal (actor);
13937 * clutter_actor_allocate_available_size:
13938 * @self: a #ClutterActor
13939 * @x: the actor's X coordinate
13940 * @y: the actor's Y coordinate
13941 * @available_width: the maximum available width, or -1 to use the
13942 * actor's natural width
13943 * @available_height: the maximum available height, or -1 to use the
13944 * actor's natural height
13945 * @flags: flags controlling the allocation
13947 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13948 * preferred size, but limiting it to the maximum available width
13949 * and height provided.
13951 * This function will do the right thing when dealing with the
13952 * actor's request mode.
13954 * The implementation of this function is equivalent to:
13957 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13959 * clutter_actor_get_preferred_width (self, available_height,
13961 * &natural_width);
13962 * width = CLAMP (natural_width, min_width, available_width);
13964 * clutter_actor_get_preferred_height (self, width,
13966 * &natural_height);
13967 * height = CLAMP (natural_height, min_height, available_height);
13971 * clutter_actor_get_preferred_height (self, available_width,
13973 * &natural_height);
13974 * height = CLAMP (natural_height, min_height, available_height);
13976 * clutter_actor_get_preferred_width (self, height,
13978 * &natural_width);
13979 * width = CLAMP (natural_width, min_width, available_width);
13982 * box.x1 = x; box.y1 = y;
13983 * box.x2 = box.x1 + available_width;
13984 * box.y2 = box.y1 + available_height;
13985 * clutter_actor_allocate (self, &box, flags);
13988 * This function can be used by fluid layout managers to allocate
13989 * an actor's preferred size without making it bigger than the area
13990 * available for the container.
13995 clutter_actor_allocate_available_size (ClutterActor *self,
13998 gfloat available_width,
13999 gfloat available_height,
14000 ClutterAllocationFlags flags)
14002 ClutterActorPrivate *priv;
14003 gfloat width, height;
14004 gfloat min_width, min_height;
14005 gfloat natural_width, natural_height;
14006 ClutterActorBox box;
14008 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14012 width = height = 0.0;
14014 switch (priv->request_mode)
14016 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
14017 clutter_actor_get_preferred_width (self, available_height,
14020 width = CLAMP (natural_width, min_width, available_width);
14022 clutter_actor_get_preferred_height (self, width,
14025 height = CLAMP (natural_height, min_height, available_height);
14028 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
14029 clutter_actor_get_preferred_height (self, available_width,
14032 height = CLAMP (natural_height, min_height, available_height);
14034 clutter_actor_get_preferred_width (self, height,
14037 width = CLAMP (natural_width, min_width, available_width);
14044 box.x2 = box.x1 + width;
14045 box.y2 = box.y1 + height;
14046 clutter_actor_allocate (self, &box, flags);
14050 * clutter_actor_allocate_preferred_size:
14051 * @self: a #ClutterActor
14052 * @flags: flags controlling the allocation
14054 * Allocates the natural size of @self.
14056 * This function is a utility call for #ClutterActor implementations
14057 * that allocates the actor's preferred natural size. It can be used
14058 * by fixed layout managers (like #ClutterGroup or so called
14059 * 'composite actors') inside the ClutterActor::allocate
14060 * implementation to give each child exactly how much space it
14063 * This function is not meant to be used by applications. It is also
14064 * not meant to be used outside the implementation of the
14065 * ClutterActor::allocate virtual function.
14070 clutter_actor_allocate_preferred_size (ClutterActor *self,
14071 ClutterAllocationFlags flags)
14073 gfloat actor_x, actor_y;
14074 gfloat natural_width, natural_height;
14075 ClutterActorBox actor_box;
14077 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14079 actor_x = clutter_actor_get_x (self);
14080 actor_y = clutter_actor_get_y (self);
14082 clutter_actor_get_preferred_size (self,
14087 actor_box.x1 = actor_x;
14088 actor_box.y1 = actor_y;
14089 actor_box.x2 = actor_box.x1 + natural_width;
14090 actor_box.y2 = actor_box.y1 + natural_height;
14092 clutter_actor_allocate (self, &actor_box, flags);
14096 * clutter_actor_allocate_align_fill:
14097 * @self: a #ClutterActor
14098 * @box: a #ClutterActorBox, containing the available width and height
14099 * @x_align: the horizontal alignment, between 0 and 1
14100 * @y_align: the vertical alignment, between 0 and 1
14101 * @x_fill: whether the actor should fill horizontally
14102 * @y_fill: whether the actor should fill vertically
14103 * @flags: allocation flags to be passed to clutter_actor_allocate()
14105 * Allocates @self by taking into consideration the available allocation
14106 * area; an alignment factor on either axis; and whether the actor should
14107 * fill the allocation on either axis.
14109 * The @box should contain the available allocation width and height;
14110 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
14111 * allocation will be offset by their value.
14113 * This function takes into consideration the geometry request specified by
14114 * the #ClutterActor:request-mode property, and the text direction.
14116 * This function is useful for fluid layout managers, like #ClutterBinLayout
14117 * or #ClutterTableLayout
14122 clutter_actor_allocate_align_fill (ClutterActor *self,
14123 const ClutterActorBox *box,
14128 ClutterAllocationFlags flags)
14130 ClutterActorPrivate *priv;
14131 ClutterActorBox allocation = { 0, };
14132 gfloat x_offset, y_offset;
14133 gfloat available_width, available_height;
14134 gfloat child_width, child_height;
14136 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14137 g_return_if_fail (box != NULL);
14138 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
14139 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
14143 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
14144 clutter_actor_box_get_size (box, &available_width, &available_height);
14146 if (available_width < 0)
14147 available_width = 0;
14149 if (available_height < 0)
14150 available_height = 0;
14154 allocation.x1 = x_offset;
14155 allocation.x2 = allocation.x1 + available_width;
14160 allocation.y1 = y_offset;
14161 allocation.y2 = allocation.y1 + available_height;
14164 /* if we are filling horizontally and vertically then we're done */
14165 if (x_fill && y_fill)
14168 child_width = child_height = 0.0f;
14170 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
14172 gfloat min_width, natural_width;
14173 gfloat min_height, natural_height;
14175 clutter_actor_get_preferred_width (self, available_height,
14179 child_width = CLAMP (natural_width, min_width, available_width);
14183 clutter_actor_get_preferred_height (self, child_width,
14187 child_height = CLAMP (natural_height, min_height, available_height);
14192 gfloat min_width, natural_width;
14193 gfloat min_height, natural_height;
14195 clutter_actor_get_preferred_height (self, available_width,
14199 child_height = CLAMP (natural_height, min_height, available_height);
14203 clutter_actor_get_preferred_width (self, child_height,
14207 child_width = CLAMP (natural_width, min_width, available_width);
14211 /* invert the horizontal alignment for RTL languages */
14212 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
14213 x_align = 1.0 - x_align;
14217 allocation.x1 = x_offset
14218 + ((available_width - child_width) * x_align);
14219 allocation.x2 = allocation.x1 + child_width;
14224 allocation.y1 = y_offset
14225 + ((available_height - child_height) * y_align);
14226 allocation.y2 = allocation.y1 + child_height;
14230 clutter_actor_box_clamp_to_pixel (&allocation);
14231 clutter_actor_allocate (self, &allocation, flags);
14235 * clutter_actor_grab_key_focus:
14236 * @self: a #ClutterActor
14238 * Sets the key focus of the #ClutterStage including @self
14239 * to this #ClutterActor.
14244 clutter_actor_grab_key_focus (ClutterActor *self)
14246 ClutterActor *stage;
14248 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14250 stage = _clutter_actor_get_stage_internal (self);
14252 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14256 * clutter_actor_get_pango_context:
14257 * @self: a #ClutterActor
14259 * Retrieves the #PangoContext for @self. The actor's #PangoContext
14260 * is already configured using the appropriate font map, resolution
14261 * and font options.
14263 * Unlike clutter_actor_create_pango_context(), this context is owend
14264 * by the #ClutterActor and it will be updated each time the options
14265 * stored by the #ClutterBackend change.
14267 * You can use the returned #PangoContext to create a #PangoLayout
14268 * and render text using cogl_pango_render_layout() to reuse the
14269 * glyphs cache also used by Clutter.
14271 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14272 * The returned #PangoContext is owned by the actor and should not be
14273 * unreferenced by the application code
14278 clutter_actor_get_pango_context (ClutterActor *self)
14280 ClutterActorPrivate *priv;
14282 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14286 if (priv->pango_context != NULL)
14287 return priv->pango_context;
14289 priv->pango_context = _clutter_context_get_pango_context ();
14290 g_object_ref (priv->pango_context);
14292 return priv->pango_context;
14296 * clutter_actor_create_pango_context:
14297 * @self: a #ClutterActor
14299 * Creates a #PangoContext for the given actor. The #PangoContext
14300 * is already configured using the appropriate font map, resolution
14301 * and font options.
14303 * See also clutter_actor_get_pango_context().
14305 * Return value: (transfer full): the newly created #PangoContext.
14306 * Use g_object_unref() on the returned value to deallocate its
14312 clutter_actor_create_pango_context (ClutterActor *self)
14314 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14316 return _clutter_context_create_pango_context ();
14320 * clutter_actor_create_pango_layout:
14321 * @self: a #ClutterActor
14322 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14324 * Creates a new #PangoLayout from the same #PangoContext used
14325 * by the #ClutterActor. The #PangoLayout is already configured
14326 * with the font map, resolution and font options, and the
14329 * If you want to keep around a #PangoLayout created by this
14330 * function you will have to connect to the #ClutterBackend::font-changed
14331 * and #ClutterBackend::resolution-changed signals, and call
14332 * pango_layout_context_changed() in response to them.
14334 * Return value: (transfer full): the newly created #PangoLayout.
14335 * Use g_object_unref() when done
14340 clutter_actor_create_pango_layout (ClutterActor *self,
14343 PangoContext *context;
14344 PangoLayout *layout;
14346 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14348 context = clutter_actor_get_pango_context (self);
14349 layout = pango_layout_new (context);
14352 pango_layout_set_text (layout, text, -1);
14357 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14358 * ClutterOffscreenEffect.
14361 _clutter_actor_set_opacity_override (ClutterActor *self,
14364 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14366 self->priv->opacity_override = opacity;
14370 _clutter_actor_get_opacity_override (ClutterActor *self)
14372 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14374 return self->priv->opacity_override;
14377 /* Allows you to disable applying the actors model view transform during
14378 * a paint. Used by ClutterClone. */
14380 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14383 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14385 self->priv->enable_model_view_transform = enable;
14389 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14392 ClutterActorPrivate *priv;
14394 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14398 priv->enable_paint_unmapped = enable;
14400 if (priv->enable_paint_unmapped)
14402 /* Make sure that the parents of the widget are realized first;
14403 * otherwise checks in clutter_actor_update_map_state() will
14406 clutter_actor_realize (self);
14408 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14412 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14417 clutter_anchor_coord_get_units (ClutterActor *self,
14418 const AnchorCoord *coord,
14423 if (coord->is_fractional)
14425 gfloat actor_width, actor_height;
14427 clutter_actor_get_size (self, &actor_width, &actor_height);
14430 *x = actor_width * coord->v.fraction.x;
14433 *y = actor_height * coord->v.fraction.y;
14441 *x = coord->v.units.x;
14444 *y = coord->v.units.y;
14447 *z = coord->v.units.z;
14452 clutter_anchor_coord_set_units (AnchorCoord *coord,
14457 coord->is_fractional = FALSE;
14458 coord->v.units.x = x;
14459 coord->v.units.y = y;
14460 coord->v.units.z = z;
14463 static ClutterGravity
14464 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14466 if (coord->is_fractional)
14468 if (coord->v.fraction.x == 0.0)
14470 if (coord->v.fraction.y == 0.0)
14471 return CLUTTER_GRAVITY_NORTH_WEST;
14472 else if (coord->v.fraction.y == 0.5)
14473 return CLUTTER_GRAVITY_WEST;
14474 else if (coord->v.fraction.y == 1.0)
14475 return CLUTTER_GRAVITY_SOUTH_WEST;
14477 return CLUTTER_GRAVITY_NONE;
14479 else if (coord->v.fraction.x == 0.5)
14481 if (coord->v.fraction.y == 0.0)
14482 return CLUTTER_GRAVITY_NORTH;
14483 else if (coord->v.fraction.y == 0.5)
14484 return CLUTTER_GRAVITY_CENTER;
14485 else if (coord->v.fraction.y == 1.0)
14486 return CLUTTER_GRAVITY_SOUTH;
14488 return CLUTTER_GRAVITY_NONE;
14490 else if (coord->v.fraction.x == 1.0)
14492 if (coord->v.fraction.y == 0.0)
14493 return CLUTTER_GRAVITY_NORTH_EAST;
14494 else if (coord->v.fraction.y == 0.5)
14495 return CLUTTER_GRAVITY_EAST;
14496 else if (coord->v.fraction.y == 1.0)
14497 return CLUTTER_GRAVITY_SOUTH_EAST;
14499 return CLUTTER_GRAVITY_NONE;
14502 return CLUTTER_GRAVITY_NONE;
14505 return CLUTTER_GRAVITY_NONE;
14509 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14510 ClutterGravity gravity)
14514 case CLUTTER_GRAVITY_NORTH:
14515 coord->v.fraction.x = 0.5;
14516 coord->v.fraction.y = 0.0;
14519 case CLUTTER_GRAVITY_NORTH_EAST:
14520 coord->v.fraction.x = 1.0;
14521 coord->v.fraction.y = 0.0;
14524 case CLUTTER_GRAVITY_EAST:
14525 coord->v.fraction.x = 1.0;
14526 coord->v.fraction.y = 0.5;
14529 case CLUTTER_GRAVITY_SOUTH_EAST:
14530 coord->v.fraction.x = 1.0;
14531 coord->v.fraction.y = 1.0;
14534 case CLUTTER_GRAVITY_SOUTH:
14535 coord->v.fraction.x = 0.5;
14536 coord->v.fraction.y = 1.0;
14539 case CLUTTER_GRAVITY_SOUTH_WEST:
14540 coord->v.fraction.x = 0.0;
14541 coord->v.fraction.y = 1.0;
14544 case CLUTTER_GRAVITY_WEST:
14545 coord->v.fraction.x = 0.0;
14546 coord->v.fraction.y = 0.5;
14549 case CLUTTER_GRAVITY_NORTH_WEST:
14550 coord->v.fraction.x = 0.0;
14551 coord->v.fraction.y = 0.0;
14554 case CLUTTER_GRAVITY_CENTER:
14555 coord->v.fraction.x = 0.5;
14556 coord->v.fraction.y = 0.5;
14560 coord->v.fraction.x = 0.0;
14561 coord->v.fraction.y = 0.0;
14565 coord->is_fractional = TRUE;
14569 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14571 if (coord->is_fractional)
14572 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14574 return (coord->v.units.x == 0.0
14575 && coord->v.units.y == 0.0
14576 && coord->v.units.z == 0.0);
14580 * clutter_actor_get_flags:
14581 * @self: a #ClutterActor
14583 * Retrieves the flags set on @self
14585 * Return value: a bitwise or of #ClutterActorFlags or 0
14590 clutter_actor_get_flags (ClutterActor *self)
14592 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14594 return self->flags;
14598 * clutter_actor_set_flags:
14599 * @self: a #ClutterActor
14600 * @flags: the flags to set
14602 * Sets @flags on @self
14604 * This function will emit notifications for the changed properties
14609 clutter_actor_set_flags (ClutterActor *self,
14610 ClutterActorFlags flags)
14612 ClutterActorFlags old_flags;
14614 gboolean was_reactive_set, reactive_set;
14615 gboolean was_realized_set, realized_set;
14616 gboolean was_mapped_set, mapped_set;
14617 gboolean was_visible_set, visible_set;
14619 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14621 if (self->flags == flags)
14624 obj = G_OBJECT (self);
14625 g_object_ref (obj);
14626 g_object_freeze_notify (obj);
14628 old_flags = self->flags;
14630 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14631 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14632 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14633 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14635 self->flags |= flags;
14637 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14638 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14639 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14640 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14642 if (reactive_set != was_reactive_set)
14643 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14645 if (realized_set != was_realized_set)
14646 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14648 if (mapped_set != was_mapped_set)
14649 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14651 if (visible_set != was_visible_set)
14652 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14654 g_object_thaw_notify (obj);
14655 g_object_unref (obj);
14659 * clutter_actor_unset_flags:
14660 * @self: a #ClutterActor
14661 * @flags: the flags to unset
14663 * Unsets @flags on @self
14665 * This function will emit notifications for the changed properties
14670 clutter_actor_unset_flags (ClutterActor *self,
14671 ClutterActorFlags flags)
14673 ClutterActorFlags old_flags;
14675 gboolean was_reactive_set, reactive_set;
14676 gboolean was_realized_set, realized_set;
14677 gboolean was_mapped_set, mapped_set;
14678 gboolean was_visible_set, visible_set;
14680 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14682 obj = G_OBJECT (self);
14683 g_object_freeze_notify (obj);
14685 old_flags = self->flags;
14687 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14688 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14689 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14690 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14692 self->flags &= ~flags;
14694 if (self->flags == old_flags)
14697 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14698 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14699 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14700 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14702 if (reactive_set != was_reactive_set)
14703 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14705 if (realized_set != was_realized_set)
14706 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14708 if (mapped_set != was_mapped_set)
14709 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14711 if (visible_set != was_visible_set)
14712 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14714 g_object_thaw_notify (obj);
14718 * clutter_actor_get_transformation_matrix:
14719 * @self: a #ClutterActor
14720 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14722 * Retrieves the transformations applied to @self relative to its
14728 clutter_actor_get_transformation_matrix (ClutterActor *self,
14729 CoglMatrix *matrix)
14731 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14733 cogl_matrix_init_identity (matrix);
14735 _clutter_actor_apply_modelview_transform (self, matrix);
14739 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14740 gboolean is_in_clone_paint)
14742 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14743 self->priv->in_clone_paint = is_in_clone_paint;
14747 * clutter_actor_is_in_clone_paint:
14748 * @self: a #ClutterActor
14750 * Checks whether @self is being currently painted by a #ClutterClone
14752 * This function is useful only inside the ::paint virtual function
14753 * implementations or within handlers for the #ClutterActor::paint
14756 * This function should not be used by applications
14758 * Return value: %TRUE if the #ClutterActor is currently being painted
14759 * by a #ClutterClone, and %FALSE otherwise
14764 clutter_actor_is_in_clone_paint (ClutterActor *self)
14766 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14768 return self->priv->in_clone_paint;
14772 set_direction_recursive (ClutterActor *actor,
14773 gpointer user_data)
14775 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14777 clutter_actor_set_text_direction (actor, text_dir);
14783 * clutter_actor_set_text_direction:
14784 * @self: a #ClutterActor
14785 * @text_dir: the text direction for @self
14787 * Sets the #ClutterTextDirection for an actor
14789 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14791 * If @self implements #ClutterContainer then this function will recurse
14792 * inside all the children of @self (including the internal ones).
14794 * Composite actors not implementing #ClutterContainer, or actors requiring
14795 * special handling when the text direction changes, should connect to
14796 * the #GObject::notify signal for the #ClutterActor:text-direction property
14801 clutter_actor_set_text_direction (ClutterActor *self,
14802 ClutterTextDirection text_dir)
14804 ClutterActorPrivate *priv;
14806 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14807 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14811 if (priv->text_direction != text_dir)
14813 priv->text_direction = text_dir;
14815 /* we need to emit the notify::text-direction first, so that
14816 * the sub-classes can catch that and do specific handling of
14817 * the text direction; see clutter_text_direction_changed_cb()
14818 * inside clutter-text.c
14820 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14822 _clutter_actor_foreach_child (self, set_direction_recursive,
14823 GINT_TO_POINTER (text_dir));
14825 clutter_actor_queue_relayout (self);
14830 _clutter_actor_set_has_pointer (ClutterActor *self,
14831 gboolean has_pointer)
14833 ClutterActorPrivate *priv = self->priv;
14835 if (priv->has_pointer != has_pointer)
14837 priv->has_pointer = has_pointer;
14839 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14844 * clutter_actor_get_text_direction:
14845 * @self: a #ClutterActor
14847 * Retrieves the value set using clutter_actor_set_text_direction()
14849 * If no text direction has been previously set, the default text
14850 * direction, as returned by clutter_get_default_text_direction(), will
14851 * be returned instead
14853 * Return value: the #ClutterTextDirection for the actor
14857 ClutterTextDirection
14858 clutter_actor_get_text_direction (ClutterActor *self)
14860 ClutterActorPrivate *priv;
14862 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14863 CLUTTER_TEXT_DIRECTION_LTR);
14867 /* if no direction has been set yet use the default */
14868 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14869 priv->text_direction = clutter_get_default_text_direction ();
14871 return priv->text_direction;
14875 * clutter_actor_push_internal:
14876 * @self: a #ClutterActor
14878 * Should be used by actors implementing the #ClutterContainer and with
14879 * internal children added through clutter_actor_set_parent(), for instance:
14883 * my_actor_init (MyActor *self)
14885 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14887 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14889 * /* calling clutter_actor_set_parent() now will result in
14890 * * the internal flag being set on a child of MyActor
14893 * /* internal child - a background texture */
14894 * self->priv->background_tex = clutter_texture_new ();
14895 * clutter_actor_set_parent (self->priv->background_tex,
14896 * CLUTTER_ACTOR (self));
14898 * /* internal child - a label */
14899 * self->priv->label = clutter_text_new ();
14900 * clutter_actor_set_parent (self->priv->label,
14901 * CLUTTER_ACTOR (self));
14903 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14905 * /* calling clutter_actor_set_parent() now will not result in
14906 * * the internal flag being set on a child of MyActor
14911 * This function will be used by Clutter to toggle an "internal child"
14912 * flag whenever clutter_actor_set_parent() is called; internal children
14913 * are handled differently by Clutter, specifically when destroying their
14916 * Call clutter_actor_pop_internal() when you finished adding internal
14919 * Nested calls to clutter_actor_push_internal() are allowed, but each
14920 * one must by followed by a clutter_actor_pop_internal() call.
14924 * Deprecated: 1.10: All children of an actor are accessible through
14925 * the #ClutterActor API, and #ClutterActor implements the
14926 * #ClutterContainer interface, so this function is only useful
14927 * for legacy containers overriding the default implementation.
14930 clutter_actor_push_internal (ClutterActor *self)
14932 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14934 self->priv->internal_child += 1;
14938 * clutter_actor_pop_internal:
14939 * @self: a #ClutterActor
14941 * Disables the effects of clutter_actor_push_internal().
14945 * Deprecated: 1.10: All children of an actor are accessible through
14946 * the #ClutterActor API. This function is only useful for legacy
14947 * containers overriding the default implementation of the
14948 * #ClutterContainer interface.
14951 clutter_actor_pop_internal (ClutterActor *self)
14953 ClutterActorPrivate *priv;
14955 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14959 if (priv->internal_child == 0)
14961 g_warning ("Mismatched %s: you need to call "
14962 "clutter_actor_push_composite() at least once before "
14963 "calling this function", G_STRFUNC);
14967 priv->internal_child -= 1;
14971 * clutter_actor_has_pointer:
14972 * @self: a #ClutterActor
14974 * Checks whether an actor contains the pointer of a
14975 * #ClutterInputDevice
14977 * Return value: %TRUE if the actor contains the pointer, and
14983 clutter_actor_has_pointer (ClutterActor *self)
14985 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14987 return self->priv->has_pointer;
14990 /* XXX: This is a workaround for not being able to break the ABI of
14991 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14992 * clutter_actor_queue_clipped_redraw() for details.
14994 ClutterPaintVolume *
14995 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14997 return g_object_get_data (G_OBJECT (self),
14998 "-clutter-actor-queue-redraw-clip");
15002 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
15003 ClutterPaintVolume *clip)
15005 g_object_set_data (G_OBJECT (self),
15006 "-clutter-actor-queue-redraw-clip",
15011 * clutter_actor_has_allocation:
15012 * @self: a #ClutterActor
15014 * Checks if the actor has an up-to-date allocation assigned to
15015 * it. This means that the actor should have an allocation: it's
15016 * visible and has a parent. It also means that there is no
15017 * outstanding relayout request in progress for the actor or its
15018 * children (There might be other outstanding layout requests in
15019 * progress that will cause the actor to get a new allocation
15020 * when the stage is laid out, however).
15022 * If this function returns %FALSE, then the actor will normally
15023 * be allocated before it is next drawn on the screen.
15025 * Return value: %TRUE if the actor has an up-to-date allocation
15030 clutter_actor_has_allocation (ClutterActor *self)
15032 ClutterActorPrivate *priv;
15034 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15038 return priv->parent != NULL &&
15039 CLUTTER_ACTOR_IS_VISIBLE (self) &&
15040 !priv->needs_allocation;
15044 * clutter_actor_add_action:
15045 * @self: a #ClutterActor
15046 * @action: a #ClutterAction
15048 * Adds @action to the list of actions applied to @self
15050 * A #ClutterAction can only belong to one actor at a time
15052 * The #ClutterActor will hold a reference on @action until either
15053 * clutter_actor_remove_action() or clutter_actor_clear_actions()
15059 clutter_actor_add_action (ClutterActor *self,
15060 ClutterAction *action)
15062 ClutterActorPrivate *priv;
15064 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15065 g_return_if_fail (CLUTTER_IS_ACTION (action));
15069 if (priv->actions == NULL)
15071 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15072 priv->actions->actor = self;
15075 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
15077 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15081 * clutter_actor_add_action_with_name:
15082 * @self: a #ClutterActor
15083 * @name: the name to set on the action
15084 * @action: a #ClutterAction
15086 * A convenience function for setting the name of a #ClutterAction
15087 * while adding it to the list of actions applied to @self
15089 * This function is the logical equivalent of:
15092 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15093 * clutter_actor_add_action (self, action);
15099 clutter_actor_add_action_with_name (ClutterActor *self,
15101 ClutterAction *action)
15103 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15104 g_return_if_fail (name != NULL);
15105 g_return_if_fail (CLUTTER_IS_ACTION (action));
15107 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15108 clutter_actor_add_action (self, action);
15112 * clutter_actor_remove_action:
15113 * @self: a #ClutterActor
15114 * @action: a #ClutterAction
15116 * Removes @action from the list of actions applied to @self
15118 * The reference held by @self on the #ClutterAction will be released
15123 clutter_actor_remove_action (ClutterActor *self,
15124 ClutterAction *action)
15126 ClutterActorPrivate *priv;
15128 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15129 g_return_if_fail (CLUTTER_IS_ACTION (action));
15133 if (priv->actions == NULL)
15136 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
15138 if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
15139 g_clear_object (&priv->actions);
15141 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15145 * clutter_actor_remove_action_by_name:
15146 * @self: a #ClutterActor
15147 * @name: the name of the action to remove
15149 * Removes the #ClutterAction with the given name from the list
15150 * of actions applied to @self
15155 clutter_actor_remove_action_by_name (ClutterActor *self,
15158 ClutterActorPrivate *priv;
15159 ClutterActorMeta *meta;
15161 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15162 g_return_if_fail (name != NULL);
15166 if (priv->actions == NULL)
15169 meta = _clutter_meta_group_get_meta (priv->actions, name);
15173 _clutter_meta_group_remove_meta (priv->actions, meta);
15175 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15179 * clutter_actor_get_actions:
15180 * @self: a #ClutterActor
15182 * Retrieves the list of actions applied to @self
15184 * Return value: (transfer container) (element-type Clutter.Action): a copy
15185 * of the list of #ClutterAction<!-- -->s. The contents of the list are
15186 * owned by the #ClutterActor. Use g_list_free() to free the resources
15187 * allocated by the returned #GList
15192 clutter_actor_get_actions (ClutterActor *self)
15194 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15196 if (self->priv->actions == NULL)
15199 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
15203 * clutter_actor_get_action:
15204 * @self: a #ClutterActor
15205 * @name: the name of the action to retrieve
15207 * Retrieves the #ClutterAction with the given name in the list
15208 * of actions applied to @self
15210 * Return value: (transfer none): a #ClutterAction for the given
15211 * name, or %NULL. The returned #ClutterAction is owned by the
15212 * actor and it should not be unreferenced directly
15217 clutter_actor_get_action (ClutterActor *self,
15220 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15221 g_return_val_if_fail (name != NULL, NULL);
15223 if (self->priv->actions == NULL)
15226 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
15230 * clutter_actor_clear_actions:
15231 * @self: a #ClutterActor
15233 * Clears the list of actions applied to @self
15238 clutter_actor_clear_actions (ClutterActor *self)
15240 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15242 if (self->priv->actions == NULL)
15245 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
15249 * clutter_actor_add_constraint:
15250 * @self: a #ClutterActor
15251 * @constraint: a #ClutterConstraint
15253 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15256 * The #ClutterActor will hold a reference on the @constraint until
15257 * either clutter_actor_remove_constraint() or
15258 * clutter_actor_clear_constraints() is called.
15263 clutter_actor_add_constraint (ClutterActor *self,
15264 ClutterConstraint *constraint)
15266 ClutterActorPrivate *priv;
15268 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15269 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15273 if (priv->constraints == NULL)
15275 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15276 priv->constraints->actor = self;
15279 _clutter_meta_group_add_meta (priv->constraints,
15280 CLUTTER_ACTOR_META (constraint));
15281 clutter_actor_queue_relayout (self);
15283 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15287 * clutter_actor_add_constraint_with_name:
15288 * @self: a #ClutterActor
15289 * @name: the name to set on the constraint
15290 * @constraint: a #ClutterConstraint
15292 * A convenience function for setting the name of a #ClutterConstraint
15293 * while adding it to the list of constraints applied to @self
15295 * This function is the logical equivalent of:
15298 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15299 * clutter_actor_add_constraint (self, constraint);
15305 clutter_actor_add_constraint_with_name (ClutterActor *self,
15307 ClutterConstraint *constraint)
15309 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15310 g_return_if_fail (name != NULL);
15311 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15313 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15314 clutter_actor_add_constraint (self, constraint);
15318 * clutter_actor_remove_constraint:
15319 * @self: a #ClutterActor
15320 * @constraint: a #ClutterConstraint
15322 * Removes @constraint from the list of constraints applied to @self
15324 * The reference held by @self on the #ClutterConstraint will be released
15329 clutter_actor_remove_constraint (ClutterActor *self,
15330 ClutterConstraint *constraint)
15332 ClutterActorPrivate *priv;
15334 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15335 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15339 if (priv->constraints == NULL)
15342 _clutter_meta_group_remove_meta (priv->constraints,
15343 CLUTTER_ACTOR_META (constraint));
15345 if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15346 g_clear_object (&priv->constraints);
15348 clutter_actor_queue_relayout (self);
15350 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15354 * clutter_actor_remove_constraint_by_name:
15355 * @self: a #ClutterActor
15356 * @name: the name of the constraint to remove
15358 * Removes the #ClutterConstraint with the given name from the list
15359 * of constraints applied to @self
15364 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15367 ClutterActorPrivate *priv;
15368 ClutterActorMeta *meta;
15370 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15371 g_return_if_fail (name != NULL);
15375 if (priv->constraints == NULL)
15378 meta = _clutter_meta_group_get_meta (priv->constraints, name);
15382 _clutter_meta_group_remove_meta (priv->constraints, meta);
15383 clutter_actor_queue_relayout (self);
15387 * clutter_actor_get_constraints:
15388 * @self: a #ClutterActor
15390 * Retrieves the list of constraints applied to @self
15392 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15393 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15394 * owned by the #ClutterActor. Use g_list_free() to free the resources
15395 * allocated by the returned #GList
15400 clutter_actor_get_constraints (ClutterActor *self)
15402 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15404 if (self->priv->constraints == NULL)
15407 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15411 * clutter_actor_get_constraint:
15412 * @self: a #ClutterActor
15413 * @name: the name of the constraint to retrieve
15415 * Retrieves the #ClutterConstraint with the given name in the list
15416 * of constraints applied to @self
15418 * Return value: (transfer none): a #ClutterConstraint for the given
15419 * name, or %NULL. The returned #ClutterConstraint is owned by the
15420 * actor and it should not be unreferenced directly
15424 ClutterConstraint *
15425 clutter_actor_get_constraint (ClutterActor *self,
15428 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15429 g_return_val_if_fail (name != NULL, NULL);
15431 if (self->priv->constraints == NULL)
15434 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15438 * clutter_actor_clear_constraints:
15439 * @self: a #ClutterActor
15441 * Clears the list of constraints applied to @self
15446 clutter_actor_clear_constraints (ClutterActor *self)
15448 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15450 if (self->priv->constraints == NULL)
15453 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15455 clutter_actor_queue_relayout (self);
15459 * clutter_actor_set_clip_to_allocation:
15460 * @self: a #ClutterActor
15461 * @clip_set: %TRUE to apply a clip tracking the allocation
15463 * Sets whether @self should be clipped to the same size as its
15469 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15472 ClutterActorPrivate *priv;
15474 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15476 clip_set = !!clip_set;
15480 if (priv->clip_to_allocation != clip_set)
15482 priv->clip_to_allocation = clip_set;
15484 clutter_actor_queue_redraw (self);
15486 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15491 * clutter_actor_get_clip_to_allocation:
15492 * @self: a #ClutterActor
15494 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15496 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15501 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15503 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15505 return self->priv->clip_to_allocation;
15509 * clutter_actor_add_effect:
15510 * @self: a #ClutterActor
15511 * @effect: a #ClutterEffect
15513 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15515 * The #ClutterActor will hold a reference on the @effect until either
15516 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15522 clutter_actor_add_effect (ClutterActor *self,
15523 ClutterEffect *effect)
15525 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15526 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15528 _clutter_actor_add_effect_internal (self, effect);
15530 clutter_actor_queue_redraw (self);
15532 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15536 * clutter_actor_add_effect_with_name:
15537 * @self: a #ClutterActor
15538 * @name: the name to set on the effect
15539 * @effect: a #ClutterEffect
15541 * A convenience function for setting the name of a #ClutterEffect
15542 * while adding it to the list of effectss applied to @self
15544 * This function is the logical equivalent of:
15547 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15548 * clutter_actor_add_effect (self, effect);
15554 clutter_actor_add_effect_with_name (ClutterActor *self,
15556 ClutterEffect *effect)
15558 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15559 g_return_if_fail (name != NULL);
15560 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15562 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15563 clutter_actor_add_effect (self, effect);
15567 * clutter_actor_remove_effect:
15568 * @self: a #ClutterActor
15569 * @effect: a #ClutterEffect
15571 * Removes @effect from the list of effects applied to @self
15573 * The reference held by @self on the #ClutterEffect will be released
15578 clutter_actor_remove_effect (ClutterActor *self,
15579 ClutterEffect *effect)
15581 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15582 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15584 _clutter_actor_remove_effect_internal (self, effect);
15586 clutter_actor_queue_redraw (self);
15588 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15592 * clutter_actor_remove_effect_by_name:
15593 * @self: a #ClutterActor
15594 * @name: the name of the effect to remove
15596 * Removes the #ClutterEffect with the given name from the list
15597 * of effects applied to @self
15602 clutter_actor_remove_effect_by_name (ClutterActor *self,
15605 ClutterActorPrivate *priv;
15606 ClutterActorMeta *meta;
15608 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15609 g_return_if_fail (name != NULL);
15613 if (priv->effects == NULL)
15616 meta = _clutter_meta_group_get_meta (priv->effects, name);
15620 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15624 * clutter_actor_get_effects:
15625 * @self: a #ClutterActor
15627 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15629 * Return value: (transfer container) (element-type Clutter.Effect): a list
15630 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15631 * list are owned by Clutter and they should not be freed. You should
15632 * free the returned list using g_list_free() when done
15637 clutter_actor_get_effects (ClutterActor *self)
15639 ClutterActorPrivate *priv;
15641 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15645 if (priv->effects == NULL)
15648 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15652 * clutter_actor_get_effect:
15653 * @self: a #ClutterActor
15654 * @name: the name of the effect to retrieve
15656 * Retrieves the #ClutterEffect with the given name in the list
15657 * of effects applied to @self
15659 * Return value: (transfer none): a #ClutterEffect for the given
15660 * name, or %NULL. The returned #ClutterEffect is owned by the
15661 * actor and it should not be unreferenced directly
15666 clutter_actor_get_effect (ClutterActor *self,
15669 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15670 g_return_val_if_fail (name != NULL, NULL);
15672 if (self->priv->effects == NULL)
15675 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15679 * clutter_actor_clear_effects:
15680 * @self: a #ClutterActor
15682 * Clears the list of effects applied to @self
15687 clutter_actor_clear_effects (ClutterActor *self)
15689 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15691 if (self->priv->effects == NULL)
15694 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15696 clutter_actor_queue_redraw (self);
15700 * clutter_actor_has_key_focus:
15701 * @self: a #ClutterActor
15703 * Checks whether @self is the #ClutterActor that has key focus
15705 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15710 clutter_actor_has_key_focus (ClutterActor *self)
15712 ClutterActor *stage;
15714 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15716 stage = _clutter_actor_get_stage_internal (self);
15720 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15724 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15725 ClutterPaintVolume *pv)
15727 ClutterActorPrivate *priv = self->priv;
15729 /* Actors are only expected to report a valid paint volume
15730 * while they have a valid allocation. */
15731 if (G_UNLIKELY (priv->needs_allocation))
15733 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15734 "Actor needs allocation",
15735 _clutter_actor_get_debug_name (self));
15739 /* Check if there are any handlers connected to the paint
15740 * signal. If there are then all bets are off for what the paint
15741 * volume for this actor might possibly be!
15743 * XXX: It's expected that this is going to end up being quite a
15744 * costly check to have to do here, but we haven't come up with
15745 * another solution that can reliably catch paint signal handlers at
15746 * the right time to either avoid artefacts due to invalid stage
15747 * clipping or due to incorrect culling.
15749 * Previously we checked in clutter_actor_paint(), but at that time
15750 * we may already be using a stage clip that could be derived from
15751 * an invalid paint-volume. We used to try and handle that by
15752 * queuing a follow up, unclipped, redraw but still the previous
15753 * checking wasn't enough to catch invalid volumes involved in
15754 * culling (considering that containers may derive their volume from
15755 * children that haven't yet been painted)
15757 * Longer term, improved solutions could be:
15758 * - Disallow painting in the paint signal, only allow using it
15759 * for tracking when paints happen. We can add another API that
15760 * allows monkey patching the paint of arbitrary actors but in a
15761 * more controlled way and that also supports modifying the
15763 * - If we could be notified somehow when signal handlers are
15764 * connected we wouldn't have to poll for handlers like this.
15766 if (g_signal_has_handler_pending (self,
15767 actor_signals[PAINT],
15771 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15772 "Actor has \"paint\" signal handlers",
15773 _clutter_actor_get_debug_name (self));
15777 _clutter_paint_volume_init_static (pv, self);
15779 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15781 clutter_paint_volume_free (pv);
15782 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15783 "Actor failed to report a volume",
15784 _clutter_actor_get_debug_name (self));
15788 /* since effects can modify the paint volume, we allow them to actually
15789 * do this by making get_paint_volume() "context sensitive"
15791 if (priv->effects != NULL)
15793 if (priv->current_effect != NULL)
15795 const GList *effects, *l;
15797 /* if we are being called from within the paint sequence of
15798 * an actor, get the paint volume up to the current effect
15800 effects = _clutter_meta_group_peek_metas (priv->effects);
15802 l != NULL || (l != NULL && l->data != priv->current_effect);
15805 if (!_clutter_effect_get_paint_volume (l->data, pv))
15807 clutter_paint_volume_free (pv);
15808 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15809 "Effect (%s) failed to report a volume",
15810 _clutter_actor_get_debug_name (self),
15811 _clutter_actor_meta_get_debug_name (l->data));
15818 const GList *effects, *l;
15820 /* otherwise, get the cumulative volume */
15821 effects = _clutter_meta_group_peek_metas (priv->effects);
15822 for (l = effects; l != NULL; l = l->next)
15823 if (!_clutter_effect_get_paint_volume (l->data, pv))
15825 clutter_paint_volume_free (pv);
15826 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15827 "Effect (%s) failed to report a volume",
15828 _clutter_actor_get_debug_name (self),
15829 _clutter_actor_meta_get_debug_name (l->data));
15838 /* The public clutter_actor_get_paint_volume API returns a const
15839 * pointer since we return a pointer directly to the cached
15840 * PaintVolume associated with the actor and don't want the user to
15841 * inadvertently modify it, but for internal uses we sometimes need
15842 * access to the same PaintVolume but need to apply some book-keeping
15843 * modifications to it so we don't want a const pointer.
15845 static ClutterPaintVolume *
15846 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15848 ClutterActorPrivate *priv;
15852 if (priv->paint_volume_valid)
15853 clutter_paint_volume_free (&priv->paint_volume);
15855 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15857 priv->paint_volume_valid = TRUE;
15858 return &priv->paint_volume;
15862 priv->paint_volume_valid = FALSE;
15868 * clutter_actor_get_paint_volume:
15869 * @self: a #ClutterActor
15871 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15872 * when a paint volume can't be determined.
15874 * The paint volume is defined as the 3D space occupied by an actor
15875 * when being painted.
15877 * This function will call the <function>get_paint_volume()</function>
15878 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15879 * should not usually care about overriding the default implementation,
15880 * unless they are, for instance: painting outside their allocation, or
15881 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15884 * <note>2D actors overriding <function>get_paint_volume()</function>
15885 * ensure their volume has a depth of 0. (This will be true so long as
15886 * you don't call clutter_paint_volume_set_depth().)</note>
15888 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15889 * or %NULL if no volume could be determined. The returned pointer
15890 * is not guaranteed to be valid across multiple frames; if you want
15891 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15895 const ClutterPaintVolume *
15896 clutter_actor_get_paint_volume (ClutterActor *self)
15898 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15900 return _clutter_actor_get_paint_volume_mutable (self);
15904 * clutter_actor_get_transformed_paint_volume:
15905 * @self: a #ClutterActor
15906 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15907 * (or %NULL for the stage)
15909 * Retrieves the 3D paint volume of an actor like
15910 * clutter_actor_get_paint_volume() does (Please refer to the
15911 * documentation of clutter_actor_get_paint_volume() for more
15912 * details.) and it additionally transforms the paint volume into the
15913 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15914 * is passed for @relative_to_ancestor)
15916 * This can be used by containers that base their paint volume on
15917 * the volume of their children. Such containers can query the
15918 * transformed paint volume of all of its children and union them
15919 * together using clutter_paint_volume_union().
15921 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15922 * or %NULL if no volume could be determined. The returned pointer is
15923 * not guaranteed to be valid across multiple frames; if you wish to
15924 * keep it, you will have to copy it using clutter_paint_volume_copy().
15928 const ClutterPaintVolume *
15929 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15930 ClutterActor *relative_to_ancestor)
15932 const ClutterPaintVolume *volume;
15933 ClutterActor *stage;
15934 ClutterPaintVolume *transformed_volume;
15936 stage = _clutter_actor_get_stage_internal (self);
15937 if (G_UNLIKELY (stage == NULL))
15940 if (relative_to_ancestor == NULL)
15941 relative_to_ancestor = stage;
15943 volume = clutter_actor_get_paint_volume (self);
15944 if (volume == NULL)
15947 transformed_volume =
15948 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15950 _clutter_paint_volume_copy_static (volume, transformed_volume);
15952 _clutter_paint_volume_transform_relative (transformed_volume,
15953 relative_to_ancestor);
15955 return transformed_volume;
15959 * clutter_actor_get_paint_box:
15960 * @self: a #ClutterActor
15961 * @box: (out): return location for a #ClutterActorBox
15963 * Retrieves the paint volume of the passed #ClutterActor, and
15964 * transforms it into a 2D bounding box in stage coordinates.
15966 * This function is useful to determine the on screen area occupied by
15967 * the actor. The box is only an approximation and may often be
15968 * considerably larger due to the optimizations used to calculate the
15969 * box. The box is never smaller though, so it can reliably be used
15972 * There are times when a 2D paint box can't be determined, e.g.
15973 * because the actor isn't yet parented under a stage or because
15974 * the actor is unable to determine a paint volume.
15976 * Return value: %TRUE if a 2D paint box could be determined, else
15982 clutter_actor_get_paint_box (ClutterActor *self,
15983 ClutterActorBox *box)
15985 ClutterActor *stage;
15986 ClutterPaintVolume *pv;
15988 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15989 g_return_val_if_fail (box != NULL, FALSE);
15991 stage = _clutter_actor_get_stage_internal (self);
15992 if (G_UNLIKELY (!stage))
15995 pv = _clutter_actor_get_paint_volume_mutable (self);
15996 if (G_UNLIKELY (!pv))
15999 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
16005 * clutter_actor_has_overlaps:
16006 * @self: A #ClutterActor
16008 * Asks the actor's implementation whether it may contain overlapping
16011 * For example; Clutter may use this to determine whether the painting
16012 * should be redirected to an offscreen buffer to correctly implement
16013 * the opacity property.
16015 * Custom actors can override the default response by implementing the
16016 * #ClutterActor <function>has_overlaps</function> virtual function. See
16017 * clutter_actor_set_offscreen_redirect() for more information.
16019 * Return value: %TRUE if the actor may have overlapping primitives, and
16025 clutter_actor_has_overlaps (ClutterActor *self)
16027 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
16029 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
16033 * clutter_actor_has_effects:
16034 * @self: A #ClutterActor
16036 * Returns whether the actor has any effects applied.
16038 * Return value: %TRUE if the actor has any effects,
16044 clutter_actor_has_effects (ClutterActor *self)
16046 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16048 if (self->priv->effects == NULL)
16051 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
16055 * clutter_actor_has_constraints:
16056 * @self: A #ClutterActor
16058 * Returns whether the actor has any constraints applied.
16060 * Return value: %TRUE if the actor has any constraints,
16066 clutter_actor_has_constraints (ClutterActor *self)
16068 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16070 return self->priv->constraints != NULL;
16074 * clutter_actor_has_actions:
16075 * @self: A #ClutterActor
16077 * Returns whether the actor has any actions applied.
16079 * Return value: %TRUE if the actor has any actions,
16085 clutter_actor_has_actions (ClutterActor *self)
16087 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16089 return self->priv->actions != NULL;
16093 * clutter_actor_get_n_children:
16094 * @self: a #ClutterActor
16096 * Retrieves the number of children of @self.
16098 * Return value: the number of children of an actor
16103 clutter_actor_get_n_children (ClutterActor *self)
16105 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
16107 return self->priv->n_children;
16111 * clutter_actor_get_child_at_index:
16112 * @self: a #ClutterActor
16113 * @index_: the position in the list of children
16115 * Retrieves the actor at the given @index_ inside the list of
16116 * children of @self.
16118 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16123 clutter_actor_get_child_at_index (ClutterActor *self,
16126 ClutterActor *iter;
16129 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16130 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
16132 for (iter = self->priv->first_child, i = 0;
16133 iter != NULL && i < index_;
16134 iter = iter->priv->next_sibling, i += 1)
16141 * _clutter_actor_foreach_child:
16142 * @actor: The actor whos children you want to iterate
16143 * @callback: The function to call for each child
16144 * @user_data: Private data to pass to @callback
16146 * Calls a given @callback once for each child of the specified @actor and
16147 * passing the @user_data pointer each time.
16149 * Return value: returns %TRUE if all children were iterated, else
16150 * %FALSE if a callback broke out of iteration early.
16153 _clutter_actor_foreach_child (ClutterActor *self,
16154 ClutterForeachCallback callback,
16155 gpointer user_data)
16157 ClutterActor *iter;
16160 if (self->priv->first_child == NULL)
16164 iter = self->priv->first_child;
16166 /* we use this form so that it's safe to change the children
16167 * list while iterating it
16169 while (cont && iter != NULL)
16171 ClutterActor *next = iter->priv->next_sibling;
16173 cont = callback (iter, user_data);
16182 /* For debugging purposes this gives us a simple way to print out
16183 * the scenegraph e.g in gdb using:
16185 * _clutter_actor_traverse (stage,
16187 * clutter_debug_print_actor_cb,
16192 static ClutterActorTraverseVisitFlags
16193 clutter_debug_print_actor_cb (ClutterActor *actor,
16197 g_print ("%*s%s:%p\n",
16199 _clutter_actor_get_debug_name (actor),
16202 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16207 _clutter_actor_traverse_breadth (ClutterActor *actor,
16208 ClutterTraverseCallback callback,
16209 gpointer user_data)
16211 GQueue *queue = g_queue_new ();
16212 ClutterActor dummy;
16213 int current_depth = 0;
16215 g_queue_push_tail (queue, actor);
16216 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
16218 while ((actor = g_queue_pop_head (queue)))
16220 ClutterActorTraverseVisitFlags flags;
16222 if (actor == &dummy)
16225 g_queue_push_tail (queue, &dummy);
16229 flags = callback (actor, current_depth, user_data);
16230 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16232 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16234 ClutterActor *iter;
16236 for (iter = actor->priv->first_child;
16238 iter = iter->priv->next_sibling)
16240 g_queue_push_tail (queue, iter);
16245 g_queue_free (queue);
16248 static ClutterActorTraverseVisitFlags
16249 _clutter_actor_traverse_depth (ClutterActor *actor,
16250 ClutterTraverseCallback before_children_callback,
16251 ClutterTraverseCallback after_children_callback,
16253 gpointer user_data)
16255 ClutterActorTraverseVisitFlags flags;
16257 flags = before_children_callback (actor, current_depth, user_data);
16258 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16259 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16261 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16263 ClutterActor *iter;
16265 for (iter = actor->priv->first_child;
16267 iter = iter->priv->next_sibling)
16269 flags = _clutter_actor_traverse_depth (iter,
16270 before_children_callback,
16271 after_children_callback,
16275 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16276 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16280 if (after_children_callback)
16281 return after_children_callback (actor, current_depth, user_data);
16283 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16286 /* _clutter_actor_traverse:
16287 * @actor: The actor to start traversing the graph from
16288 * @flags: These flags may affect how the traversal is done
16289 * @before_children_callback: A function to call before visiting the
16290 * children of the current actor.
16291 * @after_children_callback: A function to call after visiting the
16292 * children of the current actor. (Ignored if
16293 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16294 * @user_data: The private data to pass to the callbacks
16296 * Traverses the scenegraph starting at the specified @actor and
16297 * descending through all its children and its children's children.
16298 * For each actor traversed @before_children_callback and
16299 * @after_children_callback are called with the specified
16300 * @user_data, before and after visiting that actor's children.
16302 * The callbacks can return flags that affect the ongoing traversal
16303 * such as by skipping over an actors children or bailing out of
16304 * any further traversing.
16307 _clutter_actor_traverse (ClutterActor *actor,
16308 ClutterActorTraverseFlags flags,
16309 ClutterTraverseCallback before_children_callback,
16310 ClutterTraverseCallback after_children_callback,
16311 gpointer user_data)
16313 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16314 _clutter_actor_traverse_breadth (actor,
16315 before_children_callback,
16317 else /* DEPTH_FIRST */
16318 _clutter_actor_traverse_depth (actor,
16319 before_children_callback,
16320 after_children_callback,
16321 0, /* start depth */
16326 on_layout_manager_changed (ClutterLayoutManager *manager,
16327 ClutterActor *self)
16329 clutter_actor_queue_relayout (self);
16333 * clutter_actor_set_layout_manager:
16334 * @self: a #ClutterActor
16335 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16337 * Sets the #ClutterLayoutManager delegate object that will be used to
16338 * lay out the children of @self.
16340 * The #ClutterActor will take a reference on the passed @manager which
16341 * will be released either when the layout manager is removed, or when
16342 * the actor is destroyed.
16347 clutter_actor_set_layout_manager (ClutterActor *self,
16348 ClutterLayoutManager *manager)
16350 ClutterActorPrivate *priv;
16352 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16353 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16357 if (priv->layout_manager != NULL)
16359 g_signal_handlers_disconnect_by_func (priv->layout_manager,
16360 G_CALLBACK (on_layout_manager_changed),
16362 clutter_layout_manager_set_container (priv->layout_manager, NULL);
16363 g_clear_object (&priv->layout_manager);
16366 priv->layout_manager = manager;
16368 if (priv->layout_manager != NULL)
16370 g_object_ref_sink (priv->layout_manager);
16371 clutter_layout_manager_set_container (priv->layout_manager,
16372 CLUTTER_CONTAINER (self));
16373 g_signal_connect (priv->layout_manager, "layout-changed",
16374 G_CALLBACK (on_layout_manager_changed),
16378 clutter_actor_queue_relayout (self);
16380 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16384 * clutter_actor_get_layout_manager:
16385 * @self: a #ClutterActor
16387 * Retrieves the #ClutterLayoutManager used by @self.
16389 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16394 ClutterLayoutManager *
16395 clutter_actor_get_layout_manager (ClutterActor *self)
16397 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16399 return self->priv->layout_manager;
16402 static const ClutterLayoutInfo default_layout_info = {
16403 CLUTTER_POINT_INIT_ZERO, /* fixed-pos */
16404 { 0, 0, 0, 0 }, /* margin */
16405 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
16406 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
16407 FALSE, FALSE, /* expand */
16408 CLUTTER_SIZE_INIT_ZERO, /* minimum */
16409 CLUTTER_SIZE_INIT_ZERO, /* natural */
16413 layout_info_free (gpointer data)
16415 if (G_LIKELY (data != NULL))
16416 g_slice_free (ClutterLayoutInfo, data);
16420 * _clutter_actor_peek_layout_info:
16421 * @self: a #ClutterActor
16423 * Retrieves a pointer to the ClutterLayoutInfo structure.
16425 * If the actor does not have a ClutterLayoutInfo associated to it, %NULL is returned.
16427 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16429 ClutterLayoutInfo *
16430 _clutter_actor_peek_layout_info (ClutterActor *self)
16432 return g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16436 * _clutter_actor_get_layout_info:
16437 * @self: a #ClutterActor
16439 * Retrieves a pointer to the ClutterLayoutInfo structure.
16441 * If the actor does not have a ClutterLayoutInfo associated to it, one
16442 * will be created and initialized to the default values.
16444 * This function should be used for setters.
16446 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16449 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16451 ClutterLayoutInfo *
16452 _clutter_actor_get_layout_info (ClutterActor *self)
16454 ClutterLayoutInfo *retval;
16456 retval = _clutter_actor_peek_layout_info (self);
16457 if (retval == NULL)
16459 retval = g_slice_new (ClutterLayoutInfo);
16461 *retval = default_layout_info;
16463 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16472 * _clutter_actor_get_layout_info_or_defaults:
16473 * @self: a #ClutterActor
16475 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16477 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16478 * then the default structure will be returned.
16480 * This function should only be used for getters.
16482 * Return value: a const pointer to the ClutterLayoutInfo structure
16484 const ClutterLayoutInfo *
16485 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16487 const ClutterLayoutInfo *info;
16489 info = _clutter_actor_peek_layout_info (self);
16491 return &default_layout_info;
16497 * clutter_actor_set_x_align:
16498 * @self: a #ClutterActor
16499 * @x_align: the horizontal alignment policy
16501 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16502 * actor received extra horizontal space.
16504 * See also the #ClutterActor:x-align property.
16509 clutter_actor_set_x_align (ClutterActor *self,
16510 ClutterActorAlign x_align)
16512 ClutterLayoutInfo *info;
16514 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16516 info = _clutter_actor_get_layout_info (self);
16518 if (info->x_align != x_align)
16520 info->x_align = x_align;
16522 clutter_actor_queue_relayout (self);
16524 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16529 * clutter_actor_get_x_align:
16530 * @self: a #ClutterActor
16532 * Retrieves the horizontal alignment policy set using
16533 * clutter_actor_set_x_align().
16535 * Return value: the horizontal alignment policy.
16540 clutter_actor_get_x_align (ClutterActor *self)
16542 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16544 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16548 * clutter_actor_set_y_align:
16549 * @self: a #ClutterActor
16550 * @y_align: the vertical alignment policy
16552 * Sets the vertical alignment policy of a #ClutterActor, in case the
16553 * actor received extra vertical space.
16555 * See also the #ClutterActor:y-align property.
16560 clutter_actor_set_y_align (ClutterActor *self,
16561 ClutterActorAlign y_align)
16563 ClutterLayoutInfo *info;
16565 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16567 info = _clutter_actor_get_layout_info (self);
16569 if (info->y_align != y_align)
16571 info->y_align = y_align;
16573 clutter_actor_queue_relayout (self);
16575 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16580 * clutter_actor_get_y_align:
16581 * @self: a #ClutterActor
16583 * Retrieves the vertical alignment policy set using
16584 * clutter_actor_set_y_align().
16586 * Return value: the vertical alignment policy.
16591 clutter_actor_get_y_align (ClutterActor *self)
16593 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16595 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16599 * clutter_actor_set_margin:
16600 * @self: a #ClutterActor
16601 * @margin: a #ClutterMargin
16603 * Sets all the components of the margin of a #ClutterActor.
16608 clutter_actor_set_margin (ClutterActor *self,
16609 const ClutterMargin *margin)
16611 ClutterLayoutInfo *info;
16615 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16616 g_return_if_fail (margin != NULL);
16618 obj = G_OBJECT (self);
16621 g_object_freeze_notify (obj);
16623 info = _clutter_actor_get_layout_info (self);
16625 if (info->margin.top != margin->top)
16627 info->margin.top = margin->top;
16628 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16632 if (info->margin.right != margin->right)
16634 info->margin.right = margin->right;
16635 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16639 if (info->margin.bottom != margin->bottom)
16641 info->margin.bottom = margin->bottom;
16642 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16646 if (info->margin.left != margin->left)
16648 info->margin.left = margin->left;
16649 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16654 clutter_actor_queue_relayout (self);
16656 g_object_thaw_notify (obj);
16660 * clutter_actor_get_margin:
16661 * @self: a #ClutterActor
16662 * @margin: (out caller-allocates): return location for a #ClutterMargin
16664 * Retrieves all the components of the margin of a #ClutterActor.
16669 clutter_actor_get_margin (ClutterActor *self,
16670 ClutterMargin *margin)
16672 const ClutterLayoutInfo *info;
16674 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16675 g_return_if_fail (margin != NULL);
16677 info = _clutter_actor_get_layout_info_or_defaults (self);
16679 *margin = info->margin;
16683 * clutter_actor_set_margin_top:
16684 * @self: a #ClutterActor
16685 * @margin: the top margin
16687 * Sets the margin from the top of a #ClutterActor.
16692 clutter_actor_set_margin_top (ClutterActor *self,
16695 ClutterLayoutInfo *info;
16697 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16698 g_return_if_fail (margin >= 0.f);
16700 info = _clutter_actor_get_layout_info (self);
16702 if (info->margin.top == margin)
16705 info->margin.top = margin;
16707 clutter_actor_queue_relayout (self);
16709 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16713 * clutter_actor_get_margin_top:
16714 * @self: a #ClutterActor
16716 * Retrieves the top margin of a #ClutterActor.
16718 * Return value: the top margin
16723 clutter_actor_get_margin_top (ClutterActor *self)
16725 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16727 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16731 * clutter_actor_set_margin_bottom:
16732 * @self: a #ClutterActor
16733 * @margin: the bottom margin
16735 * Sets the margin from the bottom of a #ClutterActor.
16740 clutter_actor_set_margin_bottom (ClutterActor *self,
16743 ClutterLayoutInfo *info;
16745 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16746 g_return_if_fail (margin >= 0.f);
16748 info = _clutter_actor_get_layout_info (self);
16750 if (info->margin.bottom == margin)
16753 info->margin.bottom = margin;
16755 clutter_actor_queue_relayout (self);
16757 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16761 * clutter_actor_get_margin_bottom:
16762 * @self: a #ClutterActor
16764 * Retrieves the bottom margin of a #ClutterActor.
16766 * Return value: the bottom margin
16771 clutter_actor_get_margin_bottom (ClutterActor *self)
16773 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16775 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16779 * clutter_actor_set_margin_left:
16780 * @self: a #ClutterActor
16781 * @margin: the left margin
16783 * Sets the margin from the left of a #ClutterActor.
16788 clutter_actor_set_margin_left (ClutterActor *self,
16791 ClutterLayoutInfo *info;
16793 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16794 g_return_if_fail (margin >= 0.f);
16796 info = _clutter_actor_get_layout_info (self);
16798 if (info->margin.left == margin)
16801 info->margin.left = margin;
16803 clutter_actor_queue_relayout (self);
16805 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16809 * clutter_actor_get_margin_left:
16810 * @self: a #ClutterActor
16812 * Retrieves the left margin of a #ClutterActor.
16814 * Return value: the left margin
16819 clutter_actor_get_margin_left (ClutterActor *self)
16821 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16823 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16827 * clutter_actor_set_margin_right:
16828 * @self: a #ClutterActor
16829 * @margin: the right margin
16831 * Sets the margin from the right of a #ClutterActor.
16836 clutter_actor_set_margin_right (ClutterActor *self,
16839 ClutterLayoutInfo *info;
16841 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16842 g_return_if_fail (margin >= 0.f);
16844 info = _clutter_actor_get_layout_info (self);
16846 if (info->margin.right == margin)
16849 info->margin.right = margin;
16851 clutter_actor_queue_relayout (self);
16853 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16857 * clutter_actor_get_margin_right:
16858 * @self: a #ClutterActor
16860 * Retrieves the right margin of a #ClutterActor.
16862 * Return value: the right margin
16867 clutter_actor_get_margin_right (ClutterActor *self)
16869 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16871 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16875 clutter_actor_set_background_color_internal (ClutterActor *self,
16876 const ClutterColor *color)
16878 ClutterActorPrivate *priv = self->priv;
16881 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16884 obj = G_OBJECT (self);
16886 priv->bg_color = *color;
16887 priv->bg_color_set = TRUE;
16889 clutter_actor_queue_redraw (self);
16891 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16892 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16896 * clutter_actor_set_background_color:
16897 * @self: a #ClutterActor
16898 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16901 * Sets the background color of a #ClutterActor.
16903 * The background color will be used to cover the whole allocation of the
16904 * actor. The default background color of an actor is transparent.
16906 * To check whether an actor has a background color, you can use the
16907 * #ClutterActor:background-color-set actor property.
16909 * The #ClutterActor:background-color property is animatable.
16914 clutter_actor_set_background_color (ClutterActor *self,
16915 const ClutterColor *color)
16917 ClutterActorPrivate *priv;
16919 GParamSpec *bg_color_pspec;
16921 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16923 obj = G_OBJECT (self);
16929 priv->bg_color_set = FALSE;
16930 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16931 clutter_actor_queue_redraw (self);
16935 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16936 if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16938 _clutter_actor_create_transition (self, bg_color_pspec,
16943 _clutter_actor_update_transition (self, bg_color_pspec, color);
16945 clutter_actor_queue_redraw (self);
16949 * clutter_actor_get_background_color:
16950 * @self: a #ClutterActor
16951 * @color: (out caller-allocates): return location for a #ClutterColor
16953 * Retrieves the color set using clutter_actor_set_background_color().
16958 clutter_actor_get_background_color (ClutterActor *self,
16959 ClutterColor *color)
16961 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16962 g_return_if_fail (color != NULL);
16964 *color = self->priv->bg_color;
16968 * clutter_actor_get_previous_sibling:
16969 * @self: a #ClutterActor
16971 * Retrieves the sibling of @self that comes before it in the list
16972 * of children of @self's parent.
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_previous_sibling (ClutterActor *self)
16985 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16987 return self->priv->prev_sibling;
16991 * clutter_actor_get_next_sibling:
16992 * @self: a #ClutterActor
16994 * Retrieves the sibling of @self that comes after it in the list
16995 * of children of @self's parent.
16997 * The returned pointer is only valid until the scene graph changes; it
16998 * is not safe to modify the list of children of @self while iterating
17001 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
17006 clutter_actor_get_next_sibling (ClutterActor *self)
17008 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17010 return self->priv->next_sibling;
17014 * clutter_actor_get_first_child:
17015 * @self: a #ClutterActor
17017 * Retrieves the first child of @self.
17019 * The returned pointer is only valid until the scene graph changes; it
17020 * is not safe to modify the list of children of @self while iterating
17023 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
17028 clutter_actor_get_first_child (ClutterActor *self)
17030 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17032 return self->priv->first_child;
17036 * clutter_actor_get_last_child:
17037 * @self: a #ClutterActor
17039 * Retrieves the last child of @self.
17041 * The returned pointer is only valid until the scene graph changes; it
17042 * is not safe to modify the list of children of @self while iterating
17045 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
17050 clutter_actor_get_last_child (ClutterActor *self)
17052 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17054 return self->priv->last_child;
17057 /* easy way to have properly named fields instead of the dummy ones
17058 * we use in the public structure
17060 typedef struct _RealActorIter
17062 ClutterActor *root; /* dummy1 */
17063 ClutterActor *current; /* dummy2 */
17064 gpointer padding_1; /* dummy3 */
17065 gint age; /* dummy4 */
17066 gpointer padding_2; /* dummy5 */
17070 * clutter_actor_iter_init:
17071 * @iter: a #ClutterActorIter
17072 * @root: a #ClutterActor
17074 * Initializes a #ClutterActorIter, which can then be used to iterate
17075 * efficiently over a section of the scene graph, and associates it
17078 * Modifying the scene graph section that contains @root will invalidate
17082 * ClutterActorIter iter;
17083 * ClutterActor *child;
17085 * clutter_actor_iter_init (&iter, container);
17086 * while (clutter_actor_iter_next (&iter, &child))
17088 * /* do something with child */
17095 clutter_actor_iter_init (ClutterActorIter *iter,
17096 ClutterActor *root)
17098 RealActorIter *ri = (RealActorIter *) iter;
17100 g_return_if_fail (iter != NULL);
17101 g_return_if_fail (CLUTTER_IS_ACTOR (root));
17104 ri->current = NULL;
17105 ri->age = root->priv->age;
17109 * clutter_actor_iter_next:
17110 * @iter: a #ClutterActorIter
17111 * @child: (out): return location for a #ClutterActor
17113 * Advances the @iter and retrieves the next child of the root #ClutterActor
17114 * that was used to initialize the #ClutterActorIterator.
17116 * If the iterator can advance, this function returns %TRUE and sets the
17119 * If the iterator cannot advance, this function returns %FALSE, and
17120 * the contents of @child are undefined.
17122 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17127 clutter_actor_iter_next (ClutterActorIter *iter,
17128 ClutterActor **child)
17130 RealActorIter *ri = (RealActorIter *) iter;
17132 g_return_val_if_fail (iter != NULL, FALSE);
17133 g_return_val_if_fail (ri->root != NULL, FALSE);
17134 #ifndef G_DISABLE_ASSERT
17135 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17138 if (ri->current == NULL)
17139 ri->current = ri->root->priv->first_child;
17141 ri->current = ri->current->priv->next_sibling;
17144 *child = ri->current;
17146 return ri->current != NULL;
17150 * clutter_actor_iter_prev:
17151 * @iter: a #ClutterActorIter
17152 * @child: (out): return location for a #ClutterActor
17154 * Advances the @iter and retrieves the previous child of the root
17155 * #ClutterActor that was used to initialize the #ClutterActorIterator.
17157 * If the iterator can advance, this function returns %TRUE and sets the
17160 * If the iterator cannot advance, this function returns %FALSE, and
17161 * the contents of @child are undefined.
17163 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17168 clutter_actor_iter_prev (ClutterActorIter *iter,
17169 ClutterActor **child)
17171 RealActorIter *ri = (RealActorIter *) iter;
17173 g_return_val_if_fail (iter != NULL, FALSE);
17174 g_return_val_if_fail (ri->root != NULL, FALSE);
17175 #ifndef G_DISABLE_ASSERT
17176 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17179 if (ri->current == NULL)
17180 ri->current = ri->root->priv->last_child;
17182 ri->current = ri->current->priv->prev_sibling;
17185 *child = ri->current;
17187 return ri->current != NULL;
17191 * clutter_actor_iter_remove:
17192 * @iter: a #ClutterActorIter
17194 * Safely removes the #ClutterActor currently pointer to by the iterator
17197 * This function can only be called after clutter_actor_iter_next() or
17198 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17199 * than once for the same actor.
17201 * This function will call clutter_actor_remove_child() internally.
17206 clutter_actor_iter_remove (ClutterActorIter *iter)
17208 RealActorIter *ri = (RealActorIter *) iter;
17211 g_return_if_fail (iter != NULL);
17212 g_return_if_fail (ri->root != NULL);
17213 #ifndef G_DISABLE_ASSERT
17214 g_return_if_fail (ri->age == ri->root->priv->age);
17216 g_return_if_fail (ri->current != NULL);
17222 ri->current = cur->priv->prev_sibling;
17224 clutter_actor_remove_child_internal (ri->root, cur,
17225 REMOVE_CHILD_DEFAULT_FLAGS);
17232 * clutter_actor_iter_destroy:
17233 * @iter: a #ClutterActorIter
17235 * Safely destroys the #ClutterActor currently pointer to by the iterator
17238 * This function can only be called after clutter_actor_iter_next() or
17239 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17240 * than once for the same actor.
17242 * This function will call clutter_actor_destroy() internally.
17247 clutter_actor_iter_destroy (ClutterActorIter *iter)
17249 RealActorIter *ri = (RealActorIter *) iter;
17252 g_return_if_fail (iter != NULL);
17253 g_return_if_fail (ri->root != NULL);
17254 #ifndef G_DISABLE_ASSERT
17255 g_return_if_fail (ri->age == ri->root->priv->age);
17257 g_return_if_fail (ri->current != NULL);
17263 ri->current = cur->priv->prev_sibling;
17265 clutter_actor_destroy (cur);
17271 static const ClutterAnimationInfo default_animation_info = {
17272 NULL, /* transitions */
17274 NULL, /* cur_state */
17278 clutter_animation_info_free (gpointer data)
17282 ClutterAnimationInfo *info = data;
17284 if (info->transitions != NULL)
17285 g_hash_table_unref (info->transitions);
17287 if (info->states != NULL)
17288 g_array_unref (info->states);
17290 g_slice_free (ClutterAnimationInfo, info);
17294 const ClutterAnimationInfo *
17295 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17297 const ClutterAnimationInfo *res;
17298 GObject *obj = G_OBJECT (self);
17300 res = g_object_get_qdata (obj, quark_actor_animation_info);
17304 return &default_animation_info;
17307 ClutterAnimationInfo *
17308 _clutter_actor_get_animation_info (ClutterActor *self)
17310 GObject *obj = G_OBJECT (self);
17311 ClutterAnimationInfo *res;
17313 res = g_object_get_qdata (obj, quark_actor_animation_info);
17316 res = g_slice_new (ClutterAnimationInfo);
17318 *res = default_animation_info;
17320 g_object_set_qdata_full (obj, quark_actor_animation_info,
17322 clutter_animation_info_free);
17328 ClutterTransition *
17329 _clutter_actor_get_transition (ClutterActor *actor,
17332 const ClutterAnimationInfo *info;
17334 info = _clutter_actor_get_animation_info_or_defaults (actor);
17336 if (info->transitions == NULL)
17339 return g_hash_table_lookup (info->transitions, pspec->name);
17343 transition_closure_free (gpointer data)
17345 if (G_LIKELY (data != NULL))
17347 TransitionClosure *clos = data;
17348 ClutterTimeline *timeline;
17350 timeline = CLUTTER_TIMELINE (clos->transition);
17352 if (clutter_timeline_is_playing (timeline))
17353 clutter_timeline_stop (timeline);
17355 g_signal_handler_disconnect (clos->transition, clos->completed_id);
17357 g_object_unref (clos->transition);
17358 g_free (clos->name);
17360 g_slice_free (TransitionClosure, clos);
17365 on_transition_stopped (ClutterTransition *transition,
17366 gboolean is_finished,
17367 TransitionClosure *clos)
17369 ClutterActor *actor = clos->actor;
17370 ClutterAnimationInfo *info;
17372 /* reset the caches used by animations */
17373 clutter_actor_store_content_box (actor, NULL);
17378 info = _clutter_actor_get_animation_info (actor);
17380 /* we take a reference here because removing the closure
17381 * will release the reference on the transition, and we
17382 * want the transition to survive the signal emission;
17383 * the master clock will release the last reference at
17384 * the end of the frame processing.
17386 g_object_ref (transition);
17387 g_hash_table_remove (info->transitions, clos->name);
17389 /* if it's the last transition then we clean up */
17390 if (g_hash_table_size (info->transitions) == 0)
17392 g_hash_table_unref (info->transitions);
17393 info->transitions = NULL;
17395 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17396 _clutter_actor_get_debug_name (actor));
17398 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17403 _clutter_actor_update_transition (ClutterActor *actor,
17407 TransitionClosure *clos;
17408 ClutterTimeline *timeline;
17409 ClutterInterval *interval;
17410 const ClutterAnimationInfo *info;
17413 GValue initial = G_VALUE_INIT;
17414 GValue final = G_VALUE_INIT;
17415 char *error = NULL;
17417 info = _clutter_actor_get_animation_info_or_defaults (actor);
17419 if (info->transitions == NULL)
17422 clos = g_hash_table_lookup (info->transitions, pspec->name);
17426 timeline = CLUTTER_TIMELINE (clos->transition);
17428 va_start (var_args, pspec);
17430 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17432 g_value_init (&initial, ptype);
17433 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17437 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17440 g_critical ("%s: %s", G_STRLOC, error);
17445 interval = clutter_transition_get_interval (clos->transition);
17446 clutter_interval_set_initial_value (interval, &initial);
17447 clutter_interval_set_final_value (interval, &final);
17449 /* if we're updating with an easing duration of zero milliseconds,
17450 * we just jump the timeline to the end and let it run its course
17452 if (info->cur_state != NULL &&
17453 info->cur_state->easing_duration != 0)
17455 guint cur_duration = clutter_timeline_get_duration (timeline);
17456 ClutterAnimationMode cur_mode =
17457 clutter_timeline_get_progress_mode (timeline);
17459 if (cur_duration != info->cur_state->easing_duration)
17460 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17462 if (cur_mode != info->cur_state->easing_mode)
17463 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17465 clutter_timeline_rewind (timeline);
17469 guint duration = clutter_timeline_get_duration (timeline);
17471 clutter_timeline_advance (timeline, duration);
17475 g_value_unset (&initial);
17476 g_value_unset (&final);
17482 * _clutter_actor_create_transition:
17483 * @actor: a #ClutterActor
17484 * @pspec: the property used for the transition
17485 * @...: initial and final state
17487 * Creates a #ClutterTransition for the property represented by @pspec.
17489 * Return value: a #ClutterTransition
17491 ClutterTransition *
17492 _clutter_actor_create_transition (ClutterActor *actor,
17496 ClutterAnimationInfo *info;
17497 ClutterTransition *res = NULL;
17498 gboolean call_restore = FALSE;
17499 TransitionClosure *clos;
17502 info = _clutter_actor_get_animation_info (actor);
17504 /* XXX - this will go away in 2.0
17506 * if no state has been pushed, we assume that the easing state is
17507 * in "compatibility mode": all transitions have a duration of 0
17508 * msecs, which means that they happen immediately. in Clutter 2.0
17509 * this will turn into a g_assert(info->states != NULL), as every
17510 * actor will start with a predefined easing state
17512 if (info->states == NULL)
17514 clutter_actor_save_easing_state (actor);
17515 clutter_actor_set_easing_duration (actor, 0);
17516 call_restore = TRUE;
17519 if (info->transitions == NULL)
17520 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17522 transition_closure_free);
17524 va_start (var_args, pspec);
17526 clos = g_hash_table_lookup (info->transitions, pspec->name);
17529 ClutterTimeline *timeline;
17530 ClutterInterval *interval;
17531 GValue initial = G_VALUE_INIT;
17532 GValue final = G_VALUE_INIT;
17536 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17538 G_VALUE_COLLECT_INIT (&initial, ptype,
17543 g_critical ("%s: %s", G_STRLOC, error);
17548 G_VALUE_COLLECT_INIT (&final, ptype,
17554 g_critical ("%s: %s", G_STRLOC, error);
17555 g_value_unset (&initial);
17560 /* if the current easing state has a duration of 0, then we don't
17561 * bother to create the transition, and we just set the final value
17562 * directly on the actor; we don't go through the Animatable
17563 * interface because we know we got here through an animatable
17566 if (info->cur_state->easing_duration == 0)
17568 clutter_actor_set_animatable_property (actor,
17572 g_value_unset (&initial);
17573 g_value_unset (&final);
17578 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17580 g_value_unset (&initial);
17581 g_value_unset (&final);
17583 res = clutter_property_transition_new (pspec->name);
17585 clutter_transition_set_interval (res, interval);
17586 clutter_transition_set_remove_on_complete (res, TRUE);
17588 timeline = CLUTTER_TIMELINE (res);
17589 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17590 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17591 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17593 CLUTTER_NOTE (ANIMATION,
17594 "Created transition for %s:%s (len:%u, mode:%s, delay:%u)",
17595 _clutter_actor_get_debug_name (actor),
17597 info->cur_state->easing_duration,
17598 clutter_get_easing_name_for_mode (info->cur_state->easing_mode),
17599 info->cur_state->easing_delay);
17601 /* this will start the transition as well */
17602 clutter_actor_add_transition (actor, pspec->name, res);
17604 /* the actor now owns the transition */
17605 g_object_unref (res);
17608 res = clos->transition;
17612 clutter_actor_restore_easing_state (actor);
17620 * clutter_actor_add_transition:
17621 * @self: a #ClutterActor
17622 * @name: the name of the transition to add
17623 * @transition: the #ClutterTransition to add
17625 * Adds a @transition to the #ClutterActor's list of animations.
17627 * The @name string is a per-actor unique identifier of the @transition: only
17628 * one #ClutterTransition can be associated to the specified @name.
17630 * The @transition will be started once added.
17632 * This function will take a reference on the @transition.
17634 * This function is usually called implicitly when modifying an animatable
17640 clutter_actor_add_transition (ClutterActor *self,
17642 ClutterTransition *transition)
17644 ClutterTimeline *timeline;
17645 TransitionClosure *clos;
17646 ClutterAnimationInfo *info;
17648 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17649 g_return_if_fail (name != NULL);
17650 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17652 info = _clutter_actor_get_animation_info (self);
17654 if (info->transitions == NULL)
17655 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17657 transition_closure_free);
17659 if (g_hash_table_lookup (info->transitions, name) != NULL)
17661 g_warning ("A transition with name '%s' already exists for "
17664 _clutter_actor_get_debug_name (self));
17668 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17670 timeline = CLUTTER_TIMELINE (transition);
17672 clos = g_slice_new (TransitionClosure);
17673 clos->actor = self;
17674 clos->transition = g_object_ref (transition);
17675 clos->name = g_strdup (name);
17676 clos->completed_id = g_signal_connect (timeline, "stopped",
17677 G_CALLBACK (on_transition_stopped),
17680 CLUTTER_NOTE (ANIMATION,
17681 "Adding transition '%s' [%p] to actor '%s'",
17684 _clutter_actor_get_debug_name (self));
17686 g_hash_table_insert (info->transitions, clos->name, clos);
17687 clutter_timeline_start (timeline);
17691 * clutter_actor_remove_transition:
17692 * @self: a #ClutterActor
17693 * @name: the name of the transition to remove
17695 * Removes the transition stored inside a #ClutterActor using @name
17698 * If the transition is currently in progress, it will be stopped.
17700 * This function releases the reference acquired when the transition
17701 * was added to the #ClutterActor.
17706 clutter_actor_remove_transition (ClutterActor *self,
17709 const ClutterAnimationInfo *info;
17711 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17712 g_return_if_fail (name != NULL);
17714 info = _clutter_actor_get_animation_info_or_defaults (self);
17716 if (info->transitions == NULL)
17719 g_hash_table_remove (info->transitions, name);
17723 * clutter_actor_remove_all_transitions:
17724 * @self: a #ClutterActor
17726 * Removes all transitions associated to @self.
17731 clutter_actor_remove_all_transitions (ClutterActor *self)
17733 const ClutterAnimationInfo *info;
17735 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17737 info = _clutter_actor_get_animation_info_or_defaults (self);
17738 if (info->transitions == NULL)
17741 g_hash_table_remove_all (info->transitions);
17745 * clutter_actor_set_easing_duration:
17746 * @self: a #ClutterActor
17747 * @msecs: the duration of the easing, or %NULL
17749 * Sets the duration of the tweening for animatable properties
17750 * of @self for the current easing state.
17755 clutter_actor_set_easing_duration (ClutterActor *self,
17758 ClutterAnimationInfo *info;
17760 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17762 info = _clutter_actor_get_animation_info (self);
17764 if (info->cur_state == NULL)
17766 g_warning ("You must call clutter_actor_save_easing_state() prior "
17767 "to calling clutter_actor_set_easing_duration().");
17771 if (info->cur_state->easing_duration != msecs)
17772 info->cur_state->easing_duration = msecs;
17776 * clutter_actor_get_easing_duration:
17777 * @self: a #ClutterActor
17779 * Retrieves the duration of the tweening for animatable
17780 * properties of @self for the current easing state.
17782 * Return value: the duration of the tweening, in milliseconds
17787 clutter_actor_get_easing_duration (ClutterActor *self)
17789 const ClutterAnimationInfo *info;
17791 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17793 info = _clutter_actor_get_animation_info_or_defaults (self);
17795 if (info->cur_state != NULL)
17796 return info->cur_state->easing_duration;
17802 * clutter_actor_set_easing_mode:
17803 * @self: a #ClutterActor
17804 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17806 * Sets the easing mode for the tweening of animatable properties
17812 clutter_actor_set_easing_mode (ClutterActor *self,
17813 ClutterAnimationMode mode)
17815 ClutterAnimationInfo *info;
17817 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17818 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17819 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17821 info = _clutter_actor_get_animation_info (self);
17823 if (info->cur_state == NULL)
17825 g_warning ("You must call clutter_actor_save_easing_state() prior "
17826 "to calling clutter_actor_set_easing_mode().");
17830 if (info->cur_state->easing_mode != mode)
17831 info->cur_state->easing_mode = mode;
17835 * clutter_actor_get_easing_mode:
17836 * @self: a #ClutterActor
17838 * Retrieves the easing mode for the tweening of animatable properties
17839 * of @self for the current easing state.
17841 * Return value: an easing mode
17845 ClutterAnimationMode
17846 clutter_actor_get_easing_mode (ClutterActor *self)
17848 const ClutterAnimationInfo *info;
17850 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17852 info = _clutter_actor_get_animation_info_or_defaults (self);
17854 if (info->cur_state != NULL)
17855 return info->cur_state->easing_mode;
17857 return CLUTTER_EASE_OUT_CUBIC;
17861 * clutter_actor_set_easing_delay:
17862 * @self: a #ClutterActor
17863 * @msecs: the delay before the start of the tweening, in milliseconds
17865 * Sets the delay that should be applied before tweening animatable
17871 clutter_actor_set_easing_delay (ClutterActor *self,
17874 ClutterAnimationInfo *info;
17876 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17878 info = _clutter_actor_get_animation_info (self);
17880 if (info->cur_state == NULL)
17882 g_warning ("You must call clutter_actor_save_easing_state() prior "
17883 "to calling clutter_actor_set_easing_delay().");
17887 if (info->cur_state->easing_delay != msecs)
17888 info->cur_state->easing_delay = msecs;
17892 * clutter_actor_get_easing_delay:
17893 * @self: a #ClutterActor
17895 * Retrieves the delay that should be applied when tweening animatable
17898 * Return value: a delay, in milliseconds
17903 clutter_actor_get_easing_delay (ClutterActor *self)
17905 const ClutterAnimationInfo *info;
17907 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17909 info = _clutter_actor_get_animation_info_or_defaults (self);
17911 if (info->cur_state != NULL)
17912 return info->cur_state->easing_delay;
17918 * clutter_actor_get_transition:
17919 * @self: a #ClutterActor
17920 * @name: the name of the transition
17922 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17923 * transition @name.
17925 * Transitions created for animatable properties use the name of the
17926 * property itself, for instance the code below:
17929 * clutter_actor_set_easing_duration (actor, 1000);
17930 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17932 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17933 * g_signal_connect (transition, "stopped",
17934 * G_CALLBACK (on_transition_stopped),
17938 * will call the <function>on_transition_stopped</function> callback when
17939 * the transition is finished.
17941 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17942 * was found to match the passed name; the returned instance is owned
17943 * by Clutter and it should not be freed
17947 ClutterTransition *
17948 clutter_actor_get_transition (ClutterActor *self,
17951 TransitionClosure *clos;
17952 const ClutterAnimationInfo *info;
17954 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17955 g_return_val_if_fail (name != NULL, NULL);
17957 info = _clutter_actor_get_animation_info_or_defaults (self);
17958 if (info->transitions == NULL)
17961 clos = g_hash_table_lookup (info->transitions, name);
17965 return clos->transition;
17969 * clutter_actor_save_easing_state:
17970 * @self: a #ClutterActor
17972 * Saves the current easing state for animatable properties, and creates
17973 * a new state with the default values for easing mode and duration.
17978 clutter_actor_save_easing_state (ClutterActor *self)
17980 ClutterAnimationInfo *info;
17983 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17985 info = _clutter_actor_get_animation_info (self);
17987 if (info->states == NULL)
17988 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17990 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17991 new_state.easing_duration = 250;
17992 new_state.easing_delay = 0;
17994 g_array_append_val (info->states, new_state);
17996 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
18000 * clutter_actor_restore_easing_state:
18001 * @self: a #ClutterActor
18003 * Restores the easing state as it was prior to a call to
18004 * clutter_actor_save_easing_state().
18009 clutter_actor_restore_easing_state (ClutterActor *self)
18011 ClutterAnimationInfo *info;
18013 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18015 info = _clutter_actor_get_animation_info (self);
18017 if (info->states == NULL)
18019 g_critical ("The function clutter_actor_restore_easing_state() has "
18020 "called without a previous call to "
18021 "clutter_actor_save_easing_state().");
18025 g_array_remove_index (info->states, info->states->len - 1);
18027 if (info->states->len > 0)
18028 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
18031 g_array_unref (info->states);
18032 info->states = NULL;
18033 info->cur_state = NULL;
18038 * clutter_actor_set_content:
18039 * @self: a #ClutterActor
18040 * @content: (allow-none): a #ClutterContent, or %NULL
18042 * Sets the contents of a #ClutterActor.
18047 clutter_actor_set_content (ClutterActor *self,
18048 ClutterContent *content)
18050 ClutterActorPrivate *priv;
18052 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18053 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
18057 if (priv->content != NULL)
18059 _clutter_content_detached (priv->content, self);
18060 g_clear_object (&priv->content);
18063 priv->content = content;
18065 if (priv->content != NULL)
18067 g_object_ref (priv->content);
18068 _clutter_content_attached (priv->content, self);
18071 /* given that the content is always painted within the allocation,
18072 * we only need to queue a redraw here
18074 clutter_actor_queue_redraw (self);
18076 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
18078 /* if the content gravity is not resize-fill, and the new content has a
18079 * different preferred size than the previous one, then the content box
18080 * may have been changed. since we compute that lazily, we just notify
18081 * here, and let whomever watches :content-box do whatever they need to
18084 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18085 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
18089 * clutter_actor_get_content:
18090 * @self: a #ClutterActor
18092 * Retrieves the contents of @self.
18094 * Return value: (transfer none): a pointer to the #ClutterContent instance,
18095 * or %NULL if none was set
18100 clutter_actor_get_content (ClutterActor *self)
18102 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
18104 return self->priv->content;
18108 * clutter_actor_set_content_gravity:
18109 * @self: a #ClutterActor
18110 * @gravity: the #ClutterContentGravity
18112 * Sets the gravity of the #ClutterContent used by @self.
18114 * See the description of the #ClutterActor:content-gravity property for
18115 * more information.
18117 * The #ClutterActor:content-gravity property is animatable.
18122 clutter_actor_set_content_gravity (ClutterActor *self,
18123 ClutterContentGravity gravity)
18125 ClutterActorPrivate *priv;
18127 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18131 if (priv->content_gravity == gravity)
18134 priv->content_box_valid = FALSE;
18136 if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
18138 ClutterActorBox from_box, to_box;
18140 clutter_actor_get_content_box (self, &from_box);
18142 priv->content_gravity = gravity;
18144 clutter_actor_get_content_box (self, &to_box);
18146 _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
18152 ClutterActorBox to_box;
18154 priv->content_gravity = gravity;
18156 clutter_actor_get_content_box (self, &to_box);
18158 _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
18162 clutter_actor_queue_redraw (self);
18164 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
18168 * clutter_actor_get_content_gravity:
18169 * @self: a #ClutterActor
18171 * Retrieves the content gravity as set using
18172 * clutter_actor_get_content_gravity().
18174 * Return value: the content gravity
18178 ClutterContentGravity
18179 clutter_actor_get_content_gravity (ClutterActor *self)
18181 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
18182 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
18184 return self->priv->content_gravity;
18188 * clutter_actor_get_content_box:
18189 * @self: a #ClutterActor
18190 * @box: (out caller-allocates): the return location for the bounding
18191 * box for the #ClutterContent
18193 * Retrieves the bounding box for the #ClutterContent of @self.
18195 * The bounding box is relative to the actor's allocation.
18197 * If no #ClutterContent is set for @self, or if @self has not been
18198 * allocated yet, then the result is undefined.
18200 * The content box is guaranteed to be, at most, as big as the allocation
18201 * of the #ClutterActor.
18203 * If the #ClutterContent used by the actor has a preferred size, then
18204 * it is possible to modify the content box by using the
18205 * #ClutterActor:content-gravity property.
18210 clutter_actor_get_content_box (ClutterActor *self,
18211 ClutterActorBox *box)
18213 ClutterActorPrivate *priv;
18214 gfloat content_w, content_h;
18215 gfloat alloc_w, alloc_h;
18217 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18218 g_return_if_fail (box != NULL);
18224 box->x2 = priv->allocation.x2 - priv->allocation.x1;
18225 box->y2 = priv->allocation.y2 - priv->allocation.y1;
18227 if (priv->content_box_valid)
18229 *box = priv->content_box;
18233 /* no need to do any more work */
18234 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18237 if (priv->content == NULL)
18240 /* if the content does not have a preferred size then there is
18241 * no point in computing the content box
18243 if (!clutter_content_get_preferred_size (priv->content,
18251 switch (priv->content_gravity)
18253 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18254 box->x2 = box->x1 + MIN (content_w, alloc_w);
18255 box->y2 = box->y1 + MIN (content_h, alloc_h);
18258 case CLUTTER_CONTENT_GRAVITY_TOP:
18259 if (alloc_w > content_w)
18261 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18262 box->x2 = box->x1 + content_w;
18264 box->y2 = box->y1 + MIN (content_h, alloc_h);
18267 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18268 if (alloc_w > content_w)
18270 box->x1 += (alloc_w - content_w);
18271 box->x2 = box->x1 + content_w;
18273 box->y2 = box->y1 + MIN (content_h, alloc_h);
18276 case CLUTTER_CONTENT_GRAVITY_LEFT:
18277 box->x2 = box->x1 + MIN (content_w, alloc_w);
18278 if (alloc_h > content_h)
18280 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18281 box->y2 = box->y1 + content_h;
18285 case CLUTTER_CONTENT_GRAVITY_CENTER:
18286 if (alloc_w > content_w)
18288 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18289 box->x2 = box->x1 + content_w;
18291 if (alloc_h > content_h)
18293 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18294 box->y2 = box->y1 + content_h;
18298 case CLUTTER_CONTENT_GRAVITY_RIGHT:
18299 if (alloc_w > content_w)
18301 box->x1 += (alloc_w - content_w);
18302 box->x2 = box->x1 + content_w;
18304 if (alloc_h > content_h)
18306 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18307 box->y2 = box->y1 + content_h;
18311 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18312 box->x2 = box->x1 + MIN (content_w, alloc_w);
18313 if (alloc_h > content_h)
18315 box->y1 += (alloc_h - content_h);
18316 box->y2 = box->y1 + content_h;
18320 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18321 if (alloc_w > content_w)
18323 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18324 box->x2 = box->x1 + content_w;
18326 if (alloc_h > content_h)
18328 box->y1 += (alloc_h - content_h);
18329 box->y2 = box->y1 + content_h;
18333 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18334 if (alloc_w > content_w)
18336 box->x1 += (alloc_w - content_w);
18337 box->x2 = box->x1 + content_w;
18339 if (alloc_h > content_h)
18341 box->y1 += (alloc_h - content_h);
18342 box->y2 = box->y1 + content_h;
18346 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18347 g_assert_not_reached ();
18350 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18352 double r_c = content_w / content_h;
18356 if ((alloc_w / r_c) > alloc_h)
18361 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18362 box->y2 = box->y1 + (alloc_w / r_c);
18369 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18370 box->x2 = box->x1 + (alloc_h * r_c);
18375 if ((alloc_w / r_c) > alloc_h)
18380 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18381 box->x2 = box->x1 + (alloc_h * r_c);
18388 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18389 box->y2 = box->y1 + (alloc_w / r_c);
18393 CLUTTER_NOTE (LAYOUT,
18394 "r_c: %.3f, r_a: %.3f\t"
18395 "a: [%.2fx%.2f], c: [%.2fx%.2f]\t"
18396 "b: [%.2f, %.2f, %.2f, %.2f]",
18397 r_c, alloc_w / alloc_h,
18399 content_w, content_h,
18400 box->x1, box->y1, box->x2, box->y2);
18407 * clutter_actor_set_content_scaling_filters:
18408 * @self: a #ClutterActor
18409 * @min_filter: the minification filter for the content
18410 * @mag_filter: the magnification filter for the content
18412 * Sets the minification and magnification filter to be applied when
18413 * scaling the #ClutterActor:content of a #ClutterActor.
18415 * The #ClutterActor:minification-filter will be used when reducing
18416 * the size of the content; the #ClutterActor:magnification-filter
18417 * will be used when increasing the size of the content.
18422 clutter_actor_set_content_scaling_filters (ClutterActor *self,
18423 ClutterScalingFilter min_filter,
18424 ClutterScalingFilter mag_filter)
18426 ClutterActorPrivate *priv;
18430 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18433 obj = G_OBJECT (self);
18435 g_object_freeze_notify (obj);
18439 if (priv->min_filter != min_filter)
18441 priv->min_filter = min_filter;
18444 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18447 if (priv->mag_filter != mag_filter)
18449 priv->mag_filter = mag_filter;
18452 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18456 clutter_actor_queue_redraw (self);
18458 g_object_thaw_notify (obj);
18462 * clutter_actor_get_content_scaling_filters:
18463 * @self: a #ClutterActor
18464 * @min_filter: (out) (allow-none): return location for the minification
18466 * @mag_filter: (out) (allow-none): return location for the magnification
18469 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18474 clutter_actor_get_content_scaling_filters (ClutterActor *self,
18475 ClutterScalingFilter *min_filter,
18476 ClutterScalingFilter *mag_filter)
18478 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18480 if (min_filter != NULL)
18481 *min_filter = self->priv->min_filter;
18483 if (mag_filter != NULL)
18484 *mag_filter = self->priv->mag_filter;
18488 * clutter_actor_queue_compute_expand:
18489 * @self: a #ClutterActor
18491 * Invalidates the needs_x_expand and needs_y_expand flags on @self
18492 * and its parents up to the top-level actor.
18494 * This function also queues a relayout if anything changed.
18497 clutter_actor_queue_compute_expand (ClutterActor *self)
18499 ClutterActor *parent;
18502 if (self->priv->needs_compute_expand)
18507 while (parent != NULL)
18509 if (!parent->priv->needs_compute_expand)
18511 parent->priv->needs_compute_expand = TRUE;
18515 parent = parent->priv->parent;
18519 clutter_actor_queue_relayout (self);
18523 * clutter_actor_set_x_expand:
18524 * @self: a #ClutterActor
18525 * @expand: whether the actor should expand horizontally
18527 * Sets whether a #ClutterActor should expand horizontally; this means
18528 * that layout manager should allocate extra space for the actor, if
18531 * Setting an actor to expand will also make all its parent expand, so
18532 * that it's possible to build an actor tree and only set this flag on
18533 * its leaves and not on every single actor.
18538 clutter_actor_set_x_expand (ClutterActor *self,
18541 ClutterLayoutInfo *info;
18543 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18547 info = _clutter_actor_get_layout_info (self);
18548 if (info->x_expand != expand)
18550 info->x_expand = expand;
18552 self->priv->x_expand_set = TRUE;
18554 clutter_actor_queue_compute_expand (self);
18556 g_object_notify_by_pspec (G_OBJECT (self),
18557 obj_props[PROP_X_EXPAND]);
18562 * clutter_actor_get_x_expand:
18563 * @self: a #ClutterActor
18565 * Retrieves the value set with clutter_actor_set_x_expand().
18567 * See also: clutter_actor_needs_expand()
18569 * Return value: %TRUE if the actor has been set to expand
18574 clutter_actor_get_x_expand (ClutterActor *self)
18576 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18578 return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18582 * clutter_actor_set_y_expand:
18583 * @self: a #ClutterActor
18584 * @expand: whether the actor should expand vertically
18586 * Sets whether a #ClutterActor should expand horizontally; this means
18587 * that layout manager should allocate extra space for the actor, if
18590 * Setting an actor to expand will also make all its parent expand, so
18591 * that it's possible to build an actor tree and only set this flag on
18592 * its leaves and not on every single actor.
18597 clutter_actor_set_y_expand (ClutterActor *self,
18600 ClutterLayoutInfo *info;
18602 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18606 info = _clutter_actor_get_layout_info (self);
18607 if (info->y_expand != expand)
18609 info->y_expand = expand;
18611 self->priv->y_expand_set = TRUE;
18613 clutter_actor_queue_compute_expand (self);
18615 g_object_notify_by_pspec (G_OBJECT (self),
18616 obj_props[PROP_Y_EXPAND]);
18621 * clutter_actor_get_y_expand:
18622 * @self: a #ClutterActor
18624 * Retrieves the value set with clutter_actor_set_y_expand().
18626 * See also: clutter_actor_needs_expand()
18628 * Return value: %TRUE if the actor has been set to expand
18633 clutter_actor_get_y_expand (ClutterActor *self)
18635 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18637 return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18641 clutter_actor_compute_expand_recursive (ClutterActor *self,
18642 gboolean *x_expand_p,
18643 gboolean *y_expand_p)
18645 ClutterActorIter iter;
18646 ClutterActor *child;
18647 gboolean x_expand, y_expand;
18649 x_expand = y_expand = FALSE;
18651 /* note that we don't recurse into children if we're already set to expand;
18652 * this avoids traversing the whole actor tree, even if it may lead to some
18653 * child left with the needs_compute_expand flag set.
18655 clutter_actor_iter_init (&iter, self);
18656 while (clutter_actor_iter_next (&iter, &child))
18658 x_expand = x_expand ||
18659 clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL);
18661 y_expand = y_expand ||
18662 clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL);
18665 *x_expand_p = x_expand;
18666 *y_expand_p = y_expand;
18670 clutter_actor_compute_expand (ClutterActor *self)
18672 if (self->priv->needs_compute_expand)
18674 const ClutterLayoutInfo *info;
18675 gboolean x_expand, y_expand;
18677 info = _clutter_actor_get_layout_info_or_defaults (self);
18679 if (self->priv->x_expand_set)
18680 x_expand = info->x_expand;
18684 if (self->priv->y_expand_set)
18685 y_expand = info->y_expand;
18689 /* we don't need to recurse down to the children if the
18690 * actor has been forcibly set to expand
18692 if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18694 if (self->priv->n_children != 0)
18696 gboolean *x_expand_p, *y_expand_p;
18697 gboolean ignored = FALSE;
18699 x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18700 y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18702 clutter_actor_compute_expand_recursive (self,
18708 self->priv->needs_compute_expand = FALSE;
18709 self->priv->needs_x_expand = (x_expand != FALSE);
18710 self->priv->needs_y_expand = (y_expand != FALSE);
18715 * clutter_actor_needs_expand:
18716 * @self: a #ClutterActor
18717 * @orientation: the direction of expansion
18719 * Checks whether an actor, or any of its children, is set to expand
18720 * horizontally or vertically.
18722 * This function should only be called by layout managers that can
18723 * assign extra space to their children.
18725 * If you want to know whether the actor was explicitly set to expand,
18726 * use clutter_actor_get_x_expand() or clutter_actor_get_y_expand().
18728 * Return value: %TRUE if the actor should expand
18733 clutter_actor_needs_expand (ClutterActor *self,
18734 ClutterOrientation orientation)
18736 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18738 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18741 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18744 clutter_actor_compute_expand (self);
18746 switch (orientation)
18748 case CLUTTER_ORIENTATION_HORIZONTAL:
18749 return self->priv->needs_x_expand;
18751 case CLUTTER_ORIENTATION_VERTICAL:
18752 return self->priv->needs_y_expand;
18759 * clutter_actor_set_content_repeat:
18760 * @self: a #ClutterActor
18761 * @repeat: the repeat policy
18763 * Sets the policy for repeating the #ClutterActor:content of a
18764 * #ClutterActor. The behaviour is deferred to the #ClutterContent
18770 clutter_actor_set_content_repeat (ClutterActor *self,
18771 ClutterContentRepeat repeat)
18773 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18775 if (self->priv->content_repeat == repeat)
18778 self->priv->content_repeat = repeat;
18780 clutter_actor_queue_redraw (self);
18784 * clutter_actor_get_content_repeat:
18785 * @self: a #ClutterActor
18787 * Retrieves the repeat policy for a #ClutterActor set by
18788 * clutter_actor_set_content_repeat().
18790 * Return value: the content repeat policy
18794 ClutterContentRepeat
18795 clutter_actor_get_content_repeat (ClutterActor *self)
18797 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_REPEAT_NONE);
18799 return self->priv->content_repeat;