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-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44 * <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45 * <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46 * <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
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-effect-private.h"
597 #include "clutter-enum-types.h"
598 #include "clutter-fixed-layout.h"
599 #include "clutter-flatten-effect.h"
600 #include "clutter-interval.h"
601 #include "clutter-main.h"
602 #include "clutter-marshal.h"
603 #include "clutter-paint-nodes.h"
604 #include "clutter-paint-node-private.h"
605 #include "clutter-paint-volume-private.h"
606 #include "clutter-private.h"
607 #include "clutter-profile.h"
608 #include "clutter-property-transition.h"
609 #include "clutter-scriptable.h"
610 #include "clutter-script-private.h"
611 #include "clutter-stage-private.h"
612 #include "clutter-timeline.h"
613 #include "clutter-transition.h"
614 #include "clutter-units.h"
616 #include "deprecated/clutter-actor.h"
617 #include "deprecated/clutter-behaviour.h"
618 #include "deprecated/clutter-container.h"
620 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
621 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
623 /* Internal enum used to control mapped state update. This is a hint
624 * which indicates when to do something other than just enforce
628 MAP_STATE_CHECK, /* just enforce invariants. */
629 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
630 * used when about to unparent.
632 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
633 * used to set mapped on toplevels.
635 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
636 * used just before unmapping parent.
640 /* 3 entries should be a good compromise, few layout managers
641 * will ask for 3 different preferred size in each allocation cycle */
642 #define N_CACHED_SIZE_REQUESTS 3
644 struct _ClutterActorPrivate
647 ClutterRequestMode request_mode;
649 /* our cached size requests for different width / height */
650 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
651 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
653 /* An age of 0 means the entry is not set */
654 guint cached_height_age;
655 guint cached_width_age;
657 /* the bounding box of the actor, relative to the parent's
660 ClutterActorBox allocation;
661 ClutterAllocationFlags allocation_flags;
663 /* clip, in actor coordinates */
664 cairo_rectangle_t clip;
666 /* the cached transformation matrix; see apply_transform() */
667 CoglMatrix transform;
670 gint opacity_override;
672 ClutterOffscreenRedirect offscreen_redirect;
674 /* This is an internal effect used to implement the
675 offscreen-redirect property */
676 ClutterEffect *flatten_effect;
679 ClutterActor *parent;
680 ClutterActor *prev_sibling;
681 ClutterActor *next_sibling;
682 ClutterActor *first_child;
683 ClutterActor *last_child;
687 /* tracks whenever the children of an actor are changed; the
688 * age is incremented by 1 whenever an actor is added or
689 * removed. the age is not incremented when the first or the
690 * last child pointers are changed, or when grandchildren of
691 * an actor are changed.
695 gchar *name; /* a non-unique name, used for debugging */
696 guint32 id; /* unique id, used for backward compatibility */
698 gint32 pick_id; /* per-stage unique id, used for picking */
700 /* a back-pointer to the Pango context that we can use
701 * to create pre-configured PangoLayout
703 PangoContext *pango_context;
705 /* the text direction configured for this child - either by
706 * application code, or by the actor's parent
708 ClutterTextDirection text_direction;
710 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
714 ClutterMetaGroup *actions;
715 ClutterMetaGroup *constraints;
716 ClutterMetaGroup *effects;
718 /* delegate object used to allocate the children of this actor */
719 ClutterLayoutManager *layout_manager;
721 /* delegate object used to paint the contents of this actor */
722 ClutterContent *content;
724 ClutterActorBox content_box;
725 ClutterContentGravity content_gravity;
726 ClutterScalingFilter min_filter;
727 ClutterScalingFilter mag_filter;
729 /* used when painting, to update the paint volume */
730 ClutterEffect *current_effect;
732 /* This is used to store an effect which needs to be redrawn. A
733 redraw can be queued to start from a particular effect. This is
734 used by parametrised effects that can cache an image of the
735 actor. If a parameter of the effect changes then it only needs to
736 redraw the cached image, not the actual actor. The pointer is
737 only valid if is_dirty == TRUE. If the pointer is NULL then the
738 whole actor is dirty. */
739 ClutterEffect *effect_to_redraw;
741 /* This is used when painting effects to implement the
742 clutter_actor_continue_paint() function. It points to the node in
743 the list of effects that is next in the chain */
744 const GList *next_effect_to_paint;
746 ClutterPaintVolume paint_volume;
748 /* NB: This volume isn't relative to this actor, it is in eye
749 * coordinates so that it can remain valid after the actor changes.
751 ClutterPaintVolume last_paint_volume;
753 ClutterStageQueueRedrawEntry *queue_redraw_entry;
755 ClutterColor bg_color;
759 /* fixed position and sizes */
760 guint position_set : 1;
761 guint min_width_set : 1;
762 guint min_height_set : 1;
763 guint natural_width_set : 1;
764 guint natural_height_set : 1;
765 /* cached request is invalid (implies allocation is too) */
766 guint needs_width_request : 1;
767 /* cached request is invalid (implies allocation is too) */
768 guint needs_height_request : 1;
769 /* cached allocation is invalid (request has changed, probably) */
770 guint needs_allocation : 1;
771 guint show_on_set_parent : 1;
773 guint clip_to_allocation : 1;
774 guint enable_model_view_transform : 1;
775 guint enable_paint_unmapped : 1;
776 guint has_pointer : 1;
777 guint propagated_one_redraw : 1;
778 guint paint_volume_valid : 1;
779 guint last_paint_volume_valid : 1;
780 guint in_clone_paint : 1;
781 guint transform_valid : 1;
782 /* This is TRUE if anything has queued a redraw since we were last
783 painted. In this case effect_to_redraw will point to an effect
784 the redraw was queued from or it will be NULL if the redraw was
785 queued without an effect. */
787 guint bg_color_set : 1;
788 guint content_box_valid : 1;
789 guint x_expand_set : 1;
790 guint y_expand_set : 1;
791 guint needs_compute_expand : 1;
792 guint needs_x_expand : 1;
793 guint needs_y_expand : 1;
802 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
803 * when set they force a size request, when gotten they
804 * get the allocation if the allocation is valid, and the
815 /* Then the rest of these size-related properties are the "actual"
816 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
821 PROP_FIXED_POSITION_SET,
830 PROP_NATURAL_WIDTH_SET,
833 PROP_NATURAL_HEIGHT_SET,
837 /* Allocation properties are read-only */
844 PROP_CLIP_TO_ALLOCATION,
848 PROP_OFFSCREEN_REDIRECT,
861 PROP_ROTATION_ANGLE_X,
862 PROP_ROTATION_ANGLE_Y,
863 PROP_ROTATION_ANGLE_Z,
864 PROP_ROTATION_CENTER_X,
865 PROP_ROTATION_CENTER_Y,
866 PROP_ROTATION_CENTER_Z,
867 /* This property only makes sense for the z rotation because the
868 others would depend on the actor having a size along the
870 PROP_ROTATION_CENTER_Z_GRAVITY,
876 PROP_SHOW_ON_SET_PARENT,
896 PROP_BACKGROUND_COLOR,
897 PROP_BACKGROUND_COLOR_SET,
903 PROP_CONTENT_GRAVITY,
905 PROP_MINIFICATION_FILTER,
906 PROP_MAGNIFICATION_FILTER,
911 static GParamSpec *obj_props[PROP_LAST];
930 BUTTON_RELEASE_EVENT,
938 TRANSITIONS_COMPLETED,
943 static guint actor_signals[LAST_SIGNAL] = { 0, };
945 static void clutter_container_iface_init (ClutterContainerIface *iface);
946 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
947 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
948 static void atk_implementor_iface_init (AtkImplementorIface *iface);
950 /* These setters are all static for now, maybe they should be in the
951 * public API, but they are perhaps obscure enough to leave only as
954 static void clutter_actor_set_min_width (ClutterActor *self,
956 static void clutter_actor_set_min_height (ClutterActor *self,
958 static void clutter_actor_set_natural_width (ClutterActor *self,
959 gfloat natural_width);
960 static void clutter_actor_set_natural_height (ClutterActor *self,
961 gfloat natural_height);
962 static void clutter_actor_set_min_width_set (ClutterActor *self,
963 gboolean use_min_width);
964 static void clutter_actor_set_min_height_set (ClutterActor *self,
965 gboolean use_min_height);
966 static void clutter_actor_set_natural_width_set (ClutterActor *self,
967 gboolean use_natural_width);
968 static void clutter_actor_set_natural_height_set (ClutterActor *self,
969 gboolean use_natural_height);
970 static void clutter_actor_update_map_state (ClutterActor *self,
971 MapStateChange change);
972 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
974 /* Helper routines for managing anchor coords */
975 static void clutter_anchor_coord_get_units (ClutterActor *self,
976 const AnchorCoord *coord,
980 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
985 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
986 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
987 ClutterGravity gravity);
989 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
991 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
993 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
994 ClutterActor *ancestor,
997 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
999 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
1001 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
1002 const ClutterColor *color);
1004 static void on_layout_manager_changed (ClutterLayoutManager *manager,
1005 ClutterActor *self);
1007 static inline void clutter_actor_queue_compute_expand (ClutterActor *self);
1009 /* Helper macro which translates by the anchor coord, applies the
1010 given transformation and then translates back */
1011 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
1012 gfloat _tx, _ty, _tz; \
1013 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
1014 cogl_matrix_translate ((m), _tx, _ty, _tz); \
1016 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
1018 static GQuark quark_shader_data = 0;
1019 static GQuark quark_actor_layout_info = 0;
1020 static GQuark quark_actor_transform_info = 0;
1021 static GQuark quark_actor_animation_info = 0;
1023 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1025 G_TYPE_INITIALLY_UNOWNED,
1026 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1027 clutter_container_iface_init)
1028 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1029 clutter_scriptable_iface_init)
1030 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1031 clutter_animatable_iface_init)
1032 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1033 atk_implementor_iface_init));
1036 * clutter_actor_get_debug_name:
1037 * @actor: a #ClutterActor
1039 * Retrieves a printable name of @actor for debugging messages
1041 * Return value: a string with a printable name
1044 _clutter_actor_get_debug_name (ClutterActor *actor)
1046 return actor->priv->name != NULL ? actor->priv->name
1047 : G_OBJECT_TYPE_NAME (actor);
1050 #ifdef CLUTTER_ENABLE_DEBUG
1051 /* XXX - this is for debugging only, remove once working (or leave
1052 * in only in some debug mode). Should leave it for a little while
1053 * until we're confident in the new map/realize/visible handling.
1056 clutter_actor_verify_map_state (ClutterActor *self)
1058 ClutterActorPrivate *priv = self->priv;
1060 if (CLUTTER_ACTOR_IS_REALIZED (self))
1062 /* all bets are off during reparent when we're potentially realized,
1063 * but should not be according to invariants
1065 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1067 if (priv->parent == NULL)
1069 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1073 g_warning ("Realized non-toplevel actor '%s' should "
1075 _clutter_actor_get_debug_name (self));
1077 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1079 g_warning ("Realized actor %s has an unrealized parent %s",
1080 _clutter_actor_get_debug_name (self),
1081 _clutter_actor_get_debug_name (priv->parent));
1086 if (CLUTTER_ACTOR_IS_MAPPED (self))
1088 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1089 g_warning ("Actor '%s' is mapped but not realized",
1090 _clutter_actor_get_debug_name (self));
1092 /* remaining bets are off during reparent when we're potentially
1093 * mapped, but should not be according to invariants
1095 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1097 if (priv->parent == NULL)
1099 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1101 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1102 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1104 g_warning ("Toplevel actor '%s' is mapped "
1106 _clutter_actor_get_debug_name (self));
1111 g_warning ("Mapped actor '%s' should have a parent",
1112 _clutter_actor_get_debug_name (self));
1117 ClutterActor *iter = self;
1119 /* check for the enable_paint_unmapped flag on the actor
1120 * and parents; if the flag is enabled at any point of this
1121 * branch of the scene graph then all the later checks
1124 while (iter != NULL)
1126 if (iter->priv->enable_paint_unmapped)
1129 iter = iter->priv->parent;
1132 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1134 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1136 _clutter_actor_get_debug_name (self),
1137 _clutter_actor_get_debug_name (priv->parent));
1140 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1142 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1144 _clutter_actor_get_debug_name (self),
1145 _clutter_actor_get_debug_name (priv->parent));
1148 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1150 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1151 g_warning ("Actor '%s' is mapped but its non-toplevel "
1152 "parent '%s' is not mapped",
1153 _clutter_actor_get_debug_name (self),
1154 _clutter_actor_get_debug_name (priv->parent));
1161 #endif /* CLUTTER_ENABLE_DEBUG */
1164 clutter_actor_set_mapped (ClutterActor *self,
1167 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1172 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1173 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1177 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1178 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1182 /* this function updates the mapped and realized states according to
1183 * invariants, in the appropriate order.
1186 clutter_actor_update_map_state (ClutterActor *self,
1187 MapStateChange change)
1189 gboolean was_mapped;
1191 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1193 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1195 /* the mapped flag on top-level actors must be set by the
1196 * per-backend implementation because it might be asynchronous.
1198 * That is, the MAPPED flag on toplevels currently tracks the X
1199 * server mapped-ness of the window, while the expected behavior
1200 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1201 * This creates some weird complexity by breaking the invariant
1202 * that if we're visible and all ancestors shown then we are
1203 * also mapped - instead, we are mapped if all ancestors
1204 * _possibly excepting_ the stage are mapped. The stage
1205 * will map/unmap for example when it is minimized or
1206 * moved to another workspace.
1208 * So, the only invariant on the stage is that if visible it
1209 * should be realized, and that it has to be visible to be
1212 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1213 clutter_actor_realize (self);
1217 case MAP_STATE_CHECK:
1220 case MAP_STATE_MAKE_MAPPED:
1221 g_assert (!was_mapped);
1222 clutter_actor_set_mapped (self, TRUE);
1225 case MAP_STATE_MAKE_UNMAPPED:
1226 g_assert (was_mapped);
1227 clutter_actor_set_mapped (self, FALSE);
1230 case MAP_STATE_MAKE_UNREALIZED:
1231 /* we only use MAKE_UNREALIZED in unparent,
1232 * and unparenting a stage isn't possible.
1233 * If someone wants to just unrealize a stage
1234 * then clutter_actor_unrealize() doesn't
1235 * go through this codepath.
1237 g_warning ("Trying to force unrealize stage is not allowed");
1241 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1242 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1243 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1245 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1246 "it is somehow still mapped",
1247 _clutter_actor_get_debug_name (self));
1252 ClutterActorPrivate *priv = self->priv;
1253 ClutterActor *parent = priv->parent;
1254 gboolean should_be_mapped;
1255 gboolean may_be_realized;
1256 gboolean must_be_realized;
1258 should_be_mapped = FALSE;
1259 may_be_realized = TRUE;
1260 must_be_realized = FALSE;
1262 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1264 may_be_realized = FALSE;
1268 /* Maintain invariant that if parent is mapped, and we are
1269 * visible, then we are mapped ... unless parent is a
1270 * stage, in which case we map regardless of parent's map
1271 * state but do require stage to be visible and realized.
1273 * If parent is realized, that does not force us to be
1274 * realized; but if parent is unrealized, that does force
1275 * us to be unrealized.
1277 * The reason we don't force children to realize with
1278 * parents is _clutter_actor_rerealize(); if we require that
1279 * a realized parent means children are realized, then to
1280 * unrealize an actor we would have to unrealize its
1281 * parents, which would end up meaning unrealizing and
1282 * hiding the entire stage. So we allow unrealizing a
1283 * child (as long as that child is not mapped) while that
1284 * child still has a realized parent.
1286 * Also, if we unrealize from leaf nodes to root, and
1287 * realize from root to leaf, the invariants are never
1288 * violated if we allow children to be unrealized
1289 * while parents are realized.
1291 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1292 * to force us to unmap, even though parent is still
1293 * mapped. This is because we're unmapping from leaf nodes
1296 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1297 change != MAP_STATE_MAKE_UNMAPPED)
1299 gboolean parent_is_visible_realized_toplevel;
1301 parent_is_visible_realized_toplevel =
1302 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1303 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1304 CLUTTER_ACTOR_IS_REALIZED (parent));
1306 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1307 parent_is_visible_realized_toplevel)
1309 must_be_realized = TRUE;
1310 should_be_mapped = TRUE;
1314 /* if the actor has been set to be painted even if unmapped
1315 * then we should map it and check for realization as well;
1316 * this is an override for the branch of the scene graph
1317 * which begins with this node
1319 if (priv->enable_paint_unmapped)
1321 if (priv->parent == NULL)
1322 g_warning ("Attempting to map an unparented actor '%s'",
1323 _clutter_actor_get_debug_name (self));
1325 should_be_mapped = TRUE;
1326 must_be_realized = TRUE;
1329 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1330 may_be_realized = FALSE;
1333 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1336 g_warning ("Attempting to map a child that does not "
1337 "meet the necessary invariants: the actor '%s' "
1339 _clutter_actor_get_debug_name (self));
1341 g_warning ("Attempting to map a child that does not "
1342 "meet the necessary invariants: the actor '%s' "
1343 "is parented to an unmapped actor '%s'",
1344 _clutter_actor_get_debug_name (self),
1345 _clutter_actor_get_debug_name (priv->parent));
1348 /* If in reparent, we temporarily suspend unmap and unrealize.
1350 * We want to go in the order "realize, map" and "unmap, unrealize"
1354 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1355 clutter_actor_set_mapped (self, FALSE);
1358 if (must_be_realized)
1359 clutter_actor_realize (self);
1361 /* if we must be realized then we may be, presumably */
1362 g_assert (!(must_be_realized && !may_be_realized));
1365 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1366 clutter_actor_unrealize_not_hiding (self);
1369 if (should_be_mapped)
1371 if (!must_be_realized)
1372 g_warning ("Somehow we think actor '%s' should be mapped but "
1373 "not realized, which isn't allowed",
1374 _clutter_actor_get_debug_name (self));
1376 /* realization is allowed to fail (though I don't know what
1377 * an app is supposed to do about that - shouldn't it just
1378 * be a g_error? anyway, we have to avoid mapping if this
1381 if (CLUTTER_ACTOR_IS_REALIZED (self))
1382 clutter_actor_set_mapped (self, TRUE);
1386 #ifdef CLUTTER_ENABLE_DEBUG
1387 /* check all invariants were kept */
1388 clutter_actor_verify_map_state (self);
1393 clutter_actor_real_map (ClutterActor *self)
1395 ClutterActorPrivate *priv = self->priv;
1396 ClutterActor *stage, *iter;
1398 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1400 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1401 _clutter_actor_get_debug_name (self));
1403 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1405 stage = _clutter_actor_get_stage_internal (self);
1406 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1408 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1410 _clutter_actor_get_debug_name (self));
1412 /* notify on parent mapped before potentially mapping
1413 * children, so apps see a top-down notification.
1415 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1417 for (iter = self->priv->first_child;
1419 iter = iter->priv->next_sibling)
1421 clutter_actor_map (iter);
1426 * clutter_actor_map:
1427 * @self: A #ClutterActor
1429 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1430 * and realizes its children if they are visible. Does nothing if the
1431 * actor is not visible.
1433 * Calling this function is strongly disencouraged: the default
1434 * implementation of #ClutterActorClass.map() will map all the children
1435 * of an actor when mapping its parent.
1437 * When overriding map, it is mandatory to chain up to the parent
1443 clutter_actor_map (ClutterActor *self)
1445 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1447 if (CLUTTER_ACTOR_IS_MAPPED (self))
1450 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1453 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1457 clutter_actor_real_unmap (ClutterActor *self)
1459 ClutterActorPrivate *priv = self->priv;
1462 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1464 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1465 _clutter_actor_get_debug_name (self));
1467 for (iter = self->priv->first_child;
1469 iter = iter->priv->next_sibling)
1471 clutter_actor_unmap (iter);
1474 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1476 /* clear the contents of the last paint volume, so that hiding + moving +
1477 * showing will not result in the wrong area being repainted
1479 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1480 priv->last_paint_volume_valid = TRUE;
1482 /* notify on parent mapped after potentially unmapping
1483 * children, so apps see a bottom-up notification.
1485 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1487 /* relinquish keyboard focus if we were unmapped while owning it */
1488 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1490 ClutterStage *stage;
1492 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1495 _clutter_stage_release_pick_id (stage, priv->pick_id);
1499 if (stage != NULL &&
1500 clutter_stage_get_key_focus (stage) == self)
1502 clutter_stage_set_key_focus (stage, NULL);
1508 * clutter_actor_unmap:
1509 * @self: A #ClutterActor
1511 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1512 * unmaps its children if they were mapped.
1514 * Calling this function is not encouraged: the default #ClutterActor
1515 * implementation of #ClutterActorClass.unmap() will also unmap any
1516 * eventual children by default when their parent is unmapped.
1518 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1519 * chain up to the parent implementation.
1521 * <note>It is important to note that the implementation of the
1522 * #ClutterActorClass.unmap() virtual function may be called after
1523 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1524 * implementation, but it is guaranteed to be called before the
1525 * #GObjectClass.finalize() implementation.</note>
1530 clutter_actor_unmap (ClutterActor *self)
1532 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1534 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1537 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1541 clutter_actor_real_show (ClutterActor *self)
1543 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1545 ClutterActorPrivate *priv = self->priv;
1547 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1549 /* we notify on the "visible" flag in the clutter_actor_show()
1550 * wrapper so the entire show signal emission completes first
1553 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1555 /* we queue a relayout unless the actor is inside a
1556 * container that explicitly told us not to
1558 if (priv->parent != NULL &&
1559 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1561 /* While an actor is hidden the parent may not have
1562 * allocated/requested so we need to start from scratch
1563 * and avoid the short-circuiting in
1564 * clutter_actor_queue_relayout().
1566 priv->needs_width_request = FALSE;
1567 priv->needs_height_request = FALSE;
1568 priv->needs_allocation = FALSE;
1569 clutter_actor_queue_relayout (self);
1575 set_show_on_set_parent (ClutterActor *self,
1578 ClutterActorPrivate *priv = self->priv;
1580 set_show = !!set_show;
1582 if (priv->show_on_set_parent == set_show)
1585 if (priv->parent == NULL)
1587 priv->show_on_set_parent = set_show;
1588 g_object_notify_by_pspec (G_OBJECT (self),
1589 obj_props[PROP_SHOW_ON_SET_PARENT]);
1594 * clutter_actor_show:
1595 * @self: A #ClutterActor
1597 * Flags an actor to be displayed. An actor that isn't shown will not
1598 * be rendered on the stage.
1600 * Actors are visible by default.
1602 * If this function is called on an actor without a parent, the
1603 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1607 clutter_actor_show (ClutterActor *self)
1609 ClutterActorPrivate *priv;
1611 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1613 /* simple optimization */
1614 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1616 /* we still need to set the :show-on-set-parent property, in
1617 * case show() is called on an unparented actor
1619 set_show_on_set_parent (self, TRUE);
1623 #ifdef CLUTTER_ENABLE_DEBUG
1624 clutter_actor_verify_map_state (self);
1629 g_object_freeze_notify (G_OBJECT (self));
1631 set_show_on_set_parent (self, TRUE);
1633 /* if we're showing a child that needs to expand, or may
1634 * expand, then we need to recompute the expand flags for
1635 * its parent as well
1637 if (priv->needs_compute_expand ||
1638 priv->needs_x_expand ||
1639 priv->needs_y_expand)
1641 clutter_actor_queue_compute_expand (self);
1644 g_signal_emit (self, actor_signals[SHOW], 0);
1645 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1647 if (priv->parent != NULL)
1648 clutter_actor_queue_redraw (priv->parent);
1650 g_object_thaw_notify (G_OBJECT (self));
1654 * clutter_actor_show_all:
1655 * @self: a #ClutterActor
1657 * Calls clutter_actor_show() on all children of an actor (if any).
1661 * Deprecated: 1.10: Actors are visible by default
1664 clutter_actor_show_all (ClutterActor *self)
1666 ClutterActorClass *klass;
1668 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1670 klass = CLUTTER_ACTOR_GET_CLASS (self);
1671 if (klass->show_all)
1672 klass->show_all (self);
1676 clutter_actor_real_hide (ClutterActor *self)
1678 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1680 ClutterActorPrivate *priv = self->priv;
1682 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1684 /* we notify on the "visible" flag in the clutter_actor_hide()
1685 * wrapper so the entire hide signal emission completes first
1688 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1690 /* we queue a relayout unless the actor is inside a
1691 * container that explicitly told us not to
1693 if (priv->parent != NULL &&
1694 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1695 clutter_actor_queue_relayout (priv->parent);
1700 * clutter_actor_hide:
1701 * @self: A #ClutterActor
1703 * Flags an actor to be hidden. A hidden actor will not be
1704 * rendered on the stage.
1706 * Actors are visible by default.
1708 * If this function is called on an actor without a parent, the
1709 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1713 clutter_actor_hide (ClutterActor *self)
1715 ClutterActorPrivate *priv;
1717 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1719 /* simple optimization */
1720 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1722 /* we still need to set the :show-on-set-parent property, in
1723 * case hide() is called on an unparented actor
1725 set_show_on_set_parent (self, FALSE);
1729 #ifdef CLUTTER_ENABLE_DEBUG
1730 clutter_actor_verify_map_state (self);
1735 g_object_freeze_notify (G_OBJECT (self));
1737 set_show_on_set_parent (self, FALSE);
1739 /* if we're hiding a child that needs to expand, or may
1740 * expand, then we need to recompute the expand flags for
1741 * its parent as well
1743 if (priv->needs_compute_expand ||
1744 priv->needs_x_expand ||
1745 priv->needs_y_expand)
1747 clutter_actor_queue_compute_expand (self);
1750 g_signal_emit (self, actor_signals[HIDE], 0);
1751 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1753 if (priv->parent != NULL)
1754 clutter_actor_queue_redraw (priv->parent);
1756 g_object_thaw_notify (G_OBJECT (self));
1760 * clutter_actor_hide_all:
1761 * @self: a #ClutterActor
1763 * Calls clutter_actor_hide() on all child actors (if any).
1767 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1768 * prevent its children from being painted as well.
1771 clutter_actor_hide_all (ClutterActor *self)
1773 ClutterActorClass *klass;
1775 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1777 klass = CLUTTER_ACTOR_GET_CLASS (self);
1778 if (klass->hide_all)
1779 klass->hide_all (self);
1783 * clutter_actor_realize:
1784 * @self: A #ClutterActor
1786 * Realization informs the actor that it is attached to a stage. It
1787 * can use this to allocate resources if it wanted to delay allocation
1788 * until it would be rendered. However it is perfectly acceptable for
1789 * an actor to create resources before being realized because Clutter
1790 * only ever has a single rendering context so that actor is free to
1791 * be moved from one stage to another.
1793 * This function does nothing if the actor is already realized.
1795 * Because a realized actor must have realized parent actors, calling
1796 * clutter_actor_realize() will also realize all parents of the actor.
1798 * This function does not realize child actors, except in the special
1799 * case that realizing the stage, when the stage is visible, will
1800 * suddenly map (and thus realize) the children of the stage.
1803 clutter_actor_realize (ClutterActor *self)
1805 ClutterActorPrivate *priv;
1807 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1811 #ifdef CLUTTER_ENABLE_DEBUG
1812 clutter_actor_verify_map_state (self);
1815 if (CLUTTER_ACTOR_IS_REALIZED (self))
1818 /* To be realized, our parent actors must be realized first.
1819 * This will only succeed if we're inside a toplevel.
1821 if (priv->parent != NULL)
1822 clutter_actor_realize (priv->parent);
1824 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1826 /* toplevels can be realized at any time */
1830 /* "Fail" the realization if parent is missing or unrealized;
1831 * this should really be a g_warning() not some kind of runtime
1832 * failure; how can an app possibly recover? Instead it's a bug
1833 * in the app and the app should get an explanatory warning so
1834 * someone can fix it. But for now it's too hard to fix this
1835 * because e.g. ClutterTexture needs reworking.
1837 if (priv->parent == NULL ||
1838 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1842 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1844 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1845 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1847 g_signal_emit (self, actor_signals[REALIZE], 0);
1849 /* Stage actor is allowed to unset the realized flag again in its
1850 * default signal handler, though that is a pathological situation.
1853 /* If realization "failed" we'll have to update child state. */
1854 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1858 clutter_actor_real_unrealize (ClutterActor *self)
1860 /* we must be unmapped (implying our children are also unmapped) */
1861 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1865 * clutter_actor_unrealize:
1866 * @self: A #ClutterActor
1868 * Unrealization informs the actor that it may be being destroyed or
1869 * moved to another stage. The actor may want to destroy any
1870 * underlying graphics resources at this point. However it is
1871 * perfectly acceptable for it to retain the resources until the actor
1872 * is destroyed because Clutter only ever uses a single rendering
1873 * context and all of the graphics resources are valid on any stage.
1875 * Because mapped actors must be realized, actors may not be
1876 * unrealized if they are mapped. This function hides the actor to be
1877 * sure it isn't mapped, an application-visible side effect that you
1878 * may not be expecting.
1880 * This function should not be called by application code.
1883 clutter_actor_unrealize (ClutterActor *self)
1885 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1886 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1888 /* This function should not really be in the public API, because
1889 * there isn't a good reason to call it. ClutterActor will already
1890 * unrealize things for you when it's important to do so.
1892 * If you were using clutter_actor_unrealize() in a dispose
1893 * implementation, then don't, just chain up to ClutterActor's
1896 * If you were using clutter_actor_unrealize() to implement
1897 * unrealizing children of your container, then don't, ClutterActor
1898 * will already take care of that.
1900 * If you were using clutter_actor_unrealize() to re-realize to
1901 * create your resources in a different way, then use
1902 * _clutter_actor_rerealize() (inside Clutter) or just call your
1903 * code that recreates your resources directly (outside Clutter).
1906 #ifdef CLUTTER_ENABLE_DEBUG
1907 clutter_actor_verify_map_state (self);
1910 clutter_actor_hide (self);
1912 clutter_actor_unrealize_not_hiding (self);
1915 static ClutterActorTraverseVisitFlags
1916 unrealize_actor_before_children_cb (ClutterActor *self,
1920 /* If an actor is already unrealized we know its children have also
1921 * already been unrealized... */
1922 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1923 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1925 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1927 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1930 static ClutterActorTraverseVisitFlags
1931 unrealize_actor_after_children_cb (ClutterActor *self,
1935 /* We want to unset the realized flag only _after_
1936 * child actors are unrealized, to maintain invariants.
1938 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1939 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1940 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1944 * clutter_actor_unrealize_not_hiding:
1945 * @self: A #ClutterActor
1947 * Unrealization informs the actor that it may be being destroyed or
1948 * moved to another stage. The actor may want to destroy any
1949 * underlying graphics resources at this point. However it is
1950 * perfectly acceptable for it to retain the resources until the actor
1951 * is destroyed because Clutter only ever uses a single rendering
1952 * context and all of the graphics resources are valid on any stage.
1954 * Because mapped actors must be realized, actors may not be
1955 * unrealized if they are mapped. You must hide the actor or one of
1956 * its parents before attempting to unrealize.
1958 * This function is separate from clutter_actor_unrealize() because it
1959 * does not automatically hide the actor.
1960 * Actors need not be hidden to be unrealized, they just need to
1961 * be unmapped. In fact we don't want to mess up the application's
1962 * setting of the "visible" flag, so hiding is very undesirable.
1964 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1965 * backward compatibility.
1968 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1970 _clutter_actor_traverse (self,
1971 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1972 unrealize_actor_before_children_cb,
1973 unrealize_actor_after_children_cb,
1978 * _clutter_actor_rerealize:
1979 * @self: A #ClutterActor
1980 * @callback: Function to call while unrealized
1981 * @data: data for callback
1983 * If an actor is already unrealized, this just calls the callback.
1985 * If it is realized, it unrealizes temporarily, calls the callback,
1986 * and then re-realizes the actor.
1988 * As a side effect, leaves all children of the actor unrealized if
1989 * the actor was realized but not showing. This is because when we
1990 * unrealize the actor temporarily we must unrealize its children
1991 * (e.g. children of a stage can't be realized if stage window is
1992 * gone). And we aren't clever enough to save the realization state of
1993 * all children. In most cases this should not matter, because
1994 * the children will automatically realize when they next become mapped.
1997 _clutter_actor_rerealize (ClutterActor *self,
1998 ClutterCallback callback,
2001 gboolean was_mapped;
2002 gboolean was_showing;
2003 gboolean was_realized;
2005 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2007 #ifdef CLUTTER_ENABLE_DEBUG
2008 clutter_actor_verify_map_state (self);
2011 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
2012 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
2013 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
2015 /* Must be unmapped to unrealize. Note we only have to hide this
2016 * actor if it was mapped (if all parents were showing). If actor
2017 * is merely visible (but not mapped), then that's fine, we can
2021 clutter_actor_hide (self);
2023 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
2025 /* unrealize self and all children */
2026 clutter_actor_unrealize_not_hiding (self);
2028 if (callback != NULL)
2030 (* callback) (self, data);
2034 clutter_actor_show (self); /* will realize only if mapping implies it */
2035 else if (was_realized)
2036 clutter_actor_realize (self); /* realize self and all parents */
2040 clutter_actor_real_pick (ClutterActor *self,
2041 const ClutterColor *color)
2043 /* the default implementation is just to paint a rectangle
2044 * with the same size of the actor using the passed color
2046 if (clutter_actor_should_pick_paint (self))
2048 ClutterActorBox box = { 0, };
2049 float width, height;
2051 clutter_actor_get_allocation_box (self, &box);
2053 width = box.x2 - box.x1;
2054 height = box.y2 - box.y1;
2056 cogl_set_source_color4ub (color->red,
2061 cogl_rectangle (0, 0, width, height);
2064 /* XXX - this thoroughly sucks, but we need to maintain compatibility
2065 * with existing container classes that override the pick() virtual
2066 * and chain up to the default implementation - otherwise we'll end up
2067 * painting our children twice.
2069 * this has to go away for 2.0; hopefully along the pick() itself.
2071 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2075 for (iter = self->priv->first_child;
2077 iter = iter->priv->next_sibling)
2078 clutter_actor_paint (iter);
2083 * clutter_actor_should_pick_paint:
2084 * @self: A #ClutterActor
2086 * Should be called inside the implementation of the
2087 * #ClutterActor::pick virtual function in order to check whether
2088 * the actor should paint itself in pick mode or not.
2090 * This function should never be called directly by applications.
2092 * Return value: %TRUE if the actor should paint its silhouette,
2096 clutter_actor_should_pick_paint (ClutterActor *self)
2098 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2100 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2101 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2102 CLUTTER_ACTOR_IS_REACTIVE (self)))
2109 clutter_actor_real_get_preferred_width (ClutterActor *self,
2111 gfloat *min_width_p,
2112 gfloat *natural_width_p)
2114 ClutterActorPrivate *priv = self->priv;
2116 if (priv->n_children != 0 &&
2117 priv->layout_manager != NULL)
2119 ClutterContainer *container = CLUTTER_CONTAINER (self);
2121 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2122 "for the preferred width",
2123 G_OBJECT_TYPE_NAME (priv->layout_manager),
2124 priv->layout_manager);
2126 clutter_layout_manager_get_preferred_width (priv->layout_manager,
2135 /* Default implementation is always 0x0, usually an actor
2136 * using this default is relying on someone to set the
2139 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2144 if (natural_width_p)
2145 *natural_width_p = 0;
2149 clutter_actor_real_get_preferred_height (ClutterActor *self,
2151 gfloat *min_height_p,
2152 gfloat *natural_height_p)
2154 ClutterActorPrivate *priv = self->priv;
2156 if (priv->n_children != 0 &&
2157 priv->layout_manager != NULL)
2159 ClutterContainer *container = CLUTTER_CONTAINER (self);
2161 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2162 "for the preferred height",
2163 G_OBJECT_TYPE_NAME (priv->layout_manager),
2164 priv->layout_manager);
2166 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2174 /* Default implementation is always 0x0, usually an actor
2175 * using this default is relying on someone to set the
2178 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2183 if (natural_height_p)
2184 *natural_height_p = 0;
2188 clutter_actor_store_old_geometry (ClutterActor *self,
2189 ClutterActorBox *box)
2191 *box = self->priv->allocation;
2195 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2196 const ClutterActorBox *old)
2198 ClutterActorPrivate *priv = self->priv;
2199 GObject *obj = G_OBJECT (self);
2201 g_object_freeze_notify (obj);
2203 /* to avoid excessive requisition or allocation cycles we
2204 * use the cached values.
2206 * - if we don't have an allocation we assume that we need
2208 * - if we don't have a width or a height request we notify
2210 * - if we have a valid allocation then we check the old
2211 * bounding box with the current allocation and we notify
2214 if (priv->needs_allocation)
2216 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2217 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2218 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2219 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2220 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2221 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2223 else if (priv->needs_width_request || priv->needs_height_request)
2225 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2226 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2227 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2232 gfloat width, height;
2234 x = priv->allocation.x1;
2235 y = priv->allocation.y1;
2236 width = priv->allocation.x2 - priv->allocation.x1;
2237 height = priv->allocation.y2 - priv->allocation.y1;
2241 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2242 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2247 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2248 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2251 if (width != (old->x2 - old->x1))
2253 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2254 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2257 if (height != (old->y2 - old->y1))
2259 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2260 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2264 g_object_thaw_notify (obj);
2268 * clutter_actor_set_allocation_internal:
2269 * @self: a #ClutterActor
2270 * @box: a #ClutterActorBox
2271 * @flags: allocation flags
2273 * Stores the allocation of @self.
2275 * This function only performs basic storage and property notification.
2277 * This function should be called by clutter_actor_set_allocation()
2278 * and by the default implementation of #ClutterActorClass.allocate().
2280 * Return value: %TRUE if the allocation of the #ClutterActor has been
2281 * changed, and %FALSE otherwise
2283 static inline gboolean
2284 clutter_actor_set_allocation_internal (ClutterActor *self,
2285 const ClutterActorBox *box,
2286 ClutterAllocationFlags flags)
2288 ClutterActorPrivate *priv = self->priv;
2290 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2292 ClutterActorBox old_alloc = { 0, };
2294 obj = G_OBJECT (self);
2296 g_object_freeze_notify (obj);
2298 clutter_actor_store_old_geometry (self, &old_alloc);
2300 x1_changed = priv->allocation.x1 != box->x1;
2301 y1_changed = priv->allocation.y1 != box->y1;
2302 x2_changed = priv->allocation.x2 != box->x2;
2303 y2_changed = priv->allocation.y2 != box->y2;
2305 priv->allocation = *box;
2306 priv->allocation_flags = flags;
2308 /* allocation is authoritative */
2309 priv->needs_width_request = FALSE;
2310 priv->needs_height_request = FALSE;
2311 priv->needs_allocation = FALSE;
2318 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2319 _clutter_actor_get_debug_name (self));
2321 priv->transform_valid = FALSE;
2323 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2325 /* if the allocation changes, so does the content box */
2326 if (priv->content != NULL)
2328 priv->content_box_valid = FALSE;
2329 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2337 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2339 g_object_thaw_notify (obj);
2344 static void clutter_actor_real_allocate (ClutterActor *self,
2345 const ClutterActorBox *box,
2346 ClutterAllocationFlags flags);
2349 clutter_actor_maybe_layout_children (ClutterActor *self,
2350 const ClutterActorBox *allocation,
2351 ClutterAllocationFlags flags)
2353 ClutterActorPrivate *priv = self->priv;
2355 /* this is going to be a bit hard to follow, so let's put an explanation
2358 * we want ClutterActor to have a default layout manager if the actor was
2359 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2361 * we also want any subclass of ClutterActor that does not override the
2362 * ::allocate() virtual function to delegate to a layout manager.
2364 * finally, we want to allow people subclassing ClutterActor and overriding
2365 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2367 * on the other hand, we want existing actor subclasses overriding the
2368 * ::allocate() virtual function and chaining up to the parent's
2369 * implementation to continue working without allocating their children
2370 * twice, or without entering an allocation loop.
2372 * for the first two points, we check if the class of the actor is
2373 * overridding the ::allocate() virtual function; if it isn't, then we
2374 * follow through with checking whether we have children and a layout
2375 * manager, and eventually calling clutter_layout_manager_allocate().
2377 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2378 * allocation flags that we got passed, and if it is present, we continue
2379 * with the check above.
2381 * if neither of these two checks yields a positive result, we just
2382 * assume that the ::allocate() virtual function that resulted in this
2383 * function being called will also allocate the children of the actor.
2386 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2389 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2395 if (priv->n_children != 0 &&
2396 priv->layout_manager != NULL)
2398 ClutterContainer *container = CLUTTER_CONTAINER (self);
2399 ClutterAllocationFlags children_flags;
2400 ClutterActorBox children_box;
2402 /* normalize the box passed to the layout manager */
2403 children_box.x1 = children_box.y1 = 0.f;
2404 children_box.x2 = (allocation->x2 - allocation->x1);
2405 children_box.y2 = (allocation->y2 - allocation->y1);
2407 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2408 * the actor's children, since it refers only to the current
2409 * actor's allocation.
2411 children_flags = flags;
2412 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2414 CLUTTER_NOTE (LAYOUT,
2415 "Allocating %d children of %s "
2416 "at { %.2f, %.2f - %.2f x %.2f } "
2419 _clutter_actor_get_debug_name (self),
2422 (allocation->x2 - allocation->x1),
2423 (allocation->y2 - allocation->y1),
2424 G_OBJECT_TYPE_NAME (priv->layout_manager));
2426 clutter_layout_manager_allocate (priv->layout_manager,
2434 clutter_actor_real_allocate (ClutterActor *self,
2435 const ClutterActorBox *box,
2436 ClutterAllocationFlags flags)
2438 ClutterActorPrivate *priv = self->priv;
2441 g_object_freeze_notify (G_OBJECT (self));
2443 changed = clutter_actor_set_allocation_internal (self, box, flags);
2445 /* we allocate our children before we notify changes in our geometry,
2446 * so that people connecting to properties will be able to get valid
2447 * data out of the sub-tree of the scene graph that has this actor at
2450 clutter_actor_maybe_layout_children (self, box, flags);
2454 ClutterActorBox signal_box = priv->allocation;
2455 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2457 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2462 g_object_thaw_notify (G_OBJECT (self));
2466 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2467 ClutterActor *origin)
2469 /* no point in queuing a redraw on a destroyed actor */
2470 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2473 /* NB: We can't bail out early here if the actor is hidden in case
2474 * the actor bas been cloned. In this case the clone will need to
2475 * receive the signal so it can queue its own redraw.
2478 /* calls klass->queue_redraw in default handler */
2479 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2483 clutter_actor_real_queue_redraw (ClutterActor *self,
2484 ClutterActor *origin)
2486 ClutterActor *parent;
2488 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2489 _clutter_actor_get_debug_name (self),
2490 origin != NULL ? _clutter_actor_get_debug_name (origin)
2493 /* no point in queuing a redraw on a destroyed actor */
2494 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2497 /* If the queue redraw is coming from a child then the actor has
2498 become dirty and any queued effect is no longer valid */
2501 self->priv->is_dirty = TRUE;
2502 self->priv->effect_to_redraw = NULL;
2505 /* If the actor isn't visible, we still had to emit the signal
2506 * to allow for a ClutterClone, but the appearance of the parent
2507 * won't change so we don't have to propagate up the hierarchy.
2509 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2512 /* Although we could determine here that a full stage redraw
2513 * has already been queued and immediately bail out, we actually
2514 * guarantee that we will propagate a queue-redraw signal to our
2515 * parent at least once so that it's possible to implement a
2516 * container that tracks which of its children have queued a
2519 if (self->priv->propagated_one_redraw)
2521 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2522 if (stage != NULL &&
2523 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2527 self->priv->propagated_one_redraw = TRUE;
2529 /* notify parents, if they are all visible eventually we'll
2530 * queue redraw on the stage, which queues the redraw idle.
2532 parent = clutter_actor_get_parent (self);
2535 /* this will go up recursively */
2536 _clutter_actor_signal_queue_redraw (parent, origin);
2541 clutter_actor_real_queue_relayout (ClutterActor *self)
2543 ClutterActorPrivate *priv = self->priv;
2545 /* no point in queueing a redraw on a destroyed actor */
2546 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2549 priv->needs_width_request = TRUE;
2550 priv->needs_height_request = TRUE;
2551 priv->needs_allocation = TRUE;
2553 /* reset the cached size requests */
2554 memset (priv->width_requests, 0,
2555 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2556 memset (priv->height_requests, 0,
2557 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2559 /* We need to go all the way up the hierarchy */
2560 if (priv->parent != NULL)
2561 _clutter_actor_queue_only_relayout (priv->parent);
2565 * clutter_actor_apply_relative_transform_to_point:
2566 * @self: A #ClutterActor
2567 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2568 * default #ClutterStage
2569 * @point: A point as #ClutterVertex
2570 * @vertex: (out caller-allocates): The translated #ClutterVertex
2572 * Transforms @point in coordinates relative to the actor into
2573 * ancestor-relative coordinates using the relevant transform
2574 * stack (i.e. scale, rotation, etc).
2576 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2577 * this case, the coordinates returned will be the coordinates on
2578 * the stage before the projection is applied. This is different from
2579 * the behaviour of clutter_actor_apply_transform_to_point().
2584 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2585 ClutterActor *ancestor,
2586 const ClutterVertex *point,
2587 ClutterVertex *vertex)
2592 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2593 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2594 g_return_if_fail (point != NULL);
2595 g_return_if_fail (vertex != NULL);
2600 if (ancestor == NULL)
2601 ancestor = _clutter_actor_get_stage_internal (self);
2603 if (ancestor == NULL)
2609 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2610 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2614 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2615 const ClutterVertex *vertices_in,
2616 ClutterVertex *vertices_out,
2619 ClutterActor *stage;
2620 CoglMatrix modelview;
2621 CoglMatrix projection;
2624 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2626 stage = _clutter_actor_get_stage_internal (self);
2628 /* We really can't do anything meaningful in this case so don't try
2629 * to do any transform */
2633 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2634 * that gets us to stage coordinates, we want to go all the way to eye
2636 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2638 /* Fetch the projection and viewport */
2639 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2640 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2646 _clutter_util_fully_transform_vertices (&modelview,
2657 * clutter_actor_apply_transform_to_point:
2658 * @self: A #ClutterActor
2659 * @point: A point as #ClutterVertex
2660 * @vertex: (out caller-allocates): The translated #ClutterVertex
2662 * Transforms @point in coordinates relative to the actor
2663 * into screen-relative coordinates with the current actor
2664 * transformation (i.e. scale, rotation, etc)
2669 clutter_actor_apply_transform_to_point (ClutterActor *self,
2670 const ClutterVertex *point,
2671 ClutterVertex *vertex)
2673 g_return_if_fail (point != NULL);
2674 g_return_if_fail (vertex != NULL);
2675 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2679 * _clutter_actor_get_relative_transformation_matrix:
2680 * @self: The actor whose coordinate space you want to transform from.
2681 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2682 * or %NULL if you want to transform all the way to eye coordinates.
2683 * @matrix: A #CoglMatrix to store the transformation
2685 * This gets a transformation @matrix that will transform coordinates from the
2686 * coordinate space of @self into the coordinate space of @ancestor.
2688 * For example if you need a matrix that can transform the local actor
2689 * coordinates of @self into stage coordinates you would pass the actor's stage
2690 * pointer as the @ancestor.
2692 * If you pass %NULL then the transformation will take you all the way through
2693 * to eye coordinates. This can be useful if you want to extract the entire
2694 * modelview transform that Clutter applies before applying the projection
2695 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2696 * using cogl_set_modelview_matrix() for example then you would want a matrix
2697 * that transforms into eye coordinates.
2699 * <note><para>This function explicitly initializes the given @matrix. If you just
2700 * want clutter to multiply a relative transformation with an existing matrix
2701 * you can use clutter_actor_apply_relative_transformation_matrix()
2702 * instead.</para></note>
2705 /* XXX: We should consider caching the stage relative modelview along with
2706 * the actor itself */
2708 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2709 ClutterActor *ancestor,
2712 cogl_matrix_init_identity (matrix);
2714 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2717 /* Project the given @box into stage window coordinates, writing the
2718 * transformed vertices to @verts[]. */
2720 _clutter_actor_transform_and_project_box (ClutterActor *self,
2721 const ClutterActorBox *box,
2722 ClutterVertex verts[])
2724 ClutterVertex box_vertices[4];
2726 box_vertices[0].x = box->x1;
2727 box_vertices[0].y = box->y1;
2728 box_vertices[0].z = 0;
2729 box_vertices[1].x = box->x2;
2730 box_vertices[1].y = box->y1;
2731 box_vertices[1].z = 0;
2732 box_vertices[2].x = box->x1;
2733 box_vertices[2].y = box->y2;
2734 box_vertices[2].z = 0;
2735 box_vertices[3].x = box->x2;
2736 box_vertices[3].y = box->y2;
2737 box_vertices[3].z = 0;
2740 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2744 * clutter_actor_get_allocation_vertices:
2745 * @self: A #ClutterActor
2746 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2747 * against, or %NULL to use the #ClutterStage
2748 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2749 * location for an array of 4 #ClutterVertex in which to store the result
2751 * Calculates the transformed coordinates of the four corners of the
2752 * actor in the plane of @ancestor. The returned vertices relate to
2753 * the #ClutterActorBox coordinates as follows:
2755 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2756 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2757 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2758 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2761 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2762 * this case, the coordinates returned will be the coordinates on
2763 * the stage before the projection is applied. This is different from
2764 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2769 clutter_actor_get_allocation_vertices (ClutterActor *self,
2770 ClutterActor *ancestor,
2771 ClutterVertex verts[])
2773 ClutterActorPrivate *priv;
2774 ClutterActorBox box;
2775 ClutterVertex vertices[4];
2776 CoglMatrix modelview;
2778 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2779 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2781 if (ancestor == NULL)
2782 ancestor = _clutter_actor_get_stage_internal (self);
2784 /* Fallback to a NOP transform if the actor isn't parented under a
2786 if (ancestor == NULL)
2791 /* if the actor needs to be allocated we force a relayout, so that
2792 * we will have valid values to use in the transformations */
2793 if (priv->needs_allocation)
2795 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2797 _clutter_stage_maybe_relayout (stage);
2800 box.x1 = box.y1 = 0;
2801 /* The result isn't really meaningful in this case but at
2802 * least try to do something *vaguely* reasonable... */
2803 clutter_actor_get_size (self, &box.x2, &box.y2);
2807 clutter_actor_get_allocation_box (self, &box);
2809 vertices[0].x = box.x1;
2810 vertices[0].y = box.y1;
2812 vertices[1].x = box.x2;
2813 vertices[1].y = box.y1;
2815 vertices[2].x = box.x1;
2816 vertices[2].y = box.y2;
2818 vertices[3].x = box.x2;
2819 vertices[3].y = box.y2;
2822 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2825 cogl_matrix_transform_points (&modelview,
2827 sizeof (ClutterVertex),
2829 sizeof (ClutterVertex),
2835 * clutter_actor_get_abs_allocation_vertices:
2836 * @self: A #ClutterActor
2837 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2838 * of 4 #ClutterVertex where to store the result.
2840 * Calculates the transformed screen coordinates of the four corners of
2841 * the actor; the returned vertices relate to the #ClutterActorBox
2842 * coordinates as follows:
2844 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2845 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2846 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2847 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2853 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2854 ClutterVertex verts[])
2856 ClutterActorPrivate *priv;
2857 ClutterActorBox actor_space_allocation;
2859 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2863 /* if the actor needs to be allocated we force a relayout, so that
2864 * the actor allocation box will be valid for
2865 * _clutter_actor_transform_and_project_box()
2867 if (priv->needs_allocation)
2869 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2870 /* There's nothing meaningful we can do now */
2874 _clutter_stage_maybe_relayout (stage);
2877 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2878 * own coordinate space... */
2879 actor_space_allocation.x1 = 0;
2880 actor_space_allocation.y1 = 0;
2881 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2882 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2883 _clutter_actor_transform_and_project_box (self,
2884 &actor_space_allocation,
2889 clutter_actor_real_apply_transform (ClutterActor *self,
2892 ClutterActorPrivate *priv = self->priv;
2894 if (!priv->transform_valid)
2896 CoglMatrix *transform = &priv->transform;
2897 const ClutterTransformInfo *info;
2899 info = _clutter_actor_get_transform_info_or_defaults (self);
2901 cogl_matrix_init_identity (transform);
2903 cogl_matrix_translate (transform,
2904 priv->allocation.x1,
2905 priv->allocation.y1,
2909 cogl_matrix_translate (transform, 0, 0, info->depth);
2912 * because the rotation involves translations, we must scale
2913 * before applying the rotations (if we apply the scale after
2914 * the rotations, the translations included in the rotation are
2915 * not scaled and so the entire object will move on the screen
2916 * as a result of rotating it).
2918 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2920 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2921 &info->scale_center,
2922 cogl_matrix_scale (transform,
2929 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2931 cogl_matrix_rotate (transform,
2936 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2938 cogl_matrix_rotate (transform,
2943 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2945 cogl_matrix_rotate (transform,
2949 if (!clutter_anchor_coord_is_zero (&info->anchor))
2953 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2954 cogl_matrix_translate (transform, -x, -y, -z);
2957 priv->transform_valid = TRUE;
2960 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2963 /* Applies the transforms associated with this actor to the given
2966 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2969 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2973 * clutter_actor_apply_relative_transformation_matrix:
2974 * @self: The actor whose coordinate space you want to transform from.
2975 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2976 * or %NULL if you want to transform all the way to eye coordinates.
2977 * @matrix: A #CoglMatrix to apply the transformation too.
2979 * This multiplies a transform with @matrix that will transform coordinates
2980 * from the coordinate space of @self into the coordinate space of @ancestor.
2982 * For example if you need a matrix that can transform the local actor
2983 * coordinates of @self into stage coordinates you would pass the actor's stage
2984 * pointer as the @ancestor.
2986 * If you pass %NULL then the transformation will take you all the way through
2987 * to eye coordinates. This can be useful if you want to extract the entire
2988 * modelview transform that Clutter applies before applying the projection
2989 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2990 * using cogl_set_modelview_matrix() for example then you would want a matrix
2991 * that transforms into eye coordinates.
2993 * <note>This function doesn't initialize the given @matrix, it simply
2994 * multiplies the requested transformation matrix with the existing contents of
2995 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2996 * before calling this function, or you can use
2997 * clutter_actor_get_relative_transformation_matrix() instead.</note>
3000 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
3001 ClutterActor *ancestor,
3004 ClutterActor *parent;
3006 /* Note we terminate before ever calling stage->apply_transform()
3007 * since that would conceptually be relative to the underlying
3008 * window OpenGL coordinates so we'd need a special @ancestor
3009 * value to represent the fake parent of the stage. */
3010 if (self == ancestor)
3013 parent = clutter_actor_get_parent (self);
3016 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
3019 _clutter_actor_apply_modelview_transform (self, matrix);
3023 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
3024 ClutterPaintVolume *pv,
3026 const CoglColor *color)
3028 static CoglPipeline *outline = NULL;
3029 CoglPrimitive *prim;
3030 ClutterVertex line_ends[12 * 2];
3033 clutter_backend_get_cogl_context (clutter_get_default_backend ());
3034 /* XXX: at some point we'll query this from the stage but we can't
3035 * do that until the osx backend uses Cogl natively. */
3036 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
3038 if (outline == NULL)
3039 outline = cogl_pipeline_new (ctx);
3041 _clutter_paint_volume_complete (pv);
3043 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3046 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3047 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3048 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3049 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3054 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3055 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3056 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3057 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3059 /* Lines connecting front face to back face */
3060 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3061 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3062 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3063 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3066 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3068 (CoglVertexP3 *)line_ends);
3070 cogl_pipeline_set_color (outline, color);
3071 cogl_framebuffer_draw_primitive (fb, outline, prim);
3072 cogl_object_unref (prim);
3076 PangoLayout *layout;
3077 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3078 pango_layout_set_text (layout, label, -1);
3079 cogl_pango_render_layout (layout,
3084 g_object_unref (layout);
3089 _clutter_actor_draw_paint_volume (ClutterActor *self)
3091 ClutterPaintVolume *pv;
3094 pv = _clutter_actor_get_paint_volume_mutable (self);
3097 gfloat width, height;
3098 ClutterPaintVolume fake_pv;
3100 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3101 _clutter_paint_volume_init_static (&fake_pv, stage);
3103 clutter_actor_get_size (self, &width, &height);
3104 clutter_paint_volume_set_width (&fake_pv, width);
3105 clutter_paint_volume_set_height (&fake_pv, height);
3107 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3108 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3109 _clutter_actor_get_debug_name (self),
3112 clutter_paint_volume_free (&fake_pv);
3116 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3117 _clutter_actor_draw_paint_volume_full (self, pv,
3118 _clutter_actor_get_debug_name (self),
3124 _clutter_actor_paint_cull_result (ClutterActor *self,
3126 ClutterCullResult result)
3128 ClutterPaintVolume *pv;
3133 if (result == CLUTTER_CULL_RESULT_IN)
3134 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3135 else if (result == CLUTTER_CULL_RESULT_OUT)
3136 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3138 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3141 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3143 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3144 _clutter_actor_draw_paint_volume_full (self, pv,
3145 _clutter_actor_get_debug_name (self),
3149 PangoLayout *layout;
3151 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3152 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3153 cogl_set_source_color (&color);
3155 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3156 pango_layout_set_text (layout, label, -1);
3157 cogl_pango_render_layout (layout,
3163 g_object_unref (layout);
3167 static int clone_paint_level = 0;
3170 _clutter_actor_push_clone_paint (void)
3172 clone_paint_level++;
3176 _clutter_actor_pop_clone_paint (void)
3178 clone_paint_level--;
3182 in_clone_paint (void)
3184 return clone_paint_level > 0;
3187 /* Returns TRUE if the actor can be ignored */
3188 /* FIXME: we should return a ClutterCullResult, and
3189 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3190 * means there's no point in trying to cull descendants of the current
3193 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3195 ClutterActorPrivate *priv = self->priv;
3196 ClutterActor *stage;
3197 const ClutterPlane *stage_clip;
3199 if (!priv->last_paint_volume_valid)
3201 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3202 "->last_paint_volume_valid == FALSE",
3203 _clutter_actor_get_debug_name (self));
3207 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3210 stage = _clutter_actor_get_stage_internal (self);
3211 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3212 if (G_UNLIKELY (!stage_clip))
3214 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3215 "No stage clip set",
3216 _clutter_actor_get_debug_name (self));
3220 if (cogl_get_draw_framebuffer () !=
3221 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3223 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3224 "Current framebuffer doesn't correspond to stage",
3225 _clutter_actor_get_debug_name (self));
3230 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3235 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3237 ClutterActorPrivate *priv = self->priv;
3238 const ClutterPaintVolume *pv;
3240 if (priv->last_paint_volume_valid)
3242 clutter_paint_volume_free (&priv->last_paint_volume);
3243 priv->last_paint_volume_valid = FALSE;
3246 pv = clutter_actor_get_paint_volume (self);
3249 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3250 "Actor failed to report a paint volume",
3251 _clutter_actor_get_debug_name (self));
3255 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3257 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3258 NULL); /* eye coordinates */
3260 priv->last_paint_volume_valid = TRUE;
3263 static inline gboolean
3264 actor_has_shader_data (ClutterActor *self)
3266 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3270 _clutter_actor_get_pick_id (ClutterActor *self)
3272 if (self->priv->pick_id < 0)
3275 return self->priv->pick_id;
3278 /* This is the same as clutter_actor_add_effect except that it doesn't
3279 queue a redraw and it doesn't notify on the effect property */
3281 _clutter_actor_add_effect_internal (ClutterActor *self,
3282 ClutterEffect *effect)
3284 ClutterActorPrivate *priv = self->priv;
3286 if (priv->effects == NULL)
3288 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3289 priv->effects->actor = self;
3292 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3295 /* This is the same as clutter_actor_remove_effect except that it doesn't
3296 queue a redraw and it doesn't notify on the effect property */
3298 _clutter_actor_remove_effect_internal (ClutterActor *self,
3299 ClutterEffect *effect)
3301 ClutterActorPrivate *priv = self->priv;
3303 if (priv->effects == NULL)
3306 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3308 if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3309 g_clear_object (&priv->effects);
3313 needs_flatten_effect (ClutterActor *self)
3315 ClutterActorPrivate *priv = self->priv;
3317 if (G_UNLIKELY (clutter_paint_debug_flags &
3318 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3321 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3323 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3325 if (clutter_actor_get_paint_opacity (self) < 255 &&
3326 clutter_actor_has_overlaps (self))
3334 add_or_remove_flatten_effect (ClutterActor *self)
3336 ClutterActorPrivate *priv = self->priv;
3338 /* Add or remove the flatten effect depending on the
3339 offscreen-redirect property. */
3340 if (needs_flatten_effect (self))
3342 if (priv->flatten_effect == NULL)
3344 ClutterActorMeta *actor_meta;
3347 priv->flatten_effect = _clutter_flatten_effect_new ();
3348 /* Keep a reference to the effect so that we can queue
3350 g_object_ref_sink (priv->flatten_effect);
3352 /* Set the priority of the effect to high so that it will
3353 always be applied to the actor first. It uses an internal
3354 priority so that it won't be visible to applications */
3355 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3356 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3357 _clutter_actor_meta_set_priority (actor_meta, priority);
3359 /* This will add the effect without queueing a redraw */
3360 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3365 if (priv->flatten_effect != NULL)
3367 /* Destroy the effect so that it will lose its fbo cache of
3369 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3370 g_clear_object (&priv->flatten_effect);
3376 clutter_actor_real_paint (ClutterActor *actor)
3378 ClutterActorPrivate *priv = actor->priv;
3381 for (iter = priv->first_child;
3383 iter = iter->priv->next_sibling)
3385 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3386 _clutter_actor_get_debug_name (iter),
3387 _clutter_actor_get_debug_name (actor),
3388 iter->priv->allocation.x1,
3389 iter->priv->allocation.y1,
3390 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3391 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3393 clutter_actor_paint (iter);
3398 clutter_actor_paint_node (ClutterActor *actor,
3399 ClutterPaintNode *root)
3401 ClutterActorPrivate *priv = actor->priv;
3406 if (priv->bg_color_set &&
3407 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3409 ClutterPaintNode *node;
3410 ClutterColor bg_color;
3411 ClutterActorBox box;
3415 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3416 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3418 bg_color = priv->bg_color;
3419 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3420 * priv->bg_color.alpha
3423 node = clutter_color_node_new (&bg_color);
3424 clutter_paint_node_set_name (node, "backgroundColor");
3425 clutter_paint_node_add_rectangle (node, &box);
3426 clutter_paint_node_add_child (root, node);
3427 clutter_paint_node_unref (node);
3430 if (priv->content != NULL)
3431 _clutter_content_paint_content (priv->content, actor, root);
3433 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3434 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3436 if (clutter_paint_node_get_n_children (root) == 0)
3439 #ifdef CLUTTER_ENABLE_DEBUG
3440 if (CLUTTER_HAS_DEBUG (PAINT))
3442 /* dump the tree only if we have one */
3443 _clutter_paint_node_dump_tree (root);
3445 #endif /* CLUTTER_ENABLE_DEBUG */
3447 _clutter_paint_node_paint (root);
3450 /* XXX: Uncomment this when we disable emitting the paint signal */
3451 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3458 * clutter_actor_paint:
3459 * @self: A #ClutterActor
3461 * Renders the actor to display.
3463 * This function should not be called directly by applications.
3464 * Call clutter_actor_queue_redraw() to queue paints, instead.
3466 * This function is context-aware, and will either cause a
3467 * regular paint or a pick paint.
3469 * This function will emit the #ClutterActor::paint signal or
3470 * the #ClutterActor::pick signal, depending on the context.
3472 * This function does not paint the actor if the actor is set to 0,
3473 * unless it is performing a pick paint.
3476 clutter_actor_paint (ClutterActor *self)
3478 ClutterActorPrivate *priv;
3479 ClutterPickMode pick_mode;
3480 gboolean clip_set = FALSE;
3481 gboolean shader_applied = FALSE;
3483 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3484 "Actor real-paint counter",
3485 "Increments each time any actor is painted",
3486 0 /* no application private data */);
3487 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3488 "Actor pick-paint counter",
3489 "Increments each time any actor is painted "
3491 0 /* no application private data */);
3493 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3495 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3500 pick_mode = _clutter_context_get_pick_mode ();
3502 if (pick_mode == CLUTTER_PICK_NONE)
3503 priv->propagated_one_redraw = FALSE;
3505 /* It's an important optimization that we consider painting of
3506 * actors with 0 opacity to be a NOP... */
3507 if (pick_mode == CLUTTER_PICK_NONE &&
3508 /* ignore top-levels, since they might be transparent */
3509 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3510 /* Use the override opacity if its been set */
3511 ((priv->opacity_override >= 0) ?
3512 priv->opacity_override : priv->opacity) == 0)
3515 /* if we aren't paintable (not in a toplevel with all
3516 * parents paintable) then do nothing.
3518 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3521 /* mark that we are in the paint process */
3522 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3526 if (priv->enable_model_view_transform)
3530 /* XXX: It could be better to cache the modelview with the actor
3531 * instead of progressively building up the transformations on
3532 * the matrix stack every time we paint. */
3533 cogl_get_modelview_matrix (&matrix);
3534 _clutter_actor_apply_modelview_transform (self, &matrix);
3536 #ifdef CLUTTER_ENABLE_DEBUG
3537 /* Catch when out-of-band transforms have been made by actors not as part
3538 * of an apply_transform vfunc... */
3539 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3541 CoglMatrix expected_matrix;
3543 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3546 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3548 GString *buf = g_string_sized_new (1024);
3549 ClutterActor *parent;
3552 while (parent != NULL)
3554 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3556 if (parent->priv->parent != NULL)
3557 g_string_append (buf, "->");
3559 parent = parent->priv->parent;
3562 g_warning ("Unexpected transform found when painting actor "
3563 "\"%s\". This will be caused by one of the actor's "
3564 "ancestors (%s) using the Cogl API directly to transform "
3565 "children instead of using ::apply_transform().",
3566 _clutter_actor_get_debug_name (self),
3569 g_string_free (buf, TRUE);
3572 #endif /* CLUTTER_ENABLE_DEBUG */
3574 cogl_set_modelview_matrix (&matrix);
3579 cogl_clip_push_rectangle (priv->clip.x,
3581 priv->clip.x + priv->clip.width,
3582 priv->clip.y + priv->clip.height);
3585 else if (priv->clip_to_allocation)
3587 gfloat width, height;
3589 width = priv->allocation.x2 - priv->allocation.x1;
3590 height = priv->allocation.y2 - priv->allocation.y1;
3592 cogl_clip_push_rectangle (0, 0, width, height);
3596 if (pick_mode == CLUTTER_PICK_NONE)
3598 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3600 /* We check whether we need to add the flatten effect before
3601 each paint so that we can avoid having a mechanism for
3602 applications to notify when the value of the
3603 has_overlaps virtual changes. */
3604 add_or_remove_flatten_effect (self);
3607 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3609 /* We save the current paint volume so that the next time the
3610 * actor queues a redraw we can constrain the redraw to just
3611 * cover the union of the new bounding box and the old.
3613 * We also fetch the current paint volume to perform culling so
3614 * we can avoid painting actors outside the current clip region.
3616 * If we are painting inside a clone, we should neither update
3617 * the paint volume or use it to cull painting, since the paint
3618 * box represents the location of the source actor on the
3621 * XXX: We are starting to do a lot of vertex transforms on
3622 * the CPU in a typical paint, so at some point we should
3623 * audit these and consider caching some things.
3625 * NB: We don't perform culling while picking at this point because
3626 * clutter-stage.c doesn't setup the clipping planes appropriately.
3628 * NB: We don't want to update the last-paint-volume during picking
3629 * because the last-paint-volume is used to determine the old screen
3630 * space location of an actor that has moved so we can know the
3631 * minimal region to redraw to clear an old view of the actor. If we
3632 * update this during picking then by the time we come around to
3633 * paint then the last-paint-volume would likely represent the new
3634 * actor position not the old.
3636 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3639 /* annoyingly gcc warns if uninitialized even though
3640 * the initialization is redundant :-( */
3641 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3643 if (G_LIKELY ((clutter_paint_debug_flags &
3644 (CLUTTER_DEBUG_DISABLE_CULLING |
3645 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3646 (CLUTTER_DEBUG_DISABLE_CULLING |
3647 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3648 _clutter_actor_update_last_paint_volume (self);
3650 success = cull_actor (self, &result);
3652 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3653 _clutter_actor_paint_cull_result (self, success, result);
3654 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3658 if (priv->effects == NULL)
3660 if (pick_mode == CLUTTER_PICK_NONE &&
3661 actor_has_shader_data (self))
3663 _clutter_actor_shader_pre_paint (self, FALSE);
3664 shader_applied = TRUE;
3667 priv->next_effect_to_paint = NULL;
3670 priv->next_effect_to_paint =
3671 _clutter_meta_group_peek_metas (priv->effects);
3673 clutter_actor_continue_paint (self);
3676 _clutter_actor_shader_post_paint (self);
3678 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3679 pick_mode == CLUTTER_PICK_NONE))
3680 _clutter_actor_draw_paint_volume (self);
3683 /* If we make it here then the actor has run through a complete
3684 paint run including all the effects so it's no longer dirty */
3685 if (pick_mode == CLUTTER_PICK_NONE)
3686 priv->is_dirty = FALSE;
3693 /* paint sequence complete */
3694 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3698 * clutter_actor_continue_paint:
3699 * @self: A #ClutterActor
3701 * Run the next stage of the paint sequence. This function should only
3702 * be called within the implementation of the ‘run’ virtual of a
3703 * #ClutterEffect. It will cause the run method of the next effect to
3704 * be applied, or it will paint the actual actor if the current effect
3705 * is the last effect in the chain.
3710 clutter_actor_continue_paint (ClutterActor *self)
3712 ClutterActorPrivate *priv;
3714 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3715 /* This should only be called from with in the ‘run’ implementation
3716 of a ClutterEffect */
3717 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3721 /* Skip any effects that are disabled */
3722 while (priv->next_effect_to_paint &&
3723 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3724 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3726 /* If this has come from the last effect then we'll just paint the
3728 if (priv->next_effect_to_paint == NULL)
3730 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3732 ClutterPaintNode *dummy;
3734 /* XXX - this will go away in 2.0, when we can get rid of this
3735 * stuff and switch to a pure retained render tree of PaintNodes
3736 * for the entire frame, starting from the Stage; the paint()
3737 * virtual function can then be called directly.
3739 dummy = _clutter_dummy_node_new (self);
3740 clutter_paint_node_set_name (dummy, "Root");
3742 /* XXX - for 1.12, we use the return value of paint_node() to
3743 * decide whether we should emit the ::paint signal.
3745 clutter_actor_paint_node (self, dummy);
3746 clutter_paint_node_unref (dummy);
3748 g_signal_emit (self, actor_signals[PAINT], 0);
3752 ClutterColor col = { 0, };
3754 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3756 /* Actor will then paint silhouette of itself in supplied
3757 * color. See clutter_stage_get_actor_at_pos() for where
3758 * picking is enabled.
3760 g_signal_emit (self, actor_signals[PICK], 0, &col);
3765 ClutterEffect *old_current_effect;
3766 ClutterEffectPaintFlags run_flags = 0;
3768 /* Cache the current effect so that we can put it back before
3770 old_current_effect = priv->current_effect;
3772 priv->current_effect = priv->next_effect_to_paint->data;
3773 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3775 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3779 /* If there's an effect queued with this redraw then all
3780 effects up to that one will be considered dirty. It
3781 is expected the queued effect will paint the cached
3782 image and not call clutter_actor_continue_paint again
3783 (although it should work ok if it does) */
3784 if (priv->effect_to_redraw == NULL ||
3785 priv->current_effect != priv->effect_to_redraw)
3786 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3789 _clutter_effect_paint (priv->current_effect, run_flags);
3793 /* We can't determine when an actor has been modified since
3794 its last pick so lets just assume it has always been
3796 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3798 _clutter_effect_pick (priv->current_effect, run_flags);
3801 priv->current_effect = old_current_effect;
3805 static ClutterActorTraverseVisitFlags
3806 invalidate_queue_redraw_entry (ClutterActor *self,
3810 ClutterActorPrivate *priv = self->priv;
3812 if (priv->queue_redraw_entry != NULL)
3814 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3815 priv->queue_redraw_entry = NULL;
3818 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3822 remove_child (ClutterActor *self,
3823 ClutterActor *child)
3825 ClutterActor *prev_sibling, *next_sibling;
3827 prev_sibling = child->priv->prev_sibling;
3828 next_sibling = child->priv->next_sibling;
3830 if (prev_sibling != NULL)
3831 prev_sibling->priv->next_sibling = next_sibling;
3833 if (next_sibling != NULL)
3834 next_sibling->priv->prev_sibling = prev_sibling;
3836 if (self->priv->first_child == child)
3837 self->priv->first_child = next_sibling;
3839 if (self->priv->last_child == child)
3840 self->priv->last_child = prev_sibling;
3842 child->priv->parent = NULL;
3843 child->priv->prev_sibling = NULL;
3844 child->priv->next_sibling = NULL;
3848 REMOVE_CHILD_DESTROY_META = 1 << 0,
3849 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3850 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3851 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3852 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3853 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3855 /* default flags for public API */
3856 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3857 REMOVE_CHILD_EMIT_PARENT_SET |
3858 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3859 REMOVE_CHILD_CHECK_STATE |
3860 REMOVE_CHILD_FLUSH_QUEUE |
3861 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3863 /* flags for legacy/deprecated API */
3864 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3865 REMOVE_CHILD_FLUSH_QUEUE |
3866 REMOVE_CHILD_EMIT_PARENT_SET |
3867 REMOVE_CHILD_NOTIFY_FIRST_LAST
3868 } ClutterActorRemoveChildFlags;
3871 * clutter_actor_remove_child_internal:
3872 * @self: a #ClutterActor
3873 * @child: the child of @self that has to be removed
3874 * @flags: control the removal operations
3876 * Removes @child from the list of children of @self.
3879 clutter_actor_remove_child_internal (ClutterActor *self,
3880 ClutterActor *child,
3881 ClutterActorRemoveChildFlags flags)
3883 ClutterActor *old_first, *old_last;
3884 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3885 gboolean flush_queue;
3886 gboolean notify_first_last;
3887 gboolean was_mapped;
3889 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3890 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3891 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3892 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3893 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3894 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3896 g_object_freeze_notify (G_OBJECT (self));
3899 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3903 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3905 /* we need to unrealize *before* we set parent_actor to NULL,
3906 * because in an unrealize method actors are dissociating from the
3907 * stage, which means they need to be able to
3908 * clutter_actor_get_stage().
3910 * yhis should unmap and unrealize, unless we're reparenting.
3912 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3919 /* We take this opportunity to invalidate any queue redraw entry
3920 * associated with the actor and descendants since we won't be able to
3921 * determine the appropriate stage after this.
3923 * we do this after we updated the mapped state because actors might
3924 * end up queueing redraws inside their mapped/unmapped virtual
3925 * functions, and if we invalidate the redraw entry we could end up
3926 * with an inconsistent state and weird memory corruption. see
3929 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3930 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3932 _clutter_actor_traverse (child,
3934 invalidate_queue_redraw_entry,
3939 old_first = self->priv->first_child;
3940 old_last = self->priv->last_child;
3942 remove_child (self, child);
3944 self->priv->n_children -= 1;
3946 self->priv->age += 1;
3948 /* if the child that got removed was visible and set to
3949 * expand then we want to reset the parent's state in
3950 * case the child was the only thing that was making it
3953 if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
3954 (child->priv->needs_compute_expand ||
3955 child->priv->needs_x_expand ||
3956 child->priv->needs_y_expand))
3958 clutter_actor_queue_compute_expand (self);
3961 /* clutter_actor_reparent() will emit ::parent-set for us */
3962 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3963 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3965 /* if the child was mapped then we need to relayout ourselves to account
3966 * for the removed child
3969 clutter_actor_queue_relayout (self);
3971 /* we need to emit the signal before dropping the reference */
3972 if (emit_actor_removed)
3973 g_signal_emit_by_name (self, "actor-removed", child);
3975 if (notify_first_last)
3977 if (old_first != self->priv->first_child)
3978 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3980 if (old_last != self->priv->last_child)
3981 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3984 g_object_thaw_notify (G_OBJECT (self));
3986 /* remove the reference we acquired in clutter_actor_add_child() */
3987 g_object_unref (child);
3990 static const ClutterTransformInfo default_transform_info = {
3991 0.0, { 0, }, /* rotation-x */
3992 0.0, { 0, }, /* rotation-y */
3993 0.0, { 0, }, /* rotation-z */
3995 1.0, 1.0, { 0, }, /* scale */
3997 { 0, }, /* anchor */
4003 * _clutter_actor_get_transform_info_or_defaults:
4004 * @self: a #ClutterActor
4006 * Retrieves the ClutterTransformInfo structure associated to an actor.
4008 * If the actor does not have a ClutterTransformInfo structure associated
4009 * to it, then the default structure will be returned.
4011 * This function should only be used for getters.
4013 * Return value: a const pointer to the ClutterTransformInfo structure
4015 const ClutterTransformInfo *
4016 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
4018 ClutterTransformInfo *info;
4020 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4024 return &default_transform_info;
4028 clutter_transform_info_free (gpointer data)
4031 g_slice_free (ClutterTransformInfo, data);
4035 * _clutter_actor_get_transform_info:
4036 * @self: a #ClutterActor
4038 * Retrieves a pointer to the ClutterTransformInfo structure.
4040 * If the actor does not have a ClutterTransformInfo associated to it, one
4041 * will be created and initialized to the default values.
4043 * This function should be used for setters.
4045 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
4048 * Return value: (transfer none): a pointer to the ClutterTransformInfo
4051 ClutterTransformInfo *
4052 _clutter_actor_get_transform_info (ClutterActor *self)
4054 ClutterTransformInfo *info;
4056 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4059 info = g_slice_new (ClutterTransformInfo);
4061 *info = default_transform_info;
4063 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4065 clutter_transform_info_free);
4072 * clutter_actor_set_rotation_angle_internal:
4073 * @self: a #ClutterActor
4074 * @axis: the axis of the angle to change
4075 * @angle: the angle of rotation
4077 * Sets the rotation angle on the given axis without affecting the
4078 * rotation center point.
4081 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
4082 ClutterRotateAxis axis,
4085 GObject *obj = G_OBJECT (self);
4086 ClutterTransformInfo *info;
4088 info = _clutter_actor_get_transform_info (self);
4090 g_object_freeze_notify (obj);
4094 case CLUTTER_X_AXIS:
4095 info->rx_angle = angle;
4096 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4099 case CLUTTER_Y_AXIS:
4100 info->ry_angle = angle;
4101 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4104 case CLUTTER_Z_AXIS:
4105 info->rz_angle = angle;
4106 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4110 self->priv->transform_valid = FALSE;
4112 g_object_thaw_notify (obj);
4114 clutter_actor_queue_redraw (self);
4118 clutter_actor_set_rotation_angle (ClutterActor *self,
4119 ClutterRotateAxis axis,
4122 const ClutterTransformInfo *info;
4123 const double *cur_angle_p = NULL;
4124 GParamSpec *pspec = NULL;
4126 info = _clutter_actor_get_transform_info_or_defaults (self);
4130 case CLUTTER_X_AXIS:
4131 cur_angle_p = &info->rx_angle;
4132 pspec = obj_props[PROP_ROTATION_ANGLE_X];
4135 case CLUTTER_Y_AXIS:
4136 cur_angle_p = &info->ry_angle;
4137 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4140 case CLUTTER_Z_AXIS:
4141 cur_angle_p = &info->rz_angle;
4142 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4146 g_assert (pspec != NULL);
4147 g_assert (cur_angle_p != NULL);
4149 if (_clutter_actor_get_transition (self, pspec) == NULL)
4150 _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4152 _clutter_actor_update_transition (self, pspec, angle);
4154 clutter_actor_queue_redraw (self);
4158 * clutter_actor_set_rotation_center_internal:
4159 * @self: a #ClutterActor
4160 * @axis: the axis of the center to change
4161 * @center: the coordinates of the rotation center
4163 * Sets the rotation center on the given axis without affecting the
4167 clutter_actor_set_rotation_center_internal (ClutterActor *self,
4168 ClutterRotateAxis axis,
4169 const ClutterVertex *center)
4171 GObject *obj = G_OBJECT (self);
4172 ClutterTransformInfo *info;
4173 ClutterVertex v = { 0, 0, 0 };
4175 info = _clutter_actor_get_transform_info (self);
4180 g_object_freeze_notify (obj);
4184 case CLUTTER_X_AXIS:
4185 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4186 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4189 case CLUTTER_Y_AXIS:
4190 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4191 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4194 case CLUTTER_Z_AXIS:
4195 /* if the previously set rotation center was fractional, then
4196 * setting explicit coordinates will have to notify the
4197 * :rotation-center-z-gravity property as well
4199 if (info->rz_center.is_fractional)
4200 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4202 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4203 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4207 self->priv->transform_valid = FALSE;
4209 g_object_thaw_notify (obj);
4211 clutter_actor_queue_redraw (self);
4215 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4219 GObject *obj = G_OBJECT (self);
4220 ClutterTransformInfo *info;
4222 info = _clutter_actor_get_transform_info (self);
4224 if (pspec == obj_props[PROP_SCALE_X])
4225 info->scale_x = factor;
4227 info->scale_y = factor;
4229 self->priv->transform_valid = FALSE;
4230 clutter_actor_queue_redraw (self);
4231 g_object_notify_by_pspec (obj, pspec);
4235 clutter_actor_set_scale_factor (ClutterActor *self,
4236 ClutterRotateAxis axis,
4239 const ClutterTransformInfo *info;
4240 const double *scale_p = NULL;
4241 GParamSpec *pspec = NULL;
4243 info = _clutter_actor_get_transform_info_or_defaults (self);
4247 case CLUTTER_X_AXIS:
4248 pspec = obj_props[PROP_SCALE_X];
4249 scale_p = &info->scale_x;
4252 case CLUTTER_Y_AXIS:
4253 pspec = obj_props[PROP_SCALE_Y];
4254 scale_p = &info->scale_y;
4257 case CLUTTER_Z_AXIS:
4261 g_assert (pspec != NULL);
4262 g_assert (scale_p != NULL);
4264 if (_clutter_actor_get_transition (self, pspec) == NULL)
4265 _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4267 _clutter_actor_update_transition (self, pspec, factor);
4269 clutter_actor_queue_redraw (self);
4273 clutter_actor_set_scale_center (ClutterActor *self,
4274 ClutterRotateAxis axis,
4277 GObject *obj = G_OBJECT (self);
4278 ClutterTransformInfo *info;
4279 gfloat center_x, center_y;
4281 info = _clutter_actor_get_transform_info (self);
4283 g_object_freeze_notify (obj);
4285 /* get the current scale center coordinates */
4286 clutter_anchor_coord_get_units (self, &info->scale_center,
4291 /* we need to notify this too, because setting explicit coordinates will
4292 * change the gravity as a side effect
4294 if (info->scale_center.is_fractional)
4295 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4299 case CLUTTER_X_AXIS:
4300 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4301 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4304 case CLUTTER_Y_AXIS:
4305 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4306 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4310 g_assert_not_reached ();
4313 self->priv->transform_valid = FALSE;
4315 clutter_actor_queue_redraw (self);
4317 g_object_thaw_notify (obj);
4321 clutter_actor_set_scale_gravity (ClutterActor *self,
4322 ClutterGravity gravity)
4324 ClutterTransformInfo *info;
4327 info = _clutter_actor_get_transform_info (self);
4328 obj = G_OBJECT (self);
4330 if (gravity == CLUTTER_GRAVITY_NONE)
4331 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4333 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4335 self->priv->transform_valid = FALSE;
4337 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4338 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4339 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4341 clutter_actor_queue_redraw (self);
4345 clutter_actor_set_anchor_coord (ClutterActor *self,
4346 ClutterRotateAxis axis,
4349 GObject *obj = G_OBJECT (self);
4350 ClutterTransformInfo *info;
4351 gfloat anchor_x, anchor_y;
4353 info = _clutter_actor_get_transform_info (self);
4355 g_object_freeze_notify (obj);
4357 clutter_anchor_coord_get_units (self, &info->anchor,
4362 if (info->anchor.is_fractional)
4363 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4367 case CLUTTER_X_AXIS:
4368 clutter_anchor_coord_set_units (&info->anchor,
4372 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4375 case CLUTTER_Y_AXIS:
4376 clutter_anchor_coord_set_units (&info->anchor,
4380 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4384 g_assert_not_reached ();
4387 self->priv->transform_valid = FALSE;
4389 clutter_actor_queue_redraw (self);
4391 g_object_thaw_notify (obj);
4395 clutter_actor_set_property (GObject *object,
4397 const GValue *value,
4400 ClutterActor *actor = CLUTTER_ACTOR (object);
4401 ClutterActorPrivate *priv = actor->priv;
4406 clutter_actor_set_x (actor, g_value_get_float (value));
4410 clutter_actor_set_y (actor, g_value_get_float (value));
4415 const ClutterPoint *pos = g_value_get_boxed (value);
4418 clutter_actor_set_position (actor, pos->x, pos->y);
4420 clutter_actor_set_fixed_position_set (actor, FALSE);
4425 clutter_actor_set_width (actor, g_value_get_float (value));
4429 clutter_actor_set_height (actor, g_value_get_float (value));
4434 const ClutterSize *size = g_value_get_boxed (value);
4437 clutter_actor_set_size (actor, size->width, size->height);
4439 clutter_actor_set_size (actor, -1, -1);
4444 clutter_actor_set_x (actor, g_value_get_float (value));
4448 clutter_actor_set_y (actor, g_value_get_float (value));
4451 case PROP_FIXED_POSITION_SET:
4452 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4455 case PROP_MIN_WIDTH:
4456 clutter_actor_set_min_width (actor, g_value_get_float (value));
4459 case PROP_MIN_HEIGHT:
4460 clutter_actor_set_min_height (actor, g_value_get_float (value));
4463 case PROP_NATURAL_WIDTH:
4464 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4467 case PROP_NATURAL_HEIGHT:
4468 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4471 case PROP_MIN_WIDTH_SET:
4472 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4475 case PROP_MIN_HEIGHT_SET:
4476 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4479 case PROP_NATURAL_WIDTH_SET:
4480 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4483 case PROP_NATURAL_HEIGHT_SET:
4484 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4487 case PROP_REQUEST_MODE:
4488 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4492 clutter_actor_set_depth (actor, g_value_get_float (value));
4496 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4499 case PROP_OFFSCREEN_REDIRECT:
4500 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4504 clutter_actor_set_name (actor, g_value_get_string (value));
4508 if (g_value_get_boolean (value) == TRUE)
4509 clutter_actor_show (actor);
4511 clutter_actor_hide (actor);
4515 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4516 g_value_get_double (value));
4520 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4521 g_value_get_double (value));
4524 case PROP_SCALE_CENTER_X:
4525 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4526 g_value_get_float (value));
4529 case PROP_SCALE_CENTER_Y:
4530 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4531 g_value_get_float (value));
4534 case PROP_SCALE_GRAVITY:
4535 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4540 const ClutterGeometry *geom = g_value_get_boxed (value);
4542 clutter_actor_set_clip (actor,
4544 geom->width, geom->height);
4548 case PROP_CLIP_TO_ALLOCATION:
4549 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4553 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4556 case PROP_ROTATION_ANGLE_X:
4557 clutter_actor_set_rotation_angle (actor,
4559 g_value_get_double (value));
4562 case PROP_ROTATION_ANGLE_Y:
4563 clutter_actor_set_rotation_angle (actor,
4565 g_value_get_double (value));
4568 case PROP_ROTATION_ANGLE_Z:
4569 clutter_actor_set_rotation_angle (actor,
4571 g_value_get_double (value));
4574 case PROP_ROTATION_CENTER_X:
4575 clutter_actor_set_rotation_center_internal (actor,
4577 g_value_get_boxed (value));
4580 case PROP_ROTATION_CENTER_Y:
4581 clutter_actor_set_rotation_center_internal (actor,
4583 g_value_get_boxed (value));
4586 case PROP_ROTATION_CENTER_Z:
4587 clutter_actor_set_rotation_center_internal (actor,
4589 g_value_get_boxed (value));
4592 case PROP_ROTATION_CENTER_Z_GRAVITY:
4594 const ClutterTransformInfo *info;
4596 info = _clutter_actor_get_transform_info_or_defaults (actor);
4597 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4598 g_value_get_enum (value));
4603 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4604 g_value_get_float (value));
4608 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4609 g_value_get_float (value));
4612 case PROP_ANCHOR_GRAVITY:
4613 clutter_actor_set_anchor_point_from_gravity (actor,
4614 g_value_get_enum (value));
4617 case PROP_SHOW_ON_SET_PARENT:
4618 priv->show_on_set_parent = g_value_get_boolean (value);
4621 case PROP_TEXT_DIRECTION:
4622 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4626 clutter_actor_add_action (actor, g_value_get_object (value));
4629 case PROP_CONSTRAINTS:
4630 clutter_actor_add_constraint (actor, g_value_get_object (value));
4634 clutter_actor_add_effect (actor, g_value_get_object (value));
4637 case PROP_LAYOUT_MANAGER:
4638 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4642 clutter_actor_set_x_expand (actor, g_value_get_boolean (value));
4646 clutter_actor_set_y_expand (actor, g_value_get_boolean (value));
4650 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4654 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4657 case PROP_MARGIN_TOP:
4658 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4661 case PROP_MARGIN_BOTTOM:
4662 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4665 case PROP_MARGIN_LEFT:
4666 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4669 case PROP_MARGIN_RIGHT:
4670 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4673 case PROP_BACKGROUND_COLOR:
4674 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4678 clutter_actor_set_content (actor, g_value_get_object (value));
4681 case PROP_CONTENT_GRAVITY:
4682 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4685 case PROP_MINIFICATION_FILTER:
4686 clutter_actor_set_content_scaling_filters (actor,
4687 g_value_get_enum (value),
4688 actor->priv->mag_filter);
4691 case PROP_MAGNIFICATION_FILTER:
4692 clutter_actor_set_content_scaling_filters (actor,
4693 actor->priv->min_filter,
4694 g_value_get_enum (value));
4698 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4704 clutter_actor_get_property (GObject *object,
4709 ClutterActor *actor = CLUTTER_ACTOR (object);
4710 ClutterActorPrivate *priv = actor->priv;
4715 g_value_set_float (value, clutter_actor_get_x (actor));
4719 g_value_set_float (value, clutter_actor_get_y (actor));
4724 ClutterPoint position;
4726 clutter_point_init (&position,
4727 clutter_actor_get_x (actor),
4728 clutter_actor_get_y (actor));
4729 g_value_set_boxed (value, &position);
4734 g_value_set_float (value, clutter_actor_get_width (actor));
4738 g_value_set_float (value, clutter_actor_get_height (actor));
4745 clutter_size_init (&size,
4746 clutter_actor_get_width (actor),
4747 clutter_actor_get_height (actor));
4748 g_value_set_boxed (value, &size);
4754 const ClutterLayoutInfo *info;
4756 info = _clutter_actor_get_layout_info_or_defaults (actor);
4757 g_value_set_float (value, info->fixed_pos.x);
4763 const ClutterLayoutInfo *info;
4765 info = _clutter_actor_get_layout_info_or_defaults (actor);
4766 g_value_set_float (value, info->fixed_pos.y);
4770 case PROP_FIXED_POSITION_SET:
4771 g_value_set_boolean (value, priv->position_set);
4774 case PROP_MIN_WIDTH:
4776 const ClutterLayoutInfo *info;
4778 info = _clutter_actor_get_layout_info_or_defaults (actor);
4779 g_value_set_float (value, info->minimum.width);
4783 case PROP_MIN_HEIGHT:
4785 const ClutterLayoutInfo *info;
4787 info = _clutter_actor_get_layout_info_or_defaults (actor);
4788 g_value_set_float (value, info->minimum.height);
4792 case PROP_NATURAL_WIDTH:
4794 const ClutterLayoutInfo *info;
4796 info = _clutter_actor_get_layout_info_or_defaults (actor);
4797 g_value_set_float (value, info->natural.width);
4801 case PROP_NATURAL_HEIGHT:
4803 const ClutterLayoutInfo *info;
4805 info = _clutter_actor_get_layout_info_or_defaults (actor);
4806 g_value_set_float (value, info->natural.height);
4810 case PROP_MIN_WIDTH_SET:
4811 g_value_set_boolean (value, priv->min_width_set);
4814 case PROP_MIN_HEIGHT_SET:
4815 g_value_set_boolean (value, priv->min_height_set);
4818 case PROP_NATURAL_WIDTH_SET:
4819 g_value_set_boolean (value, priv->natural_width_set);
4822 case PROP_NATURAL_HEIGHT_SET:
4823 g_value_set_boolean (value, priv->natural_height_set);
4826 case PROP_REQUEST_MODE:
4827 g_value_set_enum (value, priv->request_mode);
4830 case PROP_ALLOCATION:
4831 g_value_set_boxed (value, &priv->allocation);
4835 g_value_set_float (value, clutter_actor_get_depth (actor));
4839 g_value_set_uint (value, priv->opacity);
4842 case PROP_OFFSCREEN_REDIRECT:
4843 g_value_set_enum (value, priv->offscreen_redirect);
4847 g_value_set_string (value, priv->name);
4851 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4855 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4859 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4863 g_value_set_boolean (value, priv->has_clip);
4868 ClutterGeometry clip;
4870 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4871 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4872 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4873 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4875 g_value_set_boxed (value, &clip);
4879 case PROP_CLIP_TO_ALLOCATION:
4880 g_value_set_boolean (value, priv->clip_to_allocation);
4885 const ClutterTransformInfo *info;
4887 info = _clutter_actor_get_transform_info_or_defaults (actor);
4888 g_value_set_double (value, info->scale_x);
4894 const ClutterTransformInfo *info;
4896 info = _clutter_actor_get_transform_info_or_defaults (actor);
4897 g_value_set_double (value, info->scale_y);
4901 case PROP_SCALE_CENTER_X:
4905 clutter_actor_get_scale_center (actor, ¢er, NULL);
4907 g_value_set_float (value, center);
4911 case PROP_SCALE_CENTER_Y:
4915 clutter_actor_get_scale_center (actor, NULL, ¢er);
4917 g_value_set_float (value, center);
4921 case PROP_SCALE_GRAVITY:
4922 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4926 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4929 case PROP_ROTATION_ANGLE_X:
4931 const ClutterTransformInfo *info;
4933 info = _clutter_actor_get_transform_info_or_defaults (actor);
4934 g_value_set_double (value, info->rx_angle);
4938 case PROP_ROTATION_ANGLE_Y:
4940 const ClutterTransformInfo *info;
4942 info = _clutter_actor_get_transform_info_or_defaults (actor);
4943 g_value_set_double (value, info->ry_angle);
4947 case PROP_ROTATION_ANGLE_Z:
4949 const ClutterTransformInfo *info;
4951 info = _clutter_actor_get_transform_info_or_defaults (actor);
4952 g_value_set_double (value, info->rz_angle);
4956 case PROP_ROTATION_CENTER_X:
4958 ClutterVertex center;
4960 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4965 g_value_set_boxed (value, ¢er);
4969 case PROP_ROTATION_CENTER_Y:
4971 ClutterVertex center;
4973 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4978 g_value_set_boxed (value, ¢er);
4982 case PROP_ROTATION_CENTER_Z:
4984 ClutterVertex center;
4986 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4991 g_value_set_boxed (value, ¢er);
4995 case PROP_ROTATION_CENTER_Z_GRAVITY:
4996 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
5001 const ClutterTransformInfo *info;
5004 info = _clutter_actor_get_transform_info_or_defaults (actor);
5005 clutter_anchor_coord_get_units (actor, &info->anchor,
5009 g_value_set_float (value, anchor_x);
5015 const ClutterTransformInfo *info;
5018 info = _clutter_actor_get_transform_info_or_defaults (actor);
5019 clutter_anchor_coord_get_units (actor, &info->anchor,
5023 g_value_set_float (value, anchor_y);
5027 case PROP_ANCHOR_GRAVITY:
5028 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
5031 case PROP_SHOW_ON_SET_PARENT:
5032 g_value_set_boolean (value, priv->show_on_set_parent);
5035 case PROP_TEXT_DIRECTION:
5036 g_value_set_enum (value, priv->text_direction);
5039 case PROP_HAS_POINTER:
5040 g_value_set_boolean (value, priv->has_pointer);
5043 case PROP_LAYOUT_MANAGER:
5044 g_value_set_object (value, priv->layout_manager);
5049 const ClutterLayoutInfo *info;
5051 info = _clutter_actor_get_layout_info_or_defaults (actor);
5052 g_value_set_boolean (value, info->x_expand);
5058 const ClutterLayoutInfo *info;
5060 info = _clutter_actor_get_layout_info_or_defaults (actor);
5061 g_value_set_boolean (value, info->y_expand);
5067 const ClutterLayoutInfo *info;
5069 info = _clutter_actor_get_layout_info_or_defaults (actor);
5070 g_value_set_enum (value, info->x_align);
5076 const ClutterLayoutInfo *info;
5078 info = _clutter_actor_get_layout_info_or_defaults (actor);
5079 g_value_set_enum (value, info->y_align);
5083 case PROP_MARGIN_TOP:
5085 const ClutterLayoutInfo *info;
5087 info = _clutter_actor_get_layout_info_or_defaults (actor);
5088 g_value_set_float (value, info->margin.top);
5092 case PROP_MARGIN_BOTTOM:
5094 const ClutterLayoutInfo *info;
5096 info = _clutter_actor_get_layout_info_or_defaults (actor);
5097 g_value_set_float (value, info->margin.bottom);
5101 case PROP_MARGIN_LEFT:
5103 const ClutterLayoutInfo *info;
5105 info = _clutter_actor_get_layout_info_or_defaults (actor);
5106 g_value_set_float (value, info->margin.left);
5110 case PROP_MARGIN_RIGHT:
5112 const ClutterLayoutInfo *info;
5114 info = _clutter_actor_get_layout_info_or_defaults (actor);
5115 g_value_set_float (value, info->margin.right);
5119 case PROP_BACKGROUND_COLOR_SET:
5120 g_value_set_boolean (value, priv->bg_color_set);
5123 case PROP_BACKGROUND_COLOR:
5124 g_value_set_boxed (value, &priv->bg_color);
5127 case PROP_FIRST_CHILD:
5128 g_value_set_object (value, priv->first_child);
5131 case PROP_LAST_CHILD:
5132 g_value_set_object (value, priv->last_child);
5136 g_value_set_object (value, priv->content);
5139 case PROP_CONTENT_GRAVITY:
5140 g_value_set_enum (value, priv->content_gravity);
5143 case PROP_CONTENT_BOX:
5145 ClutterActorBox box = { 0, };
5147 clutter_actor_get_content_box (actor, &box);
5148 g_value_set_boxed (value, &box);
5152 case PROP_MINIFICATION_FILTER:
5153 g_value_set_enum (value, priv->min_filter);
5156 case PROP_MAGNIFICATION_FILTER:
5157 g_value_set_enum (value, priv->mag_filter);
5161 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5167 clutter_actor_dispose (GObject *object)
5169 ClutterActor *self = CLUTTER_ACTOR (object);
5170 ClutterActorPrivate *priv = self->priv;
5172 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5174 g_type_name (G_OBJECT_TYPE (self)),
5177 g_signal_emit (self, actor_signals[DESTROY], 0);
5179 /* avoid recursing when called from clutter_actor_destroy() */
5180 if (priv->parent != NULL)
5182 ClutterActor *parent = priv->parent;
5184 /* go through the Container implementation unless this
5185 * is an internal child and has been marked as such.
5187 * removing the actor from its parent will reset the
5188 * realized and mapped states.
5190 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5191 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5193 clutter_actor_remove_child_internal (parent, self,
5194 REMOVE_CHILD_LEGACY_FLAGS);
5197 /* parent must be gone at this point */
5198 g_assert (priv->parent == NULL);
5200 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5202 /* can't be mapped or realized with no parent */
5203 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5204 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5207 g_clear_object (&priv->pango_context);
5208 g_clear_object (&priv->actions);
5209 g_clear_object (&priv->constraints);
5210 g_clear_object (&priv->effects);
5211 g_clear_object (&priv->flatten_effect);
5213 if (priv->layout_manager != NULL)
5215 clutter_layout_manager_set_container (priv->layout_manager, NULL);
5216 g_clear_object (&priv->layout_manager);
5219 if (priv->content != NULL)
5221 _clutter_content_detached (priv->content, self);
5222 g_clear_object (&priv->content);
5225 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5229 clutter_actor_finalize (GObject *object)
5231 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5233 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5234 priv->name != NULL ? priv->name : "<none>",
5236 g_type_name (G_OBJECT_TYPE (object)));
5238 _clutter_context_release_id (priv->id);
5240 g_free (priv->name);
5242 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5247 * clutter_actor_get_accessible:
5248 * @self: a #ClutterActor
5250 * Returns the accessible object that describes the actor to an
5251 * assistive technology.
5253 * If no class-specific #AtkObject implementation is available for the
5254 * actor instance in question, it will inherit an #AtkObject
5255 * implementation from the first ancestor class for which such an
5256 * implementation is defined.
5258 * The documentation of the <ulink
5259 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5260 * library contains more information about accessible objects and
5263 * Returns: (transfer none): the #AtkObject associated with @actor
5266 clutter_actor_get_accessible (ClutterActor *self)
5268 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5270 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5274 clutter_actor_real_get_accessible (ClutterActor *actor)
5276 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5280 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5282 AtkObject *accessible;
5284 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5285 if (accessible != NULL)
5286 g_object_ref (accessible);
5292 atk_implementor_iface_init (AtkImplementorIface *iface)
5294 iface->ref_accessible = _clutter_actor_ref_accessible;
5298 clutter_actor_update_default_paint_volume (ClutterActor *self,
5299 ClutterPaintVolume *volume)
5301 ClutterActorPrivate *priv = self->priv;
5302 gboolean res = TRUE;
5304 /* we start from the allocation */
5305 clutter_paint_volume_set_width (volume,
5306 priv->allocation.x2 - priv->allocation.x1);
5307 clutter_paint_volume_set_height (volume,
5308 priv->allocation.y2 - priv->allocation.y1);
5310 /* if the actor has a clip set then we have a pretty definite
5311 * size for the paint volume: the actor cannot possibly paint
5312 * outside the clip region.
5314 if (priv->clip_to_allocation)
5316 /* the allocation has already been set, so we just flip the
5323 ClutterActor *child;
5325 if (priv->has_clip &&
5326 priv->clip.width >= 0 &&
5327 priv->clip.height >= 0)
5329 ClutterVertex origin;
5331 origin.x = priv->clip.x;
5332 origin.y = priv->clip.y;
5335 clutter_paint_volume_set_origin (volume, &origin);
5336 clutter_paint_volume_set_width (volume, priv->clip.width);
5337 clutter_paint_volume_set_height (volume, priv->clip.height);
5342 /* if we don't have children we just bail out here... */
5343 if (priv->n_children == 0)
5346 /* ...but if we have children then we ask for their paint volume in
5347 * our coordinates. if any of our children replies that it doesn't
5348 * have a paint volume, we bail out
5350 for (child = priv->first_child;
5352 child = child->priv->next_sibling)
5354 const ClutterPaintVolume *child_volume;
5356 if (!CLUTTER_ACTOR_IS_MAPPED (child))
5359 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5360 if (child_volume == NULL)
5366 clutter_paint_volume_union (volume, child_volume);
5376 clutter_actor_real_get_paint_volume (ClutterActor *self,
5377 ClutterPaintVolume *volume)
5379 ClutterActorClass *klass;
5382 klass = CLUTTER_ACTOR_GET_CLASS (self);
5384 /* XXX - this thoroughly sucks, but we don't want to penalize users
5385 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5386 * redraw. This should go away in 2.0.
5388 if (klass->paint == clutter_actor_real_paint &&
5389 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5395 /* this is the default return value: we cannot know if a class
5396 * is going to paint outside its allocation, so we take the
5397 * conservative approach.
5402 /* update_default_paint_volume() should only fail if one of the children
5403 * reported an invalid, or no, paint volume
5405 if (!clutter_actor_update_default_paint_volume (self, volume))
5412 * clutter_actor_get_default_paint_volume:
5413 * @self: a #ClutterActor
5415 * Retrieves the default paint volume for @self.
5417 * This function provides the same #ClutterPaintVolume that would be
5418 * computed by the default implementation inside #ClutterActor of the
5419 * #ClutterActorClass.get_paint_volume() virtual function.
5421 * This function should only be used by #ClutterActor subclasses that
5422 * cannot chain up to the parent implementation when computing their
5425 * Return value: (transfer none): a pointer to the default
5426 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5427 * the actor could not compute a valid paint volume. The returned value
5428 * is not guaranteed to be stable across multiple frames, so if you
5429 * want to retain it, you will need to copy it using
5430 * clutter_paint_volume_copy().
5434 const ClutterPaintVolume *
5435 clutter_actor_get_default_paint_volume (ClutterActor *self)
5437 ClutterPaintVolume volume;
5438 ClutterPaintVolume *res;
5440 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5443 _clutter_paint_volume_init_static (&volume, self);
5444 if (clutter_actor_update_default_paint_volume (self, &volume))
5446 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5450 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5451 _clutter_paint_volume_copy_static (&volume, res);
5455 clutter_paint_volume_free (&volume);
5461 clutter_actor_real_has_overlaps (ClutterActor *self)
5463 /* By default we'll assume that all actors need an offscreen redirect to get
5464 * the correct opacity. Actors such as ClutterTexture that would never need
5465 * an offscreen redirect can override this to return FALSE. */
5470 clutter_actor_real_destroy (ClutterActor *actor)
5472 ClutterActorIter iter;
5474 g_object_freeze_notify (G_OBJECT (actor));
5476 clutter_actor_iter_init (&iter, actor);
5477 while (clutter_actor_iter_next (&iter, NULL))
5478 clutter_actor_iter_destroy (&iter);
5480 g_object_thaw_notify (G_OBJECT (actor));
5484 clutter_actor_constructor (GType gtype,
5486 GObjectConstructParam *props)
5488 GObjectClass *gobject_class;
5492 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5493 retval = gobject_class->constructor (gtype, n_props, props);
5494 self = CLUTTER_ACTOR (retval);
5496 if (self->priv->layout_manager == NULL)
5498 ClutterLayoutManager *default_layout;
5500 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5502 default_layout = clutter_fixed_layout_new ();
5503 clutter_actor_set_layout_manager (self, default_layout);
5510 clutter_actor_class_init (ClutterActorClass *klass)
5512 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5514 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5515 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5516 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5517 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5519 object_class->constructor = clutter_actor_constructor;
5520 object_class->set_property = clutter_actor_set_property;
5521 object_class->get_property = clutter_actor_get_property;
5522 object_class->dispose = clutter_actor_dispose;
5523 object_class->finalize = clutter_actor_finalize;
5525 klass->show = clutter_actor_real_show;
5526 klass->show_all = clutter_actor_show;
5527 klass->hide = clutter_actor_real_hide;
5528 klass->hide_all = clutter_actor_hide;
5529 klass->map = clutter_actor_real_map;
5530 klass->unmap = clutter_actor_real_unmap;
5531 klass->unrealize = clutter_actor_real_unrealize;
5532 klass->pick = clutter_actor_real_pick;
5533 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5534 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5535 klass->allocate = clutter_actor_real_allocate;
5536 klass->queue_redraw = clutter_actor_real_queue_redraw;
5537 klass->queue_relayout = clutter_actor_real_queue_relayout;
5538 klass->apply_transform = clutter_actor_real_apply_transform;
5539 klass->get_accessible = clutter_actor_real_get_accessible;
5540 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5541 klass->has_overlaps = clutter_actor_real_has_overlaps;
5542 klass->paint = clutter_actor_real_paint;
5543 klass->destroy = clutter_actor_real_destroy;
5545 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5550 * X coordinate of the actor in pixels. If written, forces a fixed
5551 * position for the actor. If read, returns the fixed position if any,
5552 * otherwise the allocation if available, otherwise 0.
5554 * The #ClutterActor:x property is animatable.
5557 g_param_spec_float ("x",
5559 P_("X coordinate of the actor"),
5560 -G_MAXFLOAT, G_MAXFLOAT,
5563 G_PARAM_STATIC_STRINGS |
5564 CLUTTER_PARAM_ANIMATABLE);
5569 * Y coordinate of the actor in pixels. If written, forces a fixed
5570 * position for the actor. If read, returns the fixed position if
5571 * any, otherwise the allocation if available, otherwise 0.
5573 * The #ClutterActor:y property is animatable.
5576 g_param_spec_float ("y",
5578 P_("Y coordinate of the actor"),
5579 -G_MAXFLOAT, G_MAXFLOAT,
5582 G_PARAM_STATIC_STRINGS |
5583 CLUTTER_PARAM_ANIMATABLE);
5586 * ClutterActor:position:
5588 * The position of the origin of the actor.
5590 * This property is a shorthand for setting and getting the
5591 * #ClutterActor:x and #ClutterActor:y properties at the same
5594 * The #ClutterActor:position property is animatable.
5598 obj_props[PROP_POSITION] =
5599 g_param_spec_boxed ("position",
5601 P_("The position of the origin of the actor"),
5604 G_PARAM_STATIC_STRINGS |
5605 CLUTTER_PARAM_ANIMATABLE);
5608 * ClutterActor:width:
5610 * Width of the actor (in pixels). If written, forces the minimum and
5611 * natural size request of the actor to the given width. If read, returns
5612 * the allocated width if available, otherwise the width request.
5614 * The #ClutterActor:width property is animatable.
5616 obj_props[PROP_WIDTH] =
5617 g_param_spec_float ("width",
5619 P_("Width of the actor"),
5623 G_PARAM_STATIC_STRINGS |
5624 CLUTTER_PARAM_ANIMATABLE);
5627 * ClutterActor:height:
5629 * Height of the actor (in pixels). If written, forces the minimum and
5630 * natural size request of the actor to the given height. If read, returns
5631 * the allocated height if available, otherwise the height request.
5633 * The #ClutterActor:height property is animatable.
5635 obj_props[PROP_HEIGHT] =
5636 g_param_spec_float ("height",
5638 P_("Height of the actor"),
5642 G_PARAM_STATIC_STRINGS |
5643 CLUTTER_PARAM_ANIMATABLE);
5646 * ClutterActor:size:
5648 * The size of the actor.
5650 * This property is a shorthand for setting and getting the
5651 * #ClutterActor:width and #ClutterActor:height at the same time.
5653 * The #ClutterActor:size property is animatable.
5657 obj_props[PROP_SIZE] =
5658 g_param_spec_boxed ("size",
5660 P_("The size of the actor"),
5663 G_PARAM_STATIC_STRINGS |
5664 CLUTTER_PARAM_ANIMATABLE);
5667 * ClutterActor:fixed-x:
5669 * The fixed X position of the actor in pixels.
5671 * Writing this property sets #ClutterActor:fixed-position-set
5672 * property as well, as a side effect
5676 obj_props[PROP_FIXED_X] =
5677 g_param_spec_float ("fixed-x",
5679 P_("Forced X position of the actor"),
5680 -G_MAXFLOAT, G_MAXFLOAT,
5682 CLUTTER_PARAM_READWRITE);
5685 * ClutterActor:fixed-y:
5687 * The fixed Y position of the actor in pixels.
5689 * Writing this property sets the #ClutterActor:fixed-position-set
5690 * property as well, as a side effect
5694 obj_props[PROP_FIXED_Y] =
5695 g_param_spec_float ("fixed-y",
5697 P_("Forced Y position of the actor"),
5698 -G_MAXFLOAT, G_MAXFLOAT,
5700 CLUTTER_PARAM_READWRITE);
5703 * ClutterActor:fixed-position-set:
5705 * This flag controls whether the #ClutterActor:fixed-x and
5706 * #ClutterActor:fixed-y properties are used
5710 obj_props[PROP_FIXED_POSITION_SET] =
5711 g_param_spec_boolean ("fixed-position-set",
5712 P_("Fixed position set"),
5713 P_("Whether to use fixed positioning for the actor"),
5715 CLUTTER_PARAM_READWRITE);
5718 * ClutterActor:min-width:
5720 * A forced minimum width request for the actor, in pixels
5722 * Writing this property sets the #ClutterActor:min-width-set property
5723 * as well, as a side effect.
5725 *This property overrides the usual width request of the actor.
5729 obj_props[PROP_MIN_WIDTH] =
5730 g_param_spec_float ("min-width",
5732 P_("Forced minimum width request for the actor"),
5735 CLUTTER_PARAM_READWRITE);
5738 * ClutterActor:min-height:
5740 * A forced minimum height request for the actor, in pixels
5742 * Writing this property sets the #ClutterActor:min-height-set property
5743 * as well, as a side effect. This property overrides the usual height
5744 * request of the actor.
5748 obj_props[PROP_MIN_HEIGHT] =
5749 g_param_spec_float ("min-height",
5751 P_("Forced minimum height request for the actor"),
5754 CLUTTER_PARAM_READWRITE);
5757 * ClutterActor:natural-width:
5759 * A forced natural width request for the actor, in pixels
5761 * Writing this property sets the #ClutterActor:natural-width-set
5762 * property as well, as a side effect. This property overrides the
5763 * usual width request of the actor
5767 obj_props[PROP_NATURAL_WIDTH] =
5768 g_param_spec_float ("natural-width",
5769 P_("Natural Width"),
5770 P_("Forced natural width request for the actor"),
5773 CLUTTER_PARAM_READWRITE);
5776 * ClutterActor:natural-height:
5778 * A forced natural height request for the actor, in pixels
5780 * Writing this property sets the #ClutterActor:natural-height-set
5781 * property as well, as a side effect. This property overrides the
5782 * usual height request of the actor
5786 obj_props[PROP_NATURAL_HEIGHT] =
5787 g_param_spec_float ("natural-height",
5788 P_("Natural Height"),
5789 P_("Forced natural height request for the actor"),
5792 CLUTTER_PARAM_READWRITE);
5795 * ClutterActor:min-width-set:
5797 * This flag controls whether the #ClutterActor:min-width property
5802 obj_props[PROP_MIN_WIDTH_SET] =
5803 g_param_spec_boolean ("min-width-set",
5804 P_("Minimum width set"),
5805 P_("Whether to use the min-width property"),
5807 CLUTTER_PARAM_READWRITE);
5810 * ClutterActor:min-height-set:
5812 * This flag controls whether the #ClutterActor:min-height property
5817 obj_props[PROP_MIN_HEIGHT_SET] =
5818 g_param_spec_boolean ("min-height-set",
5819 P_("Minimum height set"),
5820 P_("Whether to use the min-height property"),
5822 CLUTTER_PARAM_READWRITE);
5825 * ClutterActor:natural-width-set:
5827 * This flag controls whether the #ClutterActor:natural-width property
5832 obj_props[PROP_NATURAL_WIDTH_SET] =
5833 g_param_spec_boolean ("natural-width-set",
5834 P_("Natural width set"),
5835 P_("Whether to use the natural-width property"),
5837 CLUTTER_PARAM_READWRITE);
5840 * ClutterActor:natural-height-set:
5842 * This flag controls whether the #ClutterActor:natural-height property
5847 obj_props[PROP_NATURAL_HEIGHT_SET] =
5848 g_param_spec_boolean ("natural-height-set",
5849 P_("Natural height set"),
5850 P_("Whether to use the natural-height property"),
5852 CLUTTER_PARAM_READWRITE);
5855 * ClutterActor:allocation:
5857 * The allocation for the actor, in pixels
5859 * This is property is read-only, but you might monitor it to know when an
5860 * actor moves or resizes
5864 obj_props[PROP_ALLOCATION] =
5865 g_param_spec_boxed ("allocation",
5867 P_("The actor's allocation"),
5868 CLUTTER_TYPE_ACTOR_BOX,
5870 G_PARAM_STATIC_STRINGS |
5871 CLUTTER_PARAM_ANIMATABLE);
5874 * ClutterActor:request-mode:
5876 * Request mode for the #ClutterActor. The request mode determines the
5877 * type of geometry management used by the actor, either height for width
5878 * (the default) or width for height.
5880 * For actors implementing height for width, the parent container should get
5881 * the preferred width first, and then the preferred height for that width.
5883 * For actors implementing width for height, the parent container should get
5884 * the preferred height first, and then the preferred width for that height.
5889 * ClutterRequestMode mode;
5890 * gfloat natural_width, min_width;
5891 * gfloat natural_height, min_height;
5893 * mode = clutter_actor_get_request_mode (child);
5894 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5896 * clutter_actor_get_preferred_width (child, -1,
5898 * &natural_width);
5899 * clutter_actor_get_preferred_height (child, natural_width,
5901 * &natural_height);
5905 * clutter_actor_get_preferred_height (child, -1,
5907 * &natural_height);
5908 * clutter_actor_get_preferred_width (child, natural_height,
5910 * &natural_width);
5914 * will retrieve the minimum and natural width and height depending on the
5915 * preferred request mode of the #ClutterActor "child".
5917 * The clutter_actor_get_preferred_size() function will implement this
5922 obj_props[PROP_REQUEST_MODE] =
5923 g_param_spec_enum ("request-mode",
5925 P_("The actor's request mode"),
5926 CLUTTER_TYPE_REQUEST_MODE,
5927 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5928 CLUTTER_PARAM_READWRITE);
5931 * ClutterActor:depth:
5933 * The position of the actor on the Z axis.
5935 * The #ClutterActor:depth property is relative to the parent's
5938 * The #ClutterActor:depth property is animatable.
5942 obj_props[PROP_DEPTH] =
5943 g_param_spec_float ("depth",
5945 P_("Position on the Z axis"),
5946 -G_MAXFLOAT, G_MAXFLOAT,
5949 G_PARAM_STATIC_STRINGS |
5950 CLUTTER_PARAM_ANIMATABLE);
5953 * ClutterActor:opacity:
5955 * Opacity of an actor, between 0 (fully transparent) and
5956 * 255 (fully opaque)
5958 * The #ClutterActor:opacity property is animatable.
5960 obj_props[PROP_OPACITY] =
5961 g_param_spec_uint ("opacity",
5963 P_("Opacity of an actor"),
5967 G_PARAM_STATIC_STRINGS |
5968 CLUTTER_PARAM_ANIMATABLE);
5971 * ClutterActor:offscreen-redirect:
5973 * Determines the conditions in which the actor will be redirected
5974 * to an offscreen framebuffer while being painted. For example this
5975 * can be used to cache an actor in a framebuffer or for improved
5976 * handling of transparent actors. See
5977 * clutter_actor_set_offscreen_redirect() for details.
5981 obj_props[PROP_OFFSCREEN_REDIRECT] =
5982 g_param_spec_flags ("offscreen-redirect",
5983 P_("Offscreen redirect"),
5984 P_("Flags controlling when to flatten the actor into a single image"),
5985 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5987 CLUTTER_PARAM_READWRITE);
5990 * ClutterActor:visible:
5992 * Whether the actor is set to be visible or not
5994 * See also #ClutterActor:mapped
5996 obj_props[PROP_VISIBLE] =
5997 g_param_spec_boolean ("visible",
5999 P_("Whether the actor is visible or not"),
6001 CLUTTER_PARAM_READWRITE);
6004 * ClutterActor:mapped:
6006 * Whether the actor is mapped (will be painted when the stage
6007 * to which it belongs is mapped)
6011 obj_props[PROP_MAPPED] =
6012 g_param_spec_boolean ("mapped",
6014 P_("Whether the actor will be painted"),
6016 CLUTTER_PARAM_READABLE);
6019 * ClutterActor:realized:
6021 * Whether the actor has been realized
6025 obj_props[PROP_REALIZED] =
6026 g_param_spec_boolean ("realized",
6028 P_("Whether the actor has been realized"),
6030 CLUTTER_PARAM_READABLE);
6033 * ClutterActor:reactive:
6035 * Whether the actor is reactive to events or not
6037 * Only reactive actors will emit event-related signals
6041 obj_props[PROP_REACTIVE] =
6042 g_param_spec_boolean ("reactive",
6044 P_("Whether the actor is reactive to events"),
6046 CLUTTER_PARAM_READWRITE);
6049 * ClutterActor:has-clip:
6051 * Whether the actor has the #ClutterActor:clip property set or not
6053 obj_props[PROP_HAS_CLIP] =
6054 g_param_spec_boolean ("has-clip",
6056 P_("Whether the actor has a clip set"),
6058 CLUTTER_PARAM_READABLE);
6061 * ClutterActor:clip:
6063 * The clip region for the actor, in actor-relative coordinates
6065 * Every part of the actor outside the clip region will not be
6068 obj_props[PROP_CLIP] =
6069 g_param_spec_boxed ("clip",
6071 P_("The clip region for the actor"),
6072 CLUTTER_TYPE_GEOMETRY,
6073 CLUTTER_PARAM_READWRITE);
6076 * ClutterActor:name:
6078 * The name of the actor
6082 obj_props[PROP_NAME] =
6083 g_param_spec_string ("name",
6085 P_("Name of the actor"),
6087 CLUTTER_PARAM_READWRITE);
6090 * ClutterActor:scale-x:
6092 * The horizontal scale of the actor.
6094 * The #ClutterActor:scale-x property is animatable.
6098 obj_props[PROP_SCALE_X] =
6099 g_param_spec_double ("scale-x",
6101 P_("Scale factor on the X axis"),
6105 G_PARAM_STATIC_STRINGS |
6106 CLUTTER_PARAM_ANIMATABLE);
6109 * ClutterActor:scale-y:
6111 * The vertical scale of the actor.
6113 * The #ClutterActor:scale-y property is animatable.
6117 obj_props[PROP_SCALE_Y] =
6118 g_param_spec_double ("scale-y",
6120 P_("Scale factor on the Y axis"),
6124 G_PARAM_STATIC_STRINGS |
6125 CLUTTER_PARAM_ANIMATABLE);
6128 * ClutterActor:scale-center-x:
6130 * The horizontal center point for scaling
6134 obj_props[PROP_SCALE_CENTER_X] =
6135 g_param_spec_float ("scale-center-x",
6136 P_("Scale Center X"),
6137 P_("Horizontal scale center"),
6138 -G_MAXFLOAT, G_MAXFLOAT,
6140 CLUTTER_PARAM_READWRITE);
6143 * ClutterActor:scale-center-y:
6145 * The vertical center point for scaling
6149 obj_props[PROP_SCALE_CENTER_Y] =
6150 g_param_spec_float ("scale-center-y",
6151 P_("Scale Center Y"),
6152 P_("Vertical scale center"),
6153 -G_MAXFLOAT, G_MAXFLOAT,
6155 CLUTTER_PARAM_READWRITE);
6158 * ClutterActor:scale-gravity:
6160 * The center point for scaling expressed as a #ClutterGravity
6164 obj_props[PROP_SCALE_GRAVITY] =
6165 g_param_spec_enum ("scale-gravity",
6166 P_("Scale Gravity"),
6167 P_("The center of scaling"),
6168 CLUTTER_TYPE_GRAVITY,
6169 CLUTTER_GRAVITY_NONE,
6170 CLUTTER_PARAM_READWRITE);
6173 * ClutterActor:rotation-angle-x:
6175 * The rotation angle on the X axis.
6177 * The #ClutterActor:rotation-angle-x property is animatable.
6181 obj_props[PROP_ROTATION_ANGLE_X] =
6182 g_param_spec_double ("rotation-angle-x",
6183 P_("Rotation Angle X"),
6184 P_("The rotation angle on the X axis"),
6185 -G_MAXDOUBLE, G_MAXDOUBLE,
6188 G_PARAM_STATIC_STRINGS |
6189 CLUTTER_PARAM_ANIMATABLE);
6192 * ClutterActor:rotation-angle-y:
6194 * The rotation angle on the Y axis
6196 * The #ClutterActor:rotation-angle-y property is animatable.
6200 obj_props[PROP_ROTATION_ANGLE_Y] =
6201 g_param_spec_double ("rotation-angle-y",
6202 P_("Rotation Angle Y"),
6203 P_("The rotation angle on the Y axis"),
6204 -G_MAXDOUBLE, G_MAXDOUBLE,
6207 G_PARAM_STATIC_STRINGS |
6208 CLUTTER_PARAM_ANIMATABLE);
6211 * ClutterActor:rotation-angle-z:
6213 * The rotation angle on the Z axis
6215 * The #ClutterActor:rotation-angle-z property is animatable.
6219 obj_props[PROP_ROTATION_ANGLE_Z] =
6220 g_param_spec_double ("rotation-angle-z",
6221 P_("Rotation Angle Z"),
6222 P_("The rotation angle on the Z axis"),
6223 -G_MAXDOUBLE, G_MAXDOUBLE,
6226 G_PARAM_STATIC_STRINGS |
6227 CLUTTER_PARAM_ANIMATABLE);
6230 * ClutterActor:rotation-center-x:
6232 * The rotation center on the X axis.
6236 obj_props[PROP_ROTATION_CENTER_X] =
6237 g_param_spec_boxed ("rotation-center-x",
6238 P_("Rotation Center X"),
6239 P_("The rotation center on the X axis"),
6240 CLUTTER_TYPE_VERTEX,
6241 CLUTTER_PARAM_READWRITE);
6244 * ClutterActor:rotation-center-y:
6246 * The rotation center on the Y axis.
6250 obj_props[PROP_ROTATION_CENTER_Y] =
6251 g_param_spec_boxed ("rotation-center-y",
6252 P_("Rotation Center Y"),
6253 P_("The rotation center on the Y axis"),
6254 CLUTTER_TYPE_VERTEX,
6255 CLUTTER_PARAM_READWRITE);
6258 * ClutterActor:rotation-center-z:
6260 * The rotation center on the Z axis.
6264 obj_props[PROP_ROTATION_CENTER_Z] =
6265 g_param_spec_boxed ("rotation-center-z",
6266 P_("Rotation Center Z"),
6267 P_("The rotation center on the Z axis"),
6268 CLUTTER_TYPE_VERTEX,
6269 CLUTTER_PARAM_READWRITE);
6272 * ClutterActor:rotation-center-z-gravity:
6274 * The rotation center on the Z axis expressed as a #ClutterGravity.
6278 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6279 g_param_spec_enum ("rotation-center-z-gravity",
6280 P_("Rotation Center Z Gravity"),
6281 P_("Center point for rotation around the Z axis"),
6282 CLUTTER_TYPE_GRAVITY,
6283 CLUTTER_GRAVITY_NONE,
6284 CLUTTER_PARAM_READWRITE);
6287 * ClutterActor:anchor-x:
6289 * The X coordinate of an actor's anchor point, relative to
6290 * the actor coordinate space, in pixels
6294 obj_props[PROP_ANCHOR_X] =
6295 g_param_spec_float ("anchor-x",
6297 P_("X coordinate of the anchor point"),
6298 -G_MAXFLOAT, G_MAXFLOAT,
6300 CLUTTER_PARAM_READWRITE);
6303 * ClutterActor:anchor-y:
6305 * The Y coordinate of an actor's anchor point, relative to
6306 * the actor coordinate space, in pixels
6310 obj_props[PROP_ANCHOR_Y] =
6311 g_param_spec_float ("anchor-y",
6313 P_("Y coordinate of the anchor point"),
6314 -G_MAXFLOAT, G_MAXFLOAT,
6316 CLUTTER_PARAM_READWRITE);
6319 * ClutterActor:anchor-gravity:
6321 * The anchor point expressed as a #ClutterGravity
6325 obj_props[PROP_ANCHOR_GRAVITY] =
6326 g_param_spec_enum ("anchor-gravity",
6327 P_("Anchor Gravity"),
6328 P_("The anchor point as a ClutterGravity"),
6329 CLUTTER_TYPE_GRAVITY,
6330 CLUTTER_GRAVITY_NONE,
6331 CLUTTER_PARAM_READWRITE);
6334 * ClutterActor:show-on-set-parent:
6336 * If %TRUE, the actor is automatically shown when parented.
6338 * Calling clutter_actor_hide() on an actor which has not been
6339 * parented will set this property to %FALSE as a side effect.
6343 obj_props[PROP_SHOW_ON_SET_PARENT] =
6344 g_param_spec_boolean ("show-on-set-parent",
6345 P_("Show on set parent"),
6346 P_("Whether the actor is shown when parented"),
6348 CLUTTER_PARAM_READWRITE);
6351 * ClutterActor:clip-to-allocation:
6353 * Whether the clip region should track the allocated area
6356 * This property is ignored if a clip area has been explicitly
6357 * set using clutter_actor_set_clip().
6361 obj_props[PROP_CLIP_TO_ALLOCATION] =
6362 g_param_spec_boolean ("clip-to-allocation",
6363 P_("Clip to Allocation"),
6364 P_("Sets the clip region to track the actor's allocation"),
6366 CLUTTER_PARAM_READWRITE);
6369 * ClutterActor:text-direction:
6371 * The direction of the text inside a #ClutterActor.
6375 obj_props[PROP_TEXT_DIRECTION] =
6376 g_param_spec_enum ("text-direction",
6377 P_("Text Direction"),
6378 P_("Direction of the text"),
6379 CLUTTER_TYPE_TEXT_DIRECTION,
6380 CLUTTER_TEXT_DIRECTION_LTR,
6381 CLUTTER_PARAM_READWRITE);
6384 * ClutterActor:has-pointer:
6386 * Whether the actor contains the pointer of a #ClutterInputDevice
6391 obj_props[PROP_HAS_POINTER] =
6392 g_param_spec_boolean ("has-pointer",
6394 P_("Whether the actor contains the pointer of an input device"),
6396 CLUTTER_PARAM_READABLE);
6399 * ClutterActor:actions:
6401 * Adds a #ClutterAction to the actor
6405 obj_props[PROP_ACTIONS] =
6406 g_param_spec_object ("actions",
6408 P_("Adds an action to the actor"),
6409 CLUTTER_TYPE_ACTION,
6410 CLUTTER_PARAM_WRITABLE);
6413 * ClutterActor:constraints:
6415 * Adds a #ClutterConstraint to the actor
6419 obj_props[PROP_CONSTRAINTS] =
6420 g_param_spec_object ("constraints",
6422 P_("Adds a constraint to the actor"),
6423 CLUTTER_TYPE_CONSTRAINT,
6424 CLUTTER_PARAM_WRITABLE);
6427 * ClutterActor:effect:
6429 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6433 obj_props[PROP_EFFECT] =
6434 g_param_spec_object ("effect",
6436 P_("Add an effect to be applied on the actor"),
6437 CLUTTER_TYPE_EFFECT,
6438 CLUTTER_PARAM_WRITABLE);
6441 * ClutterActor:layout-manager:
6443 * A delegate object for controlling the layout of the children of
6448 obj_props[PROP_LAYOUT_MANAGER] =
6449 g_param_spec_object ("layout-manager",
6450 P_("Layout Manager"),
6451 P_("The object controlling the layout of an actor's children"),
6452 CLUTTER_TYPE_LAYOUT_MANAGER,
6453 CLUTTER_PARAM_READWRITE);
6456 * ClutterActor:x-expand:
6458 * Whether a layout manager should assign more space to the actor on
6463 obj_props[PROP_X_EXPAND] =
6464 g_param_spec_boolean ("x-expand",
6466 P_("Whether extra horizontal space should be assigned to the actor"),
6469 G_PARAM_STATIC_STRINGS);
6472 * ClutterActor:y-expand:
6474 * Whether a layout manager should assign more space to the actor on
6479 obj_props[PROP_Y_EXPAND] =
6480 g_param_spec_boolean ("y-expand",
6482 P_("Whether extra vertical space should be assigned to the actor"),
6485 G_PARAM_STATIC_STRINGS);
6488 * ClutterActor:x-align:
6490 * The alignment of an actor on the X axis, if the actor has been given
6491 * extra space for its allocation. See also the #ClutterActor:x-expand
6496 obj_props[PROP_X_ALIGN] =
6497 g_param_spec_enum ("x-align",
6499 P_("The alignment of the actor on the X axis within its allocation"),
6500 CLUTTER_TYPE_ACTOR_ALIGN,
6501 CLUTTER_ACTOR_ALIGN_FILL,
6502 CLUTTER_PARAM_READWRITE);
6505 * ClutterActor:y-align:
6507 * The alignment of an actor on the Y axis, if the actor has been given
6508 * extra space for its allocation.
6512 obj_props[PROP_Y_ALIGN] =
6513 g_param_spec_enum ("y-align",
6515 P_("The alignment of the actor on the Y axis within its allocation"),
6516 CLUTTER_TYPE_ACTOR_ALIGN,
6517 CLUTTER_ACTOR_ALIGN_FILL,
6518 CLUTTER_PARAM_READWRITE);
6521 * ClutterActor:margin-top:
6523 * The margin (in pixels) from the top of the actor.
6525 * This property adds a margin to the actor's preferred size; the margin
6526 * will be automatically taken into account when allocating the actor.
6530 obj_props[PROP_MARGIN_TOP] =
6531 g_param_spec_float ("margin-top",
6533 P_("Extra space at the top"),
6536 CLUTTER_PARAM_READWRITE);
6539 * ClutterActor:margin-bottom:
6541 * The margin (in pixels) from the bottom of the actor.
6543 * This property adds a margin to the actor's preferred size; the margin
6544 * will be automatically taken into account when allocating the actor.
6548 obj_props[PROP_MARGIN_BOTTOM] =
6549 g_param_spec_float ("margin-bottom",
6550 P_("Margin Bottom"),
6551 P_("Extra space at the bottom"),
6554 CLUTTER_PARAM_READWRITE);
6557 * ClutterActor:margin-left:
6559 * The margin (in pixels) from the left of the actor.
6561 * This property adds a margin to the actor's preferred size; the margin
6562 * will be automatically taken into account when allocating the actor.
6566 obj_props[PROP_MARGIN_LEFT] =
6567 g_param_spec_float ("margin-left",
6569 P_("Extra space at the left"),
6572 CLUTTER_PARAM_READWRITE);
6575 * ClutterActor:margin-right:
6577 * The margin (in pixels) from the right of the actor.
6579 * This property adds a margin to the actor's preferred size; the margin
6580 * will be automatically taken into account when allocating the actor.
6584 obj_props[PROP_MARGIN_RIGHT] =
6585 g_param_spec_float ("margin-right",
6587 P_("Extra space at the right"),
6590 CLUTTER_PARAM_READWRITE);
6593 * ClutterActor:background-color-set:
6595 * Whether the #ClutterActor:background-color property has been set.
6599 obj_props[PROP_BACKGROUND_COLOR_SET] =
6600 g_param_spec_boolean ("background-color-set",
6601 P_("Background Color Set"),
6602 P_("Whether the background color is set"),
6604 CLUTTER_PARAM_READABLE);
6607 * ClutterActor:background-color:
6609 * Paints a solid fill of the actor's allocation using the specified
6612 * The #ClutterActor:background-color property is animatable.
6616 obj_props[PROP_BACKGROUND_COLOR] =
6617 clutter_param_spec_color ("background-color",
6618 P_("Background color"),
6619 P_("The actor's background color"),
6620 CLUTTER_COLOR_Transparent,
6622 G_PARAM_STATIC_STRINGS |
6623 CLUTTER_PARAM_ANIMATABLE);
6626 * ClutterActor:first-child:
6628 * The actor's first child.
6632 obj_props[PROP_FIRST_CHILD] =
6633 g_param_spec_object ("first-child",
6635 P_("The actor's first child"),
6637 CLUTTER_PARAM_READABLE);
6640 * ClutterActor:last-child:
6642 * The actor's last child.
6646 obj_props[PROP_LAST_CHILD] =
6647 g_param_spec_object ("last-child",
6649 P_("The actor's last child"),
6651 CLUTTER_PARAM_READABLE);
6654 * ClutterActor:content:
6656 * The #ClutterContent implementation that controls the content
6661 obj_props[PROP_CONTENT] =
6662 g_param_spec_object ("content",
6664 P_("Delegate object for painting the actor's content"),
6665 CLUTTER_TYPE_CONTENT,
6666 CLUTTER_PARAM_READWRITE);
6669 * ClutterActor:content-gravity:
6671 * The alignment that should be honoured by the #ClutterContent
6672 * set with the #ClutterActor:content property.
6674 * Changing the value of this property will change the bounding box of
6675 * the content; you can use the #ClutterActor:content-box property to
6676 * get the position and size of the content within the actor's
6679 * This property is meaningful only for #ClutterContent implementations
6680 * that have a preferred size, and if the preferred size is smaller than
6681 * the actor's allocation.
6683 * The #ClutterActor:content-gravity property is animatable.
6687 obj_props[PROP_CONTENT_GRAVITY] =
6688 g_param_spec_enum ("content-gravity",
6689 P_("Content Gravity"),
6690 P_("Alignment of the actor's content"),
6691 CLUTTER_TYPE_CONTENT_GRAVITY,
6692 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6693 CLUTTER_PARAM_READWRITE);
6696 * ClutterActor:content-box:
6698 * The bounding box for the #ClutterContent used by the actor.
6700 * The value of this property is controlled by the #ClutterActor:allocation
6701 * and #ClutterActor:content-gravity properties of #ClutterActor.
6703 * The bounding box for the content is guaranteed to never exceed the
6704 * allocation's of the actor.
6708 obj_props[PROP_CONTENT_BOX] =
6709 g_param_spec_boxed ("content-box",
6711 P_("The bounding box of the actor's content"),
6712 CLUTTER_TYPE_ACTOR_BOX,
6714 G_PARAM_STATIC_STRINGS |
6715 CLUTTER_PARAM_ANIMATABLE);
6717 obj_props[PROP_MINIFICATION_FILTER] =
6718 g_param_spec_enum ("minification-filter",
6719 P_("Minification Filter"),
6720 P_("The filter used when reducing the size of the content"),
6721 CLUTTER_TYPE_SCALING_FILTER,
6722 CLUTTER_SCALING_FILTER_LINEAR,
6723 CLUTTER_PARAM_READWRITE);
6725 obj_props[PROP_MAGNIFICATION_FILTER] =
6726 g_param_spec_enum ("magnification-filter",
6727 P_("Magnification Filter"),
6728 P_("The filter used when increasing the size of the content"),
6729 CLUTTER_TYPE_SCALING_FILTER,
6730 CLUTTER_SCALING_FILTER_LINEAR,
6731 CLUTTER_PARAM_READWRITE);
6733 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6736 * ClutterActor::destroy:
6737 * @actor: the #ClutterActor which emitted the signal
6739 * The ::destroy signal notifies that all references held on the
6740 * actor which emitted it should be released.
6742 * The ::destroy signal should be used by all holders of a reference
6745 * This signal might result in the finalization of the #ClutterActor
6746 * if all references are released.
6748 * Composite actors and actors implementing the #ClutterContainer
6749 * interface should override the default implementation of the
6750 * class handler of this signal and call clutter_actor_destroy() on
6751 * their children. When overriding the default class handler, it is
6752 * required to chain up to the parent's implementation.
6756 actor_signals[DESTROY] =
6757 g_signal_new (I_("destroy"),
6758 G_TYPE_FROM_CLASS (object_class),
6759 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6760 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6762 _clutter_marshal_VOID__VOID,
6765 * ClutterActor::show:
6766 * @actor: the object which received the signal
6768 * The ::show signal is emitted when an actor is visible and
6769 * rendered on the stage.
6773 actor_signals[SHOW] =
6774 g_signal_new (I_("show"),
6775 G_TYPE_FROM_CLASS (object_class),
6777 G_STRUCT_OFFSET (ClutterActorClass, show),
6779 _clutter_marshal_VOID__VOID,
6782 * ClutterActor::hide:
6783 * @actor: the object which received the signal
6785 * The ::hide signal is emitted when an actor is no longer rendered
6790 actor_signals[HIDE] =
6791 g_signal_new (I_("hide"),
6792 G_TYPE_FROM_CLASS (object_class),
6794 G_STRUCT_OFFSET (ClutterActorClass, hide),
6796 _clutter_marshal_VOID__VOID,
6799 * ClutterActor::parent-set:
6800 * @actor: the object which received the signal
6801 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6803 * This signal is emitted when the parent of the actor changes.
6807 actor_signals[PARENT_SET] =
6808 g_signal_new (I_("parent-set"),
6809 G_TYPE_FROM_CLASS (object_class),
6811 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6813 _clutter_marshal_VOID__OBJECT,
6815 CLUTTER_TYPE_ACTOR);
6818 * ClutterActor::queue-redraw:
6819 * @actor: the actor we're bubbling the redraw request through
6820 * @origin: the actor which initiated the redraw request
6822 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6823 * is called on @origin.
6825 * The default implementation for #ClutterActor chains up to the
6826 * parent actor and queues a redraw on the parent, thus "bubbling"
6827 * the redraw queue up through the actor graph. The default
6828 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6829 * in a main loop idle handler.
6831 * Note that the @origin actor may be the stage, or a container; it
6832 * does not have to be a leaf node in the actor graph.
6834 * Toolkits embedding a #ClutterStage which require a redraw and
6835 * relayout cycle can stop the emission of this signal using the
6836 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6841 * on_redraw_complete (gpointer data)
6843 * ClutterStage *stage = data;
6845 * /* execute the Clutter drawing pipeline */
6846 * clutter_stage_ensure_redraw (stage);
6850 * on_stage_queue_redraw (ClutterStage *stage)
6852 * /* this prevents the default handler to run */
6853 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6855 * /* queue a redraw with the host toolkit and call
6856 * * a function when the redraw has been completed
6858 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6862 * <note><para>This signal is emitted before the Clutter paint
6863 * pipeline is executed. If you want to know when the pipeline has
6864 * been completed you should connect to the ::paint signal on the
6865 * Stage with g_signal_connect_after().</para></note>
6869 actor_signals[QUEUE_REDRAW] =
6870 g_signal_new (I_("queue-redraw"),
6871 G_TYPE_FROM_CLASS (object_class),
6874 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6876 _clutter_marshal_VOID__OBJECT,
6878 CLUTTER_TYPE_ACTOR);
6881 * ClutterActor::queue-relayout:
6882 * @actor: the actor being queued for relayout
6884 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6885 * is called on an actor.
6887 * The default implementation for #ClutterActor chains up to the
6888 * parent actor and queues a relayout on the parent, thus "bubbling"
6889 * the relayout queue up through the actor graph.
6891 * The main purpose of this signal is to allow relayout to be propagated
6892 * properly in the procense of #ClutterClone actors. Applications will
6893 * not normally need to connect to this signal.
6897 actor_signals[QUEUE_RELAYOUT] =
6898 g_signal_new (I_("queue-relayout"),
6899 G_TYPE_FROM_CLASS (object_class),
6902 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6904 _clutter_marshal_VOID__VOID,
6908 * ClutterActor::event:
6909 * @actor: the actor which received the event
6910 * @event: a #ClutterEvent
6912 * The ::event signal is emitted each time an event is received
6913 * by the @actor. This signal will be emitted on every actor,
6914 * following the hierarchy chain, until it reaches the top-level
6915 * container (the #ClutterStage).
6917 * Return value: %TRUE if the event has been handled by the actor,
6918 * or %FALSE to continue the emission.
6922 actor_signals[EVENT] =
6923 g_signal_new (I_("event"),
6924 G_TYPE_FROM_CLASS (object_class),
6926 G_STRUCT_OFFSET (ClutterActorClass, event),
6927 _clutter_boolean_handled_accumulator, NULL,
6928 _clutter_marshal_BOOLEAN__BOXED,
6930 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6932 * ClutterActor::button-press-event:
6933 * @actor: the actor which received the event
6934 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6936 * The ::button-press-event signal is emitted each time a mouse button
6937 * is pressed on @actor.
6939 * Return value: %TRUE if the event has been handled by the actor,
6940 * or %FALSE to continue the emission.
6944 actor_signals[BUTTON_PRESS_EVENT] =
6945 g_signal_new (I_("button-press-event"),
6946 G_TYPE_FROM_CLASS (object_class),
6948 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6949 _clutter_boolean_handled_accumulator, NULL,
6950 _clutter_marshal_BOOLEAN__BOXED,
6952 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6954 * ClutterActor::button-release-event:
6955 * @actor: the actor which received the event
6956 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6958 * The ::button-release-event signal is emitted each time a mouse button
6959 * is released on @actor.
6961 * Return value: %TRUE if the event has been handled by the actor,
6962 * or %FALSE to continue the emission.
6966 actor_signals[BUTTON_RELEASE_EVENT] =
6967 g_signal_new (I_("button-release-event"),
6968 G_TYPE_FROM_CLASS (object_class),
6970 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6971 _clutter_boolean_handled_accumulator, NULL,
6972 _clutter_marshal_BOOLEAN__BOXED,
6974 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6976 * ClutterActor::scroll-event:
6977 * @actor: the actor which received the event
6978 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6980 * The ::scroll-event signal is emitted each time the mouse is
6981 * scrolled on @actor
6983 * Return value: %TRUE if the event has been handled by the actor,
6984 * or %FALSE to continue the emission.
6988 actor_signals[SCROLL_EVENT] =
6989 g_signal_new (I_("scroll-event"),
6990 G_TYPE_FROM_CLASS (object_class),
6992 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6993 _clutter_boolean_handled_accumulator, NULL,
6994 _clutter_marshal_BOOLEAN__BOXED,
6996 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6998 * ClutterActor::key-press-event:
6999 * @actor: the actor which received the event
7000 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7002 * The ::key-press-event signal is emitted each time a keyboard button
7003 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
7005 * Return value: %TRUE if the event has been handled by the actor,
7006 * or %FALSE to continue the emission.
7010 actor_signals[KEY_PRESS_EVENT] =
7011 g_signal_new (I_("key-press-event"),
7012 G_TYPE_FROM_CLASS (object_class),
7014 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
7015 _clutter_boolean_handled_accumulator, NULL,
7016 _clutter_marshal_BOOLEAN__BOXED,
7018 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7020 * ClutterActor::key-release-event:
7021 * @actor: the actor which received the event
7022 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7024 * The ::key-release-event signal is emitted each time a keyboard button
7025 * is released while @actor has key focus (see
7026 * clutter_stage_set_key_focus()).
7028 * Return value: %TRUE if the event has been handled by the actor,
7029 * or %FALSE to continue the emission.
7033 actor_signals[KEY_RELEASE_EVENT] =
7034 g_signal_new (I_("key-release-event"),
7035 G_TYPE_FROM_CLASS (object_class),
7037 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
7038 _clutter_boolean_handled_accumulator, NULL,
7039 _clutter_marshal_BOOLEAN__BOXED,
7041 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7043 * ClutterActor::motion-event:
7044 * @actor: the actor which received the event
7045 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
7047 * The ::motion-event signal is emitted each time the mouse pointer is
7048 * moved over @actor.
7050 * Return value: %TRUE if the event has been handled by the actor,
7051 * or %FALSE to continue the emission.
7055 actor_signals[MOTION_EVENT] =
7056 g_signal_new (I_("motion-event"),
7057 G_TYPE_FROM_CLASS (object_class),
7059 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
7060 _clutter_boolean_handled_accumulator, NULL,
7061 _clutter_marshal_BOOLEAN__BOXED,
7063 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7066 * ClutterActor::key-focus-in:
7067 * @actor: the actor which now has key focus
7069 * The ::key-focus-in signal is emitted when @actor receives key focus.
7073 actor_signals[KEY_FOCUS_IN] =
7074 g_signal_new (I_("key-focus-in"),
7075 G_TYPE_FROM_CLASS (object_class),
7077 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
7079 _clutter_marshal_VOID__VOID,
7083 * ClutterActor::key-focus-out:
7084 * @actor: the actor which now has key focus
7086 * The ::key-focus-out signal is emitted when @actor loses key focus.
7090 actor_signals[KEY_FOCUS_OUT] =
7091 g_signal_new (I_("key-focus-out"),
7092 G_TYPE_FROM_CLASS (object_class),
7094 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
7096 _clutter_marshal_VOID__VOID,
7100 * ClutterActor::enter-event:
7101 * @actor: the actor which the pointer has entered.
7102 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7104 * The ::enter-event signal is emitted when the pointer enters the @actor
7106 * Return value: %TRUE if the event has been handled by the actor,
7107 * or %FALSE to continue the emission.
7111 actor_signals[ENTER_EVENT] =
7112 g_signal_new (I_("enter-event"),
7113 G_TYPE_FROM_CLASS (object_class),
7115 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
7116 _clutter_boolean_handled_accumulator, NULL,
7117 _clutter_marshal_BOOLEAN__BOXED,
7119 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7122 * ClutterActor::leave-event:
7123 * @actor: the actor which the pointer has left
7124 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7126 * The ::leave-event signal is emitted when the pointer leaves the @actor.
7128 * Return value: %TRUE if the event has been handled by the actor,
7129 * or %FALSE to continue the emission.
7133 actor_signals[LEAVE_EVENT] =
7134 g_signal_new (I_("leave-event"),
7135 G_TYPE_FROM_CLASS (object_class),
7137 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7138 _clutter_boolean_handled_accumulator, NULL,
7139 _clutter_marshal_BOOLEAN__BOXED,
7141 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7144 * ClutterActor::captured-event:
7145 * @actor: the actor which received the signal
7146 * @event: a #ClutterEvent
7148 * The ::captured-event signal is emitted when an event is captured
7149 * by Clutter. This signal will be emitted starting from the top-level
7150 * container (the #ClutterStage) to the actor which received the event
7151 * going down the hierarchy. This signal can be used to intercept every
7152 * event before the specialized events (like
7153 * ClutterActor::button-press-event or ::key-released-event) are
7156 * Return value: %TRUE if the event has been handled by the actor,
7157 * or %FALSE to continue the emission.
7161 actor_signals[CAPTURED_EVENT] =
7162 g_signal_new (I_("captured-event"),
7163 G_TYPE_FROM_CLASS (object_class),
7165 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7166 _clutter_boolean_handled_accumulator, NULL,
7167 _clutter_marshal_BOOLEAN__BOXED,
7169 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7172 * ClutterActor::paint:
7173 * @actor: the #ClutterActor that received the signal
7175 * The ::paint signal is emitted each time an actor is being painted.
7177 * Subclasses of #ClutterActor should override the class signal handler
7178 * and paint themselves in that function.
7180 * It is possible to connect a handler to the ::paint signal in order
7181 * to set up some custom aspect of a paint.
7185 actor_signals[PAINT] =
7186 g_signal_new (I_("paint"),
7187 G_TYPE_FROM_CLASS (object_class),
7190 G_STRUCT_OFFSET (ClutterActorClass, paint),
7192 _clutter_marshal_VOID__VOID,
7195 * ClutterActor::realize:
7196 * @actor: the #ClutterActor that received the signal
7198 * The ::realize signal is emitted each time an actor is being
7203 actor_signals[REALIZE] =
7204 g_signal_new (I_("realize"),
7205 G_TYPE_FROM_CLASS (object_class),
7207 G_STRUCT_OFFSET (ClutterActorClass, realize),
7209 _clutter_marshal_VOID__VOID,
7212 * ClutterActor::unrealize:
7213 * @actor: the #ClutterActor that received the signal
7215 * The ::unrealize signal is emitted each time an actor is being
7220 actor_signals[UNREALIZE] =
7221 g_signal_new (I_("unrealize"),
7222 G_TYPE_FROM_CLASS (object_class),
7224 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7226 _clutter_marshal_VOID__VOID,
7230 * ClutterActor::pick:
7231 * @actor: the #ClutterActor that received the signal
7232 * @color: the #ClutterColor to be used when picking
7234 * The ::pick signal is emitted each time an actor is being painted
7235 * in "pick mode". The pick mode is used to identify the actor during
7236 * the event handling phase, or by clutter_stage_get_actor_at_pos().
7237 * The actor should paint its shape using the passed @pick_color.
7239 * Subclasses of #ClutterActor should override the class signal handler
7240 * and paint themselves in that function.
7242 * It is possible to connect a handler to the ::pick signal in order
7243 * to set up some custom aspect of a paint in pick mode.
7247 actor_signals[PICK] =
7248 g_signal_new (I_("pick"),
7249 G_TYPE_FROM_CLASS (object_class),
7251 G_STRUCT_OFFSET (ClutterActorClass, pick),
7253 _clutter_marshal_VOID__BOXED,
7255 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7258 * ClutterActor::allocation-changed:
7259 * @actor: the #ClutterActor that emitted the signal
7260 * @box: a #ClutterActorBox with the new allocation
7261 * @flags: #ClutterAllocationFlags for the allocation
7263 * The ::allocation-changed signal is emitted when the
7264 * #ClutterActor:allocation property changes. Usually, application
7265 * code should just use the notifications for the :allocation property
7266 * but if you want to track the allocation flags as well, for instance
7267 * to know whether the absolute origin of @actor changed, then you might
7268 * want use this signal instead.
7272 actor_signals[ALLOCATION_CHANGED] =
7273 g_signal_new (I_("allocation-changed"),
7274 G_TYPE_FROM_CLASS (object_class),
7278 _clutter_marshal_VOID__BOXED_FLAGS,
7280 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7281 CLUTTER_TYPE_ALLOCATION_FLAGS);
7284 * ClutterActor::transitions-completed:
7285 * @actor: a #ClutterActor
7287 * The ::transitions-completed signal is emitted once all transitions
7288 * involving @actor are complete.
7292 actor_signals[TRANSITIONS_COMPLETED] =
7293 g_signal_new (I_("transitions-completed"),
7294 G_TYPE_FROM_CLASS (object_class),
7298 _clutter_marshal_VOID__VOID,
7303 clutter_actor_init (ClutterActor *self)
7305 ClutterActorPrivate *priv;
7307 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7309 priv->id = _clutter_context_acquire_id (self);
7312 priv->opacity = 0xff;
7313 priv->show_on_set_parent = TRUE;
7315 priv->needs_width_request = TRUE;
7316 priv->needs_height_request = TRUE;
7317 priv->needs_allocation = TRUE;
7319 priv->cached_width_age = 1;
7320 priv->cached_height_age = 1;
7322 priv->opacity_override = -1;
7323 priv->enable_model_view_transform = TRUE;
7325 /* Initialize an empty paint volume to start with */
7326 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7327 priv->last_paint_volume_valid = TRUE;
7329 priv->transform_valid = FALSE;
7331 /* the default is to stretch the content, to match the
7332 * current behaviour of basically all actors. also, it's
7333 * the easiest thing to compute.
7335 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7336 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7337 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7339 /* this flag will be set to TRUE if the actor gets a child
7340 * or if the [xy]-expand flags are explicitly set; until
7341 * then, the actor does not need to expand.
7343 * this also allows us to avoid computing the expand flag
7344 * when building up a scene.
7346 priv->needs_compute_expand = FALSE;
7350 * clutter_actor_new:
7352 * Creates a new #ClutterActor.
7354 * A newly created actor has a floating reference, which will be sunk
7355 * when it is added to another actor.
7357 * Return value: (transfer full): the newly created #ClutterActor
7362 clutter_actor_new (void)
7364 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7368 * clutter_actor_destroy:
7369 * @self: a #ClutterActor
7371 * Destroys an actor. When an actor is destroyed, it will break any
7372 * references it holds to other objects. If the actor is inside a
7373 * container, the actor will be removed.
7375 * When you destroy a container, its children will be destroyed as well.
7377 * Note: you cannot destroy the #ClutterStage returned by
7378 * clutter_stage_get_default().
7381 clutter_actor_destroy (ClutterActor *self)
7383 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7385 g_object_ref (self);
7387 /* avoid recursion while destroying */
7388 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7390 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7392 g_object_run_dispose (G_OBJECT (self));
7394 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7397 g_object_unref (self);
7401 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7402 ClutterPaintVolume *clip)
7404 ClutterActorPrivate *priv = self->priv;
7405 ClutterPaintVolume *pv;
7408 /* Remove queue entry early in the process, otherwise a new
7409 queue_redraw() during signal handling could put back this
7410 object in the stage redraw list (but the entry is freed as
7411 soon as we return from this function, causing a segfault
7414 priv->queue_redraw_entry = NULL;
7416 /* If we've been explicitly passed a clip volume then there's
7417 * nothing more to calculate, but otherwise the only thing we know
7418 * is that the change is constrained to the given actor.
7420 * The idea is that if we know the paint volume for where the actor
7421 * was last drawn (in eye coordinates) and we also have the paint
7422 * volume for where it will be drawn next (in actor coordinates)
7423 * then if we queue a redraw for both these volumes that will cover
7424 * everything that needs to be redrawn to clear the old view and
7425 * show the latest view of the actor.
7427 * Don't clip this redraw if we don't know what position we had for
7428 * the previous redraw since we don't know where to set the clip so
7429 * it will clear the actor as it is currently.
7433 _clutter_actor_set_queue_redraw_clip (self, clip);
7436 else if (G_LIKELY (priv->last_paint_volume_valid))
7438 pv = _clutter_actor_get_paint_volume_mutable (self);
7441 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7443 /* make sure we redraw the actors old position... */
7444 _clutter_actor_set_queue_redraw_clip (stage,
7445 &priv->last_paint_volume);
7446 _clutter_actor_signal_queue_redraw (stage, stage);
7447 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7449 /* XXX: Ideally the redraw signal would take a clip volume
7450 * argument, but that would be an ABI break. Until we can
7451 * break the ABI we pass the argument out-of-band
7454 /* setup the clip for the actors new position... */
7455 _clutter_actor_set_queue_redraw_clip (self, pv);
7464 _clutter_actor_signal_queue_redraw (self, self);
7466 /* Just in case anyone is manually firing redraw signals without
7467 * using the public queue_redraw() API we are careful to ensure that
7468 * our out-of-band clip member is cleared before returning...
7470 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7472 if (G_LIKELY (clipped))
7473 _clutter_actor_set_queue_redraw_clip (self, NULL);
7477 _clutter_actor_get_allocation_clip (ClutterActor *self,
7478 ClutterActorBox *clip)
7480 ClutterActorBox allocation;
7482 /* XXX: we don't care if we get an out of date allocation here
7483 * because clutter_actor_queue_redraw_with_clip knows to ignore
7484 * the clip if the actor's allocation is invalid.
7486 * This is noted because clutter_actor_get_allocation_box does some
7487 * unnecessary work to support buggy code with a comment suggesting
7488 * that it could be changed later which would be good for this use
7491 clutter_actor_get_allocation_box (self, &allocation);
7493 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7494 * actor's own coordinate space but the allocation is in parent
7498 clip->x2 = allocation.x2 - allocation.x1;
7499 clip->y2 = allocation.y2 - allocation.y1;
7503 _clutter_actor_queue_redraw_full (ClutterActor *self,
7504 ClutterRedrawFlags flags,
7505 ClutterPaintVolume *volume,
7506 ClutterEffect *effect)
7508 ClutterActorPrivate *priv = self->priv;
7509 ClutterPaintVolume allocation_pv;
7510 ClutterPaintVolume *pv;
7511 gboolean should_free_pv;
7512 ClutterActor *stage;
7514 /* Here's an outline of the actor queue redraw mechanism:
7516 * The process starts in one of the following two functions which
7517 * are wrappers for this function:
7518 * clutter_actor_queue_redraw
7519 * _clutter_actor_queue_redraw_with_clip
7521 * additionally, an effect can queue a redraw by wrapping this
7522 * function in clutter_effect_queue_rerun
7524 * This functions queues an entry in a list associated with the
7525 * stage which is a list of actors that queued a redraw while
7526 * updating the timelines, performing layouting and processing other
7527 * mainloop sources before the next paint starts.
7529 * We aim to minimize the processing done at this point because
7530 * there is a good chance other events will happen while updating
7531 * the scenegraph that would invalidate any expensive work we might
7532 * otherwise try to do here. For example we don't try and resolve
7533 * the screen space bounding box of an actor at this stage so as to
7534 * minimize how much of the screen redraw because it's possible
7535 * something else will happen which will force a full redraw anyway.
7537 * When all updates are complete and we come to paint the stage then
7538 * we iterate this list and actually emit the "queue-redraw" signals
7539 * for each of the listed actors which will bubble up to the stage
7540 * for each actor and at that point we will transform the actors
7541 * paint volume into screen coordinates to determine the clip region
7542 * for what needs to be redrawn in the next paint.
7544 * Besides minimizing redundant work another reason for this
7545 * deferred design is that it's more likely we will be able to
7546 * determine the paint volume of an actor once we've finished
7547 * updating the scenegraph because its allocation should be up to
7548 * date. NB: If we can't determine an actors paint volume then we
7549 * can't automatically queue a clipped redraw which can make a big
7550 * difference to performance.
7552 * So the control flow goes like this:
7553 * One of clutter_actor_queue_redraw,
7554 * _clutter_actor_queue_redraw_with_clip
7555 * or clutter_effect_queue_rerun
7557 * then control moves to:
7558 * _clutter_stage_queue_actor_redraw
7560 * later during _clutter_stage_do_update, once relayouting is done
7561 * and the scenegraph has been updated we will call:
7562 * _clutter_stage_finish_queue_redraws
7564 * _clutter_stage_finish_queue_redraws will call
7565 * _clutter_actor_finish_queue_redraw for each listed actor.
7566 * Note: actors *are* allowed to queue further redraws during this
7567 * process (considering clone actors or texture_new_from_actor which
7568 * respond to their source queueing a redraw by queuing a redraw
7569 * themselves). We repeat the process until the list is empty.
7571 * This will result in the "queue-redraw" signal being fired for
7572 * each actor which will pass control to the default signal handler:
7573 * clutter_actor_real_queue_redraw
7575 * This will bubble up to the stages handler:
7576 * clutter_stage_real_queue_redraw
7578 * clutter_stage_real_queue_redraw will transform the actors paint
7579 * volume into screen space and add it as a clip region for the next
7583 /* ignore queueing a redraw for actors being destroyed */
7584 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7587 stage = _clutter_actor_get_stage_internal (self);
7589 /* Ignore queueing a redraw for actors not descended from a stage */
7593 /* ignore queueing a redraw on stages that are being destroyed */
7594 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7597 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7599 ClutterActorBox allocation_clip;
7600 ClutterVertex origin;
7602 /* If the actor doesn't have a valid allocation then we will
7603 * queue a full stage redraw. */
7604 if (priv->needs_allocation)
7606 /* NB: NULL denotes an undefined clip which will result in a
7608 _clutter_actor_set_queue_redraw_clip (self, NULL);
7609 _clutter_actor_signal_queue_redraw (self, self);
7613 _clutter_paint_volume_init_static (&allocation_pv, self);
7614 pv = &allocation_pv;
7616 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7618 origin.x = allocation_clip.x1;
7619 origin.y = allocation_clip.y1;
7621 clutter_paint_volume_set_origin (pv, &origin);
7622 clutter_paint_volume_set_width (pv,
7623 allocation_clip.x2 - allocation_clip.x1);
7624 clutter_paint_volume_set_height (pv,
7625 allocation_clip.y2 -
7626 allocation_clip.y1);
7627 should_free_pv = TRUE;
7632 should_free_pv = FALSE;
7635 self->priv->queue_redraw_entry =
7636 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7637 priv->queue_redraw_entry,
7642 clutter_paint_volume_free (pv);
7644 /* If this is the first redraw queued then we can directly use the
7646 if (!priv->is_dirty)
7647 priv->effect_to_redraw = effect;
7648 /* Otherwise we need to merge it with the existing effect parameter */
7649 else if (effect != NULL)
7651 /* If there's already an effect then we need to use whichever is
7652 later in the chain of actors. Otherwise a full redraw has
7653 already been queued on the actor so we need to ignore the
7655 if (priv->effect_to_redraw != NULL)
7657 if (priv->effects == NULL)
7658 g_warning ("Redraw queued with an effect that is "
7659 "not applied to the actor");
7664 for (l = _clutter_meta_group_peek_metas (priv->effects);
7668 if (l->data == priv->effect_to_redraw ||
7670 priv->effect_to_redraw = l->data;
7677 /* If no effect is specified then we need to redraw the whole
7679 priv->effect_to_redraw = NULL;
7682 priv->is_dirty = TRUE;
7686 * clutter_actor_queue_redraw:
7687 * @self: A #ClutterActor
7689 * Queues up a redraw of an actor and any children. The redraw occurs
7690 * once the main loop becomes idle (after the current batch of events
7691 * has been processed, roughly).
7693 * Applications rarely need to call this, as redraws are handled
7694 * automatically by modification functions.
7696 * This function will not do anything if @self is not visible, or
7697 * if the actor is inside an invisible part of the scenegraph.
7699 * Also be aware that painting is a NOP for actors with an opacity of
7702 * When you are implementing a custom actor you must queue a redraw
7703 * whenever some private state changes that will affect painting or
7704 * picking of your actor.
7707 clutter_actor_queue_redraw (ClutterActor *self)
7709 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7711 _clutter_actor_queue_redraw_full (self,
7713 NULL, /* clip volume */
7718 * _clutter_actor_queue_redraw_with_clip:
7719 * @self: A #ClutterActor
7720 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7721 * this queue redraw.
7722 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7723 * redrawn or %NULL if you are just using a @flag to state your
7726 * Queues up a clipped redraw of an actor and any children. The redraw
7727 * occurs once the main loop becomes idle (after the current batch of
7728 * events has been processed, roughly).
7730 * If no flags are given the clip volume is defined by @volume
7731 * specified in actor coordinates and tells Clutter that only content
7732 * within this volume has been changed so Clutter can optionally
7733 * optimize the redraw.
7735 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7736 * should be %NULL and this tells Clutter to use the actor's current
7737 * allocation as a clip box. This flag can only be used for 2D actors,
7738 * because any actor with depth may be projected outside its
7741 * Applications rarely need to call this, as redraws are handled
7742 * automatically by modification functions.
7744 * This function will not do anything if @self is not visible, or if
7745 * the actor is inside an invisible part of the scenegraph.
7747 * Also be aware that painting is a NOP for actors with an opacity of
7750 * When you are implementing a custom actor you must queue a redraw
7751 * whenever some private state changes that will affect painting or
7752 * picking of your actor.
7755 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7756 ClutterRedrawFlags flags,
7757 ClutterPaintVolume *volume)
7759 _clutter_actor_queue_redraw_full (self,
7761 volume, /* clip volume */
7766 _clutter_actor_queue_only_relayout (ClutterActor *self)
7768 ClutterActorPrivate *priv = self->priv;
7770 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7773 if (priv->needs_width_request &&
7774 priv->needs_height_request &&
7775 priv->needs_allocation)
7776 return; /* save some cpu cycles */
7778 #if CLUTTER_ENABLE_DEBUG
7779 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7781 g_warning ("The actor '%s' is currently inside an allocation "
7782 "cycle; calling clutter_actor_queue_relayout() is "
7784 _clutter_actor_get_debug_name (self));
7786 #endif /* CLUTTER_ENABLE_DEBUG */
7788 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7792 * clutter_actor_queue_redraw_with_clip:
7793 * @self: a #ClutterActor
7794 * @clip: (allow-none): a rectangular clip region, or %NULL
7796 * Queues a redraw on @self limited to a specific, actor-relative
7799 * If @clip is %NULL this function is equivalent to
7800 * clutter_actor_queue_redraw().
7805 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7806 const cairo_rectangle_int_t *clip)
7808 ClutterPaintVolume volume;
7809 ClutterVertex origin;
7811 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7815 clutter_actor_queue_redraw (self);
7819 _clutter_paint_volume_init_static (&volume, self);
7825 clutter_paint_volume_set_origin (&volume, &origin);
7826 clutter_paint_volume_set_width (&volume, clip->width);
7827 clutter_paint_volume_set_height (&volume, clip->height);
7829 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7831 clutter_paint_volume_free (&volume);
7835 * clutter_actor_queue_relayout:
7836 * @self: A #ClutterActor
7838 * Indicates that the actor's size request or other layout-affecting
7839 * properties may have changed. This function is used inside #ClutterActor
7840 * subclass implementations, not by applications directly.
7842 * Queueing a new layout automatically queues a redraw as well.
7847 clutter_actor_queue_relayout (ClutterActor *self)
7849 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7851 _clutter_actor_queue_only_relayout (self);
7852 clutter_actor_queue_redraw (self);
7856 * clutter_actor_get_preferred_size:
7857 * @self: a #ClutterActor
7858 * @min_width_p: (out) (allow-none): return location for the minimum
7860 * @min_height_p: (out) (allow-none): return location for the minimum
7862 * @natural_width_p: (out) (allow-none): return location for the natural
7864 * @natural_height_p: (out) (allow-none): return location for the natural
7867 * Computes the preferred minimum and natural size of an actor, taking into
7868 * account the actor's geometry management (either height-for-width
7869 * or width-for-height).
7871 * The width and height used to compute the preferred height and preferred
7872 * width are the actor's natural ones.
7874 * If you need to control the height for the preferred width, or the width for
7875 * the preferred height, you should use clutter_actor_get_preferred_width()
7876 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7877 * geometry management using the #ClutterActor:request-mode property.
7882 clutter_actor_get_preferred_size (ClutterActor *self,
7883 gfloat *min_width_p,
7884 gfloat *min_height_p,
7885 gfloat *natural_width_p,
7886 gfloat *natural_height_p)
7888 ClutterActorPrivate *priv;
7889 gfloat min_width, min_height;
7890 gfloat natural_width, natural_height;
7892 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7896 min_width = min_height = 0;
7897 natural_width = natural_height = 0;
7899 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7901 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7902 clutter_actor_get_preferred_width (self, -1,
7905 clutter_actor_get_preferred_height (self, natural_width,
7911 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7912 clutter_actor_get_preferred_height (self, -1,
7915 clutter_actor_get_preferred_width (self, natural_height,
7921 *min_width_p = min_width;
7924 *min_height_p = min_height;
7926 if (natural_width_p)
7927 *natural_width_p = natural_width;
7929 if (natural_height_p)
7930 *natural_height_p = natural_height;
7935 * @align: a #ClutterActorAlign
7936 * @direction: a #ClutterTextDirection
7938 * Retrieves the correct alignment depending on the text direction
7940 * Return value: the effective alignment
7942 static ClutterActorAlign
7943 effective_align (ClutterActorAlign align,
7944 ClutterTextDirection direction)
7946 ClutterActorAlign res;
7950 case CLUTTER_ACTOR_ALIGN_START:
7951 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7952 ? CLUTTER_ACTOR_ALIGN_END
7953 : CLUTTER_ACTOR_ALIGN_START;
7956 case CLUTTER_ACTOR_ALIGN_END:
7957 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7958 ? CLUTTER_ACTOR_ALIGN_START
7959 : CLUTTER_ACTOR_ALIGN_END;
7971 * _clutter_actor_get_effective_x_align:
7972 * @self: a #ClutterActor
7974 * Retrieves the effective horizontal alignment, taking into
7975 * consideration the text direction of @self.
7977 * Return value: the effective horizontal alignment
7980 _clutter_actor_get_effective_x_align (ClutterActor *self)
7982 return effective_align (clutter_actor_get_x_align (self),
7983 clutter_actor_get_text_direction (self));
7987 adjust_for_margin (float margin_start,
7989 float *minimum_size,
7990 float *natural_size,
7991 float *allocated_start,
7992 float *allocated_end)
7994 *minimum_size -= (margin_start + margin_end);
7995 *natural_size -= (margin_start + margin_end);
7996 *allocated_start += margin_start;
7997 *allocated_end -= margin_end;
8001 adjust_for_alignment (ClutterActorAlign alignment,
8003 float *allocated_start,
8004 float *allocated_end)
8006 float allocated_size = *allocated_end - *allocated_start;
8010 case CLUTTER_ACTOR_ALIGN_FILL:
8014 case CLUTTER_ACTOR_ALIGN_START:
8016 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
8019 case CLUTTER_ACTOR_ALIGN_END:
8020 if (allocated_size > natural_size)
8022 *allocated_start += (allocated_size - natural_size);
8023 *allocated_end = *allocated_start + natural_size;
8027 case CLUTTER_ACTOR_ALIGN_CENTER:
8028 if (allocated_size > natural_size)
8030 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
8031 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
8038 * clutter_actor_adjust_width:
8039 * @self: a #ClutterActor
8040 * @minimum_width: (inout): the actor's preferred minimum width, which
8041 * will be adjusted depending on the margin
8042 * @natural_width: (inout): the actor's preferred natural width, which
8043 * will be adjusted depending on the margin
8044 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
8045 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
8047 * Adjusts the preferred and allocated position and size of an actor,
8048 * depending on the margin and alignment properties.
8051 clutter_actor_adjust_width (ClutterActor *self,
8052 gfloat *minimum_width,
8053 gfloat *natural_width,
8054 gfloat *adjusted_x1,
8055 gfloat *adjusted_x2)
8057 ClutterTextDirection text_dir;
8058 const ClutterLayoutInfo *info;
8060 info = _clutter_actor_get_layout_info_or_defaults (self);
8061 text_dir = clutter_actor_get_text_direction (self);
8063 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
8065 /* this will tweak natural_width to remove the margin, so that
8066 * adjust_for_alignment() will use the correct size
8068 adjust_for_margin (info->margin.left, info->margin.right,
8069 minimum_width, natural_width,
8070 adjusted_x1, adjusted_x2);
8072 adjust_for_alignment (effective_align (info->x_align, text_dir),
8074 adjusted_x1, adjusted_x2);
8078 * clutter_actor_adjust_height:
8079 * @self: a #ClutterActor
8080 * @minimum_height: (inout): the actor's preferred minimum height, which
8081 * will be adjusted depending on the margin
8082 * @natural_height: (inout): the actor's preferred natural height, which
8083 * will be adjusted depending on the margin
8084 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
8085 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
8087 * Adjusts the preferred and allocated position and size of an actor,
8088 * depending on the margin and alignment properties.
8091 clutter_actor_adjust_height (ClutterActor *self,
8092 gfloat *minimum_height,
8093 gfloat *natural_height,
8094 gfloat *adjusted_y1,
8095 gfloat *adjusted_y2)
8097 const ClutterLayoutInfo *info;
8099 info = _clutter_actor_get_layout_info_or_defaults (self);
8101 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
8103 /* this will tweak natural_height to remove the margin, so that
8104 * adjust_for_alignment() will use the correct size
8106 adjust_for_margin (info->margin.top, info->margin.bottom,
8107 minimum_height, natural_height,
8111 /* we don't use effective_align() here, because text direction
8112 * only affects the horizontal axis
8114 adjust_for_alignment (info->y_align,
8121 /* looks for a cached size request for this for_size. If not
8122 * found, returns the oldest entry so it can be overwritten */
8124 _clutter_actor_get_cached_size_request (gfloat for_size,
8125 SizeRequest *cached_size_requests,
8126 SizeRequest **result)
8130 *result = &cached_size_requests[0];
8132 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
8136 sr = &cached_size_requests[i];
8139 sr->for_size == for_size)
8141 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8145 else if (sr->age < (*result)->age)
8151 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8157 * clutter_actor_get_preferred_width:
8158 * @self: A #ClutterActor
8159 * @for_height: available height when computing the preferred width,
8160 * or a negative value to indicate that no height is defined
8161 * @min_width_p: (out) (allow-none): return location for minimum width,
8163 * @natural_width_p: (out) (allow-none): return location for the natural
8166 * Computes the requested minimum and natural widths for an actor,
8167 * optionally depending on the specified height, or if they are
8168 * already computed, returns the cached values.
8170 * An actor may not get its request - depending on the layout
8171 * manager that's in effect.
8173 * A request should not incorporate the actor's scale or anchor point;
8174 * those transformations do not affect layout, only rendering.
8179 clutter_actor_get_preferred_width (ClutterActor *self,
8181 gfloat *min_width_p,
8182 gfloat *natural_width_p)
8184 float request_min_width, request_natural_width;
8185 SizeRequest *cached_size_request;
8186 const ClutterLayoutInfo *info;
8187 ClutterActorPrivate *priv;
8188 gboolean found_in_cache;
8190 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8194 info = _clutter_actor_get_layout_info_or_defaults (self);
8196 /* we shortcircuit the case of a fixed size set using set_width() */
8197 if (priv->min_width_set && priv->natural_width_set)
8199 if (min_width_p != NULL)
8200 *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8202 if (natural_width_p != NULL)
8203 *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8208 /* the remaining cases are:
8210 * - either min_width or natural_width have been set
8211 * - neither min_width or natural_width have been set
8213 * in both cases, we go through the cache (and through the actor in case
8214 * of cache misses) and determine the authoritative value depending on
8218 if (!priv->needs_width_request)
8221 _clutter_actor_get_cached_size_request (for_height,
8222 priv->width_requests,
8223 &cached_size_request);
8227 /* if the actor needs a width request we use the first slot */
8228 found_in_cache = FALSE;
8229 cached_size_request = &priv->width_requests[0];
8232 if (!found_in_cache)
8234 gfloat minimum_width, natural_width;
8235 ClutterActorClass *klass;
8237 minimum_width = natural_width = 0;
8239 /* adjust for the margin */
8240 if (for_height >= 0)
8242 for_height -= (info->margin.top + info->margin.bottom);
8247 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8249 klass = CLUTTER_ACTOR_GET_CLASS (self);
8250 klass->get_preferred_width (self, for_height,
8254 /* adjust for the margin */
8255 minimum_width += (info->margin.left + info->margin.right);
8256 natural_width += (info->margin.left + info->margin.right);
8258 /* Due to accumulated float errors, it's better not to warn
8259 * on this, but just fix it.
8261 if (natural_width < minimum_width)
8262 natural_width = minimum_width;
8264 cached_size_request->min_size = minimum_width;
8265 cached_size_request->natural_size = natural_width;
8266 cached_size_request->for_size = for_height;
8267 cached_size_request->age = priv->cached_width_age;
8269 priv->cached_width_age += 1;
8270 priv->needs_width_request = FALSE;
8273 if (!priv->min_width_set)
8274 request_min_width = cached_size_request->min_size;
8276 request_min_width = info->margin.left
8277 + info->minimum.width
8278 + info->margin.right;
8280 if (!priv->natural_width_set)
8281 request_natural_width = cached_size_request->natural_size;
8283 request_natural_width = info->margin.left
8284 + info->natural.width
8285 + info->margin.right;
8288 *min_width_p = request_min_width;
8290 if (natural_width_p)
8291 *natural_width_p = request_natural_width;
8295 * clutter_actor_get_preferred_height:
8296 * @self: A #ClutterActor
8297 * @for_width: available width to assume in computing desired height,
8298 * or a negative value to indicate that no width is defined
8299 * @min_height_p: (out) (allow-none): return location for minimum height,
8301 * @natural_height_p: (out) (allow-none): return location for natural
8304 * Computes the requested minimum and natural heights for an actor,
8305 * or if they are already computed, returns the cached values.
8307 * An actor may not get its request - depending on the layout
8308 * manager that's in effect.
8310 * A request should not incorporate the actor's scale or anchor point;
8311 * those transformations do not affect layout, only rendering.
8316 clutter_actor_get_preferred_height (ClutterActor *self,
8318 gfloat *min_height_p,
8319 gfloat *natural_height_p)
8321 float request_min_height, request_natural_height;
8322 SizeRequest *cached_size_request;
8323 const ClutterLayoutInfo *info;
8324 ClutterActorPrivate *priv;
8325 gboolean found_in_cache;
8327 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8331 info = _clutter_actor_get_layout_info_or_defaults (self);
8333 /* we shortcircuit the case of a fixed size set using set_height() */
8334 if (priv->min_height_set && priv->natural_height_set)
8336 if (min_height_p != NULL)
8337 *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8339 if (natural_height_p != NULL)
8340 *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8345 /* the remaining cases are:
8347 * - either min_height or natural_height have been set
8348 * - neither min_height or natural_height have been set
8350 * in both cases, we go through the cache (and through the actor in case
8351 * of cache misses) and determine the authoritative value depending on
8355 if (!priv->needs_height_request)
8358 _clutter_actor_get_cached_size_request (for_width,
8359 priv->height_requests,
8360 &cached_size_request);
8364 found_in_cache = FALSE;
8365 cached_size_request = &priv->height_requests[0];
8368 if (!found_in_cache)
8370 gfloat minimum_height, natural_height;
8371 ClutterActorClass *klass;
8373 minimum_height = natural_height = 0;
8375 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8377 /* adjust for margin */
8380 for_width -= (info->margin.left + info->margin.right);
8385 klass = CLUTTER_ACTOR_GET_CLASS (self);
8386 klass->get_preferred_height (self, for_width,
8390 /* adjust for margin */
8391 minimum_height += (info->margin.top + info->margin.bottom);
8392 natural_height += (info->margin.top + info->margin.bottom);
8394 /* Due to accumulated float errors, it's better not to warn
8395 * on this, but just fix it.
8397 if (natural_height < minimum_height)
8398 natural_height = minimum_height;
8400 cached_size_request->min_size = minimum_height;
8401 cached_size_request->natural_size = natural_height;
8402 cached_size_request->for_size = for_width;
8403 cached_size_request->age = priv->cached_height_age;
8405 priv->cached_height_age += 1;
8406 priv->needs_height_request = FALSE;
8409 if (!priv->min_height_set)
8410 request_min_height = cached_size_request->min_size;
8412 request_min_height = info->margin.top
8413 + info->minimum.height
8414 + info->margin.bottom;
8416 if (!priv->natural_height_set)
8417 request_natural_height = cached_size_request->natural_size;
8419 request_natural_height = info->margin.top
8420 + info->natural.height
8421 + info->margin.bottom;
8424 *min_height_p = request_min_height;
8426 if (natural_height_p)
8427 *natural_height_p = request_natural_height;
8431 * clutter_actor_get_allocation_box:
8432 * @self: A #ClutterActor
8433 * @box: (out): the function fills this in with the actor's allocation
8435 * Gets the layout box an actor has been assigned. The allocation can
8436 * only be assumed valid inside a paint() method; anywhere else, it
8437 * may be out-of-date.
8439 * An allocation does not incorporate the actor's scale or anchor point;
8440 * those transformations do not affect layout, only rendering.
8442 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8443 * of functions inside the implementation of the get_preferred_width()
8444 * or get_preferred_height() virtual functions.</note>
8449 clutter_actor_get_allocation_box (ClutterActor *self,
8450 ClutterActorBox *box)
8452 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8454 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8455 * which limits calling get_allocation to inside paint() basically; or
8456 * we can 2) force a layout, which could be expensive if someone calls
8457 * get_allocation somewhere silly; or we can 3) just return the latest
8458 * value, allowing it to be out-of-date, and assume people know what
8461 * The least-surprises approach that keeps existing code working is
8462 * likely to be 2). People can end up doing some inefficient things,
8463 * though, and in general code that requires 2) is probably broken.
8466 /* this implements 2) */
8467 if (G_UNLIKELY (self->priv->needs_allocation))
8469 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8471 /* do not queue a relayout on an unparented actor */
8473 _clutter_stage_maybe_relayout (stage);
8476 /* commenting out the code above and just keeping this assigment
8479 *box = self->priv->allocation;
8483 * clutter_actor_get_allocation_geometry:
8484 * @self: A #ClutterActor
8485 * @geom: (out): allocation geometry in pixels
8487 * Gets the layout box an actor has been assigned. The allocation can
8488 * only be assumed valid inside a paint() method; anywhere else, it
8489 * may be out-of-date.
8491 * An allocation does not incorporate the actor's scale or anchor point;
8492 * those transformations do not affect layout, only rendering.
8494 * The returned rectangle is in pixels.
8499 clutter_actor_get_allocation_geometry (ClutterActor *self,
8500 ClutterGeometry *geom)
8502 ClutterActorBox box;
8504 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8505 g_return_if_fail (geom != NULL);
8507 clutter_actor_get_allocation_box (self, &box);
8509 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8510 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8511 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8512 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8516 clutter_actor_update_constraints (ClutterActor *self,
8517 ClutterActorBox *allocation)
8519 ClutterActorPrivate *priv = self->priv;
8520 const GList *constraints, *l;
8522 if (priv->constraints == NULL)
8525 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8526 for (l = constraints; l != NULL; l = l->next)
8528 ClutterConstraint *constraint = l->data;
8529 ClutterActorMeta *meta = l->data;
8531 if (clutter_actor_meta_get_enabled (meta))
8533 _clutter_constraint_update_allocation (constraint,
8537 CLUTTER_NOTE (LAYOUT,
8538 "Allocation of '%s' after constraint '%s': "
8539 "{ %.2f, %.2f, %.2f, %.2f }",
8540 _clutter_actor_get_debug_name (self),
8541 _clutter_actor_meta_get_debug_name (meta),
8551 * clutter_actor_adjust_allocation:
8552 * @self: a #ClutterActor
8553 * @allocation: (inout): the allocation to adjust
8555 * Adjusts the passed allocation box taking into account the actor's
8556 * layout information, like alignment, expansion, and margin.
8559 clutter_actor_adjust_allocation (ClutterActor *self,
8560 ClutterActorBox *allocation)
8562 ClutterActorBox adj_allocation;
8563 float alloc_width, alloc_height;
8564 float min_width, min_height;
8565 float nat_width, nat_height;
8566 ClutterRequestMode req_mode;
8568 adj_allocation = *allocation;
8570 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8572 /* we want to hit the cache, so we use the public API */
8573 req_mode = clutter_actor_get_request_mode (self);
8575 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8577 clutter_actor_get_preferred_width (self, -1,
8580 clutter_actor_get_preferred_height (self, alloc_width,
8584 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8586 clutter_actor_get_preferred_height (self, -1,
8589 clutter_actor_get_preferred_height (self, alloc_height,
8594 #ifdef CLUTTER_ENABLE_DEBUG
8595 /* warn about underallocations */
8596 if (_clutter_diagnostic_enabled () &&
8597 (floorf (min_width - alloc_width) > 0 ||
8598 floorf (min_height - alloc_height) > 0))
8600 ClutterActor *parent = clutter_actor_get_parent (self);
8602 /* the only actors that are allowed to be underallocated are the Stage,
8603 * as it doesn't have an implicit size, and Actors that specifically
8604 * told us that they want to opt-out from layout control mechanisms
8605 * through the NO_LAYOUT escape hatch.
8607 if (parent != NULL &&
8608 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8610 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8611 "of %.2f x %.2f from its parent actor '%s', but its "
8612 "requested minimum size is of %.2f x %.2f",
8613 _clutter_actor_get_debug_name (self),
8614 alloc_width, alloc_height,
8615 _clutter_actor_get_debug_name (parent),
8616 min_width, min_height);
8621 clutter_actor_adjust_width (self,
8625 &adj_allocation.x2);
8627 clutter_actor_adjust_height (self,
8631 &adj_allocation.y2);
8633 /* we maintain the invariant that an allocation cannot be adjusted
8634 * to be outside the parent-given box
8636 if (adj_allocation.x1 < allocation->x1 ||
8637 adj_allocation.y1 < allocation->y1 ||
8638 adj_allocation.x2 > allocation->x2 ||
8639 adj_allocation.y2 > allocation->y2)
8641 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8642 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8643 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8644 _clutter_actor_get_debug_name (self),
8645 adj_allocation.x1, adj_allocation.y1,
8646 adj_allocation.x2 - adj_allocation.x1,
8647 adj_allocation.y2 - adj_allocation.y1,
8648 allocation->x1, allocation->y1,
8649 allocation->x2 - allocation->x1,
8650 allocation->y2 - allocation->y1);
8654 *allocation = adj_allocation;
8658 clutter_actor_allocate_internal (ClutterActor *self,
8659 const ClutterActorBox *allocation,
8660 ClutterAllocationFlags flags)
8662 ClutterActorClass *klass;
8664 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8666 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8667 _clutter_actor_get_debug_name (self));
8669 klass = CLUTTER_ACTOR_GET_CLASS (self);
8670 klass->allocate (self, allocation, flags);
8672 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8674 clutter_actor_queue_redraw (self);
8678 * clutter_actor_allocate:
8679 * @self: A #ClutterActor
8680 * @box: new allocation of the actor, in parent-relative coordinates
8681 * @flags: flags that control the allocation
8683 * Called by the parent of an actor to assign the actor its size.
8684 * Should never be called by applications (except when implementing
8685 * a container or layout manager).
8687 * Actors can know from their allocation box whether they have moved
8688 * with respect to their parent actor. The @flags parameter describes
8689 * additional information about the allocation, for instance whether
8690 * the parent has moved with respect to the stage, for example because
8691 * a grandparent's origin has moved.
8696 clutter_actor_allocate (ClutterActor *self,
8697 const ClutterActorBox *box,
8698 ClutterAllocationFlags flags)
8700 ClutterActorBox old_allocation, real_allocation;
8701 gboolean origin_changed, child_moved, size_changed;
8702 gboolean stage_allocation_changed;
8703 ClutterActorPrivate *priv;
8705 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8706 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8708 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8709 "which isn't a descendent of the stage!\n",
8710 self, _clutter_actor_get_debug_name (self));
8716 old_allocation = priv->allocation;
8717 real_allocation = *box;
8719 /* constraints are allowed to modify the allocation only here; we do
8720 * this prior to all the other checks so that we can bail out if the
8721 * allocation did not change
8723 clutter_actor_update_constraints (self, &real_allocation);
8725 /* adjust the allocation depending on the align/margin properties */
8726 clutter_actor_adjust_allocation (self, &real_allocation);
8728 if (real_allocation.x2 < real_allocation.x1 ||
8729 real_allocation.y2 < real_allocation.y1)
8731 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8732 _clutter_actor_get_debug_name (self),
8733 real_allocation.x2 - real_allocation.x1,
8734 real_allocation.y2 - real_allocation.y1);
8737 /* we allow 0-sized actors, but not negative-sized ones */
8738 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8739 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8741 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8743 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8744 real_allocation.y1 != old_allocation.y1);
8746 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8747 real_allocation.y2 != old_allocation.y2);
8749 if (origin_changed || child_moved || size_changed)
8750 stage_allocation_changed = TRUE;
8752 stage_allocation_changed = FALSE;
8754 /* If we get an allocation "out of the blue"
8755 * (we did not queue relayout), then we want to
8756 * ignore it. But if we have needs_allocation set,
8757 * we want to guarantee that allocate() virtual
8758 * method is always called, i.e. that queue_relayout()
8759 * always results in an allocate() invocation on
8762 * The optimization here is to avoid re-allocating
8763 * actors that did not queue relayout and were
8766 if (!priv->needs_allocation && !stage_allocation_changed)
8768 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8772 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8773 * clutter_actor_allocate(), it indicates whether the parent has its
8774 * absolute origin moved; when passed in to ClutterActor::allocate()
8775 * virtual method though, it indicates whether the child has its
8776 * absolute origin moved. So we set it when child_moved is TRUE
8779 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8781 /* store the flags here, so that they can be propagated by the
8784 self->priv->allocation_flags = flags;
8786 if (_clutter_actor_get_transition (self, obj_props[PROP_ALLOCATION]) == NULL)
8788 _clutter_actor_create_transition (self, obj_props[PROP_ALLOCATION],
8793 _clutter_actor_update_transition (self, obj_props[PROP_ALLOCATION],
8798 * clutter_actor_set_allocation:
8799 * @self: a #ClutterActor
8800 * @box: a #ClutterActorBox
8801 * @flags: allocation flags
8803 * Stores the allocation of @self as defined by @box.
8805 * This function can only be called from within the implementation of
8806 * the #ClutterActorClass.allocate() virtual function.
8808 * The allocation should have been adjusted to take into account constraints,
8809 * alignment, and margin properties. If you are implementing a #ClutterActor
8810 * subclass that provides its own layout management policy for its children
8811 * instead of using a #ClutterLayoutManager delegate, you should not call
8812 * this function on the children of @self; instead, you should call
8813 * clutter_actor_allocate(), which will adjust the allocation box for
8816 * This function should only be used by subclasses of #ClutterActor
8817 * that wish to store their allocation but cannot chain up to the
8818 * parent's implementation; the default implementation of the
8819 * #ClutterActorClass.allocate() virtual function will call this
8822 * It is important to note that, while chaining up was the recommended
8823 * behaviour for #ClutterActor subclasses prior to the introduction of
8824 * this function, it is recommended to call clutter_actor_set_allocation()
8827 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8828 * to handle the allocation of its children, this function will call
8829 * the clutter_layout_manager_allocate() function only if the
8830 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8831 * expected that the subclass will call clutter_layout_manager_allocate()
8832 * by itself. For instance, the following code:
8836 * my_actor_allocate (ClutterActor *actor,
8837 * const ClutterActorBox *allocation,
8838 * ClutterAllocationFlags flags)
8840 * ClutterActorBox new_alloc;
8841 * ClutterAllocationFlags new_flags;
8843 * adjust_allocation (allocation, &new_alloc);
8845 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8847 * /* this will use the layout manager set on the actor */
8848 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8852 * is equivalent to this:
8856 * my_actor_allocate (ClutterActor *actor,
8857 * const ClutterActorBox *allocation,
8858 * ClutterAllocationFlags flags)
8860 * ClutterLayoutManager *layout;
8861 * ClutterActorBox new_alloc;
8863 * adjust_allocation (allocation, &new_alloc);
8865 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8867 * layout = clutter_actor_get_layout_manager (actor);
8868 * clutter_layout_manager_allocate (layout,
8869 * CLUTTER_CONTAINER (actor),
8878 clutter_actor_set_allocation (ClutterActor *self,
8879 const ClutterActorBox *box,
8880 ClutterAllocationFlags flags)
8882 ClutterActorPrivate *priv;
8885 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8886 g_return_if_fail (box != NULL);
8888 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8890 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8891 "can only be called from within the implementation of "
8892 "the ClutterActor::allocate() virtual function.");
8898 g_object_freeze_notify (G_OBJECT (self));
8900 changed = clutter_actor_set_allocation_internal (self, box, flags);
8902 /* we allocate our children before we notify changes in our geometry,
8903 * so that people connecting to properties will be able to get valid
8904 * data out of the sub-tree of the scene graph that has this actor at
8907 clutter_actor_maybe_layout_children (self, box, flags);
8911 ClutterActorBox signal_box = priv->allocation;
8912 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8914 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8919 g_object_thaw_notify (G_OBJECT (self));
8923 * clutter_actor_set_geometry:
8924 * @self: A #ClutterActor
8925 * @geometry: A #ClutterGeometry
8927 * Sets the actor's fixed position and forces its minimum and natural
8928 * size, in pixels. This means the untransformed actor will have the
8929 * given geometry. This is the same as calling clutter_actor_set_position()
8930 * and clutter_actor_set_size().
8932 * Deprecated: 1.10: Use clutter_actor_set_position() and
8933 * clutter_actor_set_size() instead.
8936 clutter_actor_set_geometry (ClutterActor *self,
8937 const ClutterGeometry *geometry)
8939 g_object_freeze_notify (G_OBJECT (self));
8941 clutter_actor_set_position (self, geometry->x, geometry->y);
8942 clutter_actor_set_size (self, geometry->width, geometry->height);
8944 g_object_thaw_notify (G_OBJECT (self));
8948 * clutter_actor_get_geometry:
8949 * @self: A #ClutterActor
8950 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8952 * Gets the size and position of an actor relative to its parent
8953 * actor. This is the same as calling clutter_actor_get_position() and
8954 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8955 * requested size and position if the actor's allocation is invalid.
8957 * Deprecated: 1.10: Use clutter_actor_get_position() and
8958 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8962 clutter_actor_get_geometry (ClutterActor *self,
8963 ClutterGeometry *geometry)
8965 gfloat x, y, width, height;
8967 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8968 g_return_if_fail (geometry != NULL);
8970 clutter_actor_get_position (self, &x, &y);
8971 clutter_actor_get_size (self, &width, &height);
8973 geometry->x = (int) x;
8974 geometry->y = (int) y;
8975 geometry->width = (int) width;
8976 geometry->height = (int) height;
8980 * clutter_actor_set_position:
8981 * @self: A #ClutterActor
8982 * @x: New left position of actor in pixels.
8983 * @y: New top position of actor in pixels.
8985 * Sets the actor's fixed position in pixels relative to any parent
8988 * If a layout manager is in use, this position will override the
8989 * layout manager and force a fixed position.
8992 clutter_actor_set_position (ClutterActor *self,
8996 ClutterPoint new_position;
8998 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9000 clutter_point_init (&new_position, x, y);
9002 if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
9004 ClutterPoint cur_position;
9006 cur_position.x = clutter_actor_get_x (self);
9007 cur_position.y = clutter_actor_get_y (self);
9009 _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
9014 _clutter_actor_update_transition (self,
9015 obj_props[PROP_POSITION],
9018 clutter_actor_queue_relayout (self);
9022 * clutter_actor_get_fixed_position_set:
9023 * @self: A #ClutterActor
9025 * Checks whether an actor has a fixed position set (and will thus be
9026 * unaffected by any layout manager).
9028 * Return value: %TRUE if the fixed position is set on the actor
9033 clutter_actor_get_fixed_position_set (ClutterActor *self)
9035 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9037 return self->priv->position_set;
9041 * clutter_actor_set_fixed_position_set:
9042 * @self: A #ClutterActor
9043 * @is_set: whether to use fixed position
9045 * Sets whether an actor has a fixed position set (and will thus be
9046 * unaffected by any layout manager).
9051 clutter_actor_set_fixed_position_set (ClutterActor *self,
9054 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9056 if (self->priv->position_set == (is_set != FALSE))
9059 self->priv->position_set = is_set != FALSE;
9060 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9062 clutter_actor_queue_relayout (self);
9066 * clutter_actor_move_by:
9067 * @self: A #ClutterActor
9068 * @dx: Distance to move Actor on X axis.
9069 * @dy: Distance to move Actor on Y axis.
9071 * Moves an actor by the specified distance relative to its current
9072 * position in pixels.
9074 * This function modifies the fixed position of an actor and thus removes
9075 * it from any layout management. Another way to move an actor is with an
9076 * anchor point, see clutter_actor_set_anchor_point().
9081 clutter_actor_move_by (ClutterActor *self,
9085 const ClutterLayoutInfo *info;
9088 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9090 info = _clutter_actor_get_layout_info_or_defaults (self);
9091 x = info->fixed_pos.x;
9092 y = info->fixed_pos.y;
9094 clutter_actor_set_position (self, x + dx, y + dy);
9098 clutter_actor_set_min_width (ClutterActor *self,
9101 ClutterActorPrivate *priv = self->priv;
9102 ClutterActorBox old = { 0, };
9103 ClutterLayoutInfo *info;
9105 /* if we are setting the size on a top-level actor and the
9106 * backend only supports static top-levels (e.g. framebuffers)
9107 * then we ignore the passed value and we override it with
9108 * the stage implementation's preferred size.
9110 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9111 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9114 info = _clutter_actor_get_layout_info (self);
9116 if (priv->min_width_set && min_width == info->minimum.width)
9119 g_object_freeze_notify (G_OBJECT (self));
9121 clutter_actor_store_old_geometry (self, &old);
9123 info->minimum.width = min_width;
9124 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9125 clutter_actor_set_min_width_set (self, TRUE);
9127 clutter_actor_notify_if_geometry_changed (self, &old);
9129 g_object_thaw_notify (G_OBJECT (self));
9131 clutter_actor_queue_relayout (self);
9135 clutter_actor_set_min_height (ClutterActor *self,
9139 ClutterActorPrivate *priv = self->priv;
9140 ClutterActorBox old = { 0, };
9141 ClutterLayoutInfo *info;
9143 /* if we are setting the size on a top-level actor and the
9144 * backend only supports static top-levels (e.g. framebuffers)
9145 * then we ignore the passed value and we override it with
9146 * the stage implementation's preferred size.
9148 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9149 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9152 info = _clutter_actor_get_layout_info (self);
9154 if (priv->min_height_set && min_height == info->minimum.height)
9157 g_object_freeze_notify (G_OBJECT (self));
9159 clutter_actor_store_old_geometry (self, &old);
9161 info->minimum.height = min_height;
9162 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9163 clutter_actor_set_min_height_set (self, TRUE);
9165 clutter_actor_notify_if_geometry_changed (self, &old);
9167 g_object_thaw_notify (G_OBJECT (self));
9169 clutter_actor_queue_relayout (self);
9173 clutter_actor_set_natural_width (ClutterActor *self,
9174 gfloat natural_width)
9176 ClutterActorPrivate *priv = self->priv;
9177 ClutterActorBox old = { 0, };
9178 ClutterLayoutInfo *info;
9180 /* if we are setting the size on a top-level actor and the
9181 * backend only supports static top-levels (e.g. framebuffers)
9182 * then we ignore the passed value and we override it with
9183 * the stage implementation's preferred size.
9185 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9186 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9189 info = _clutter_actor_get_layout_info (self);
9191 if (priv->natural_width_set && natural_width == info->natural.width)
9194 g_object_freeze_notify (G_OBJECT (self));
9196 clutter_actor_store_old_geometry (self, &old);
9198 info->natural.width = natural_width;
9199 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9200 clutter_actor_set_natural_width_set (self, TRUE);
9202 clutter_actor_notify_if_geometry_changed (self, &old);
9204 g_object_thaw_notify (G_OBJECT (self));
9206 clutter_actor_queue_relayout (self);
9210 clutter_actor_set_natural_height (ClutterActor *self,
9211 gfloat natural_height)
9213 ClutterActorPrivate *priv = self->priv;
9214 ClutterActorBox old = { 0, };
9215 ClutterLayoutInfo *info;
9217 /* if we are setting the size on a top-level actor and the
9218 * backend only supports static top-levels (e.g. framebuffers)
9219 * then we ignore the passed value and we override it with
9220 * the stage implementation's preferred size.
9222 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9223 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9226 info = _clutter_actor_get_layout_info (self);
9228 if (priv->natural_height_set && natural_height == info->natural.height)
9231 g_object_freeze_notify (G_OBJECT (self));
9233 clutter_actor_store_old_geometry (self, &old);
9235 info->natural.height = natural_height;
9236 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9237 clutter_actor_set_natural_height_set (self, TRUE);
9239 clutter_actor_notify_if_geometry_changed (self, &old);
9241 g_object_thaw_notify (G_OBJECT (self));
9243 clutter_actor_queue_relayout (self);
9247 clutter_actor_set_min_width_set (ClutterActor *self,
9248 gboolean use_min_width)
9250 ClutterActorPrivate *priv = self->priv;
9251 ClutterActorBox old = { 0, };
9253 if (priv->min_width_set == (use_min_width != FALSE))
9256 clutter_actor_store_old_geometry (self, &old);
9258 priv->min_width_set = use_min_width != FALSE;
9259 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9261 clutter_actor_notify_if_geometry_changed (self, &old);
9263 clutter_actor_queue_relayout (self);
9267 clutter_actor_set_min_height_set (ClutterActor *self,
9268 gboolean use_min_height)
9270 ClutterActorPrivate *priv = self->priv;
9271 ClutterActorBox old = { 0, };
9273 if (priv->min_height_set == (use_min_height != FALSE))
9276 clutter_actor_store_old_geometry (self, &old);
9278 priv->min_height_set = use_min_height != FALSE;
9279 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9281 clutter_actor_notify_if_geometry_changed (self, &old);
9283 clutter_actor_queue_relayout (self);
9287 clutter_actor_set_natural_width_set (ClutterActor *self,
9288 gboolean use_natural_width)
9290 ClutterActorPrivate *priv = self->priv;
9291 ClutterActorBox old = { 0, };
9293 if (priv->natural_width_set == (use_natural_width != FALSE))
9296 clutter_actor_store_old_geometry (self, &old);
9298 priv->natural_width_set = use_natural_width != FALSE;
9299 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9301 clutter_actor_notify_if_geometry_changed (self, &old);
9303 clutter_actor_queue_relayout (self);
9307 clutter_actor_set_natural_height_set (ClutterActor *self,
9308 gboolean use_natural_height)
9310 ClutterActorPrivate *priv = self->priv;
9311 ClutterActorBox old = { 0, };
9313 if (priv->natural_height_set == (use_natural_height != FALSE))
9316 clutter_actor_store_old_geometry (self, &old);
9318 priv->natural_height_set = use_natural_height != FALSE;
9319 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9321 clutter_actor_notify_if_geometry_changed (self, &old);
9323 clutter_actor_queue_relayout (self);
9327 * clutter_actor_set_request_mode:
9328 * @self: a #ClutterActor
9329 * @mode: the request mode
9331 * Sets the geometry request mode of @self.
9333 * The @mode determines the order for invoking
9334 * clutter_actor_get_preferred_width() and
9335 * clutter_actor_get_preferred_height()
9340 clutter_actor_set_request_mode (ClutterActor *self,
9341 ClutterRequestMode mode)
9343 ClutterActorPrivate *priv;
9345 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9349 if (priv->request_mode == mode)
9352 priv->request_mode = mode;
9354 priv->needs_width_request = TRUE;
9355 priv->needs_height_request = TRUE;
9357 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9359 clutter_actor_queue_relayout (self);
9363 * clutter_actor_get_request_mode:
9364 * @self: a #ClutterActor
9366 * Retrieves the geometry request mode of @self
9368 * Return value: the request mode for the actor
9373 clutter_actor_get_request_mode (ClutterActor *self)
9375 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9376 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9378 return self->priv->request_mode;
9381 /* variant of set_width() without checks and without notification
9382 * freeze+thaw, for internal usage only
9385 clutter_actor_set_width_internal (ClutterActor *self,
9390 /* the Stage will use the :min-width to control the minimum
9391 * width to be resized to, so we should not be setting it
9392 * along with the :natural-width
9394 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9395 clutter_actor_set_min_width (self, width);
9397 clutter_actor_set_natural_width (self, width);
9401 /* we only unset the :natural-width for the Stage */
9402 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9403 clutter_actor_set_min_width_set (self, FALSE);
9405 clutter_actor_set_natural_width_set (self, FALSE);
9409 /* variant of set_height() without checks and without notification
9410 * freeze+thaw, for internal usage only
9413 clutter_actor_set_height_internal (ClutterActor *self,
9418 /* see the comment above in set_width_internal() */
9419 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9420 clutter_actor_set_min_height (self, height);
9422 clutter_actor_set_natural_height (self, height);
9426 /* see the comment above in set_width_internal() */
9427 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9428 clutter_actor_set_min_height_set (self, FALSE);
9430 clutter_actor_set_natural_height_set (self, FALSE);
9435 clutter_actor_set_size_internal (ClutterActor *self,
9436 const ClutterSize *size)
9440 clutter_actor_set_width_internal (self, size->width);
9441 clutter_actor_set_height_internal (self, size->height);
9445 clutter_actor_set_width_internal (self, -1);
9446 clutter_actor_set_height_internal (self, -1);
9451 * clutter_actor_set_size:
9452 * @self: A #ClutterActor
9453 * @width: New width of actor in pixels, or -1
9454 * @height: New height of actor in pixels, or -1
9456 * Sets the actor's size request in pixels. This overrides any
9457 * "normal" size request the actor would have. For example
9458 * a text actor might normally request the size of the text;
9459 * this function would force a specific size instead.
9461 * If @width and/or @height are -1 the actor will use its
9462 * "normal" size request instead of overriding it, i.e.
9463 * you can "unset" the size with -1.
9465 * This function sets or unsets both the minimum and natural size.
9468 clutter_actor_set_size (ClutterActor *self,
9472 ClutterSize new_size;
9474 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9476 clutter_size_init (&new_size, width, height);
9478 if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9480 /* minor optimization: if we don't have a duration then we can
9481 * skip the get_size() below, to avoid the chance of going through
9482 * get_preferred_width() and get_preferred_height() just to jump to
9483 * a new desired size
9485 if (clutter_actor_get_easing_duration (self) == 0)
9487 g_object_freeze_notify (G_OBJECT (self));
9489 clutter_actor_set_size_internal (self, &new_size);
9491 g_object_thaw_notify (G_OBJECT (self));
9497 ClutterSize cur_size;
9499 clutter_size_init (&cur_size,
9500 clutter_actor_get_width (self),
9501 clutter_actor_get_height (self));
9503 _clutter_actor_create_transition (self,
9504 obj_props[PROP_SIZE],
9510 _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9512 clutter_actor_queue_relayout (self);
9516 * clutter_actor_get_size:
9517 * @self: A #ClutterActor
9518 * @width: (out) (allow-none): return location for the width, or %NULL.
9519 * @height: (out) (allow-none): return location for the height, or %NULL.
9521 * This function tries to "do what you mean" and return
9522 * the size an actor will have. If the actor has a valid
9523 * allocation, the allocation will be returned; otherwise,
9524 * the actors natural size request will be returned.
9526 * If you care whether you get the request vs. the allocation, you
9527 * should probably call a different function like
9528 * clutter_actor_get_allocation_box() or
9529 * clutter_actor_get_preferred_width().
9534 clutter_actor_get_size (ClutterActor *self,
9538 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9541 *width = clutter_actor_get_width (self);
9544 *height = clutter_actor_get_height (self);
9548 * clutter_actor_get_position:
9549 * @self: a #ClutterActor
9550 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9551 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9553 * This function tries to "do what you mean" and tell you where the
9554 * actor is, prior to any transformations. Retrieves the fixed
9555 * position of an actor in pixels, if one has been set; otherwise, if
9556 * the allocation is valid, returns the actor's allocated position;
9557 * otherwise, returns 0,0.
9559 * The returned position is in pixels.
9564 clutter_actor_get_position (ClutterActor *self,
9568 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9571 *x = clutter_actor_get_x (self);
9574 *y = clutter_actor_get_y (self);
9578 * clutter_actor_get_transformed_position:
9579 * @self: A #ClutterActor
9580 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9581 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9583 * Gets the absolute position of an actor, in pixels relative to the stage.
9588 clutter_actor_get_transformed_position (ClutterActor *self,
9595 v1.x = v1.y = v1.z = 0;
9596 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9606 * clutter_actor_get_transformed_size:
9607 * @self: A #ClutterActor
9608 * @width: (out) (allow-none): return location for the width, or %NULL
9609 * @height: (out) (allow-none): return location for the height, or %NULL
9611 * Gets the absolute size of an actor in pixels, taking into account the
9614 * If the actor has a valid allocation, the allocated size will be used.
9615 * If the actor has not a valid allocation then the preferred size will
9616 * be transformed and returned.
9618 * If you want the transformed allocation, see
9619 * clutter_actor_get_abs_allocation_vertices() instead.
9621 * <note>When the actor (or one of its ancestors) is rotated around the
9622 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9623 * as a generic quadrangle; in that case this function returns the size
9624 * of the smallest rectangle that encapsulates the entire quad. Please
9625 * note that in this case no assumptions can be made about the relative
9626 * position of this envelope to the absolute position of the actor, as
9627 * returned by clutter_actor_get_transformed_position(); if you need this
9628 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9629 * to get the coords of the actual quadrangle.</note>
9634 clutter_actor_get_transformed_size (ClutterActor *self,
9638 ClutterActorPrivate *priv;
9640 gfloat x_min, x_max, y_min, y_max;
9643 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9647 /* if the actor hasn't been allocated yet, get the preferred
9648 * size and transform that
9650 if (priv->needs_allocation)
9652 gfloat natural_width, natural_height;
9653 ClutterActorBox box;
9655 /* Make a fake allocation to transform.
9657 * NB: _clutter_actor_transform_and_project_box expects a box in
9658 * the actor's coordinate space... */
9663 natural_width = natural_height = 0;
9664 clutter_actor_get_preferred_size (self, NULL, NULL,
9668 box.x2 = natural_width;
9669 box.y2 = natural_height;
9671 _clutter_actor_transform_and_project_box (self, &box, v);
9674 clutter_actor_get_abs_allocation_vertices (self, v);
9676 x_min = x_max = v[0].x;
9677 y_min = y_max = v[0].y;
9679 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9695 *width = x_max - x_min;
9698 *height = y_max - y_min;
9702 * clutter_actor_get_width:
9703 * @self: A #ClutterActor
9705 * Retrieves the width of a #ClutterActor.
9707 * If the actor has a valid allocation, this function will return the
9708 * width of the allocated area given to the actor.
9710 * If the actor does not have a valid allocation, this function will
9711 * return the actor's natural width, that is the preferred width of
9714 * If you care whether you get the preferred width or the width that
9715 * has been assigned to the actor, you should probably call a different
9716 * function like clutter_actor_get_allocation_box() to retrieve the
9717 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9720 * If an actor has a fixed width, for instance a width that has been
9721 * assigned using clutter_actor_set_width(), the width returned will
9722 * be the same value.
9724 * Return value: the width of the actor, in pixels
9727 clutter_actor_get_width (ClutterActor *self)
9729 ClutterActorPrivate *priv;
9731 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9735 if (priv->needs_allocation)
9737 gfloat natural_width = 0;
9739 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9740 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9743 gfloat natural_height = 0;
9745 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9746 clutter_actor_get_preferred_width (self, natural_height,
9751 return natural_width;
9754 return priv->allocation.x2 - priv->allocation.x1;
9758 * clutter_actor_get_height:
9759 * @self: A #ClutterActor
9761 * Retrieves the height of a #ClutterActor.
9763 * If the actor has a valid allocation, this function will return the
9764 * height of the allocated area given to the actor.
9766 * If the actor does not have a valid allocation, this function will
9767 * return the actor's natural height, that is the preferred height of
9770 * If you care whether you get the preferred height or the height that
9771 * has been assigned to the actor, you should probably call a different
9772 * function like clutter_actor_get_allocation_box() to retrieve the
9773 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9776 * If an actor has a fixed height, for instance a height that has been
9777 * assigned using clutter_actor_set_height(), the height returned will
9778 * be the same value.
9780 * Return value: the height of the actor, in pixels
9783 clutter_actor_get_height (ClutterActor *self)
9785 ClutterActorPrivate *priv;
9787 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9791 if (priv->needs_allocation)
9793 gfloat natural_height = 0;
9795 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9797 gfloat natural_width = 0;
9799 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9800 clutter_actor_get_preferred_height (self, natural_width,
9801 NULL, &natural_height);
9804 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9806 return natural_height;
9809 return priv->allocation.y2 - priv->allocation.y1;
9813 * clutter_actor_set_width:
9814 * @self: A #ClutterActor
9815 * @width: Requested new width for the actor, in pixels, or -1
9817 * Forces a width on an actor, causing the actor's preferred width
9818 * and height (if any) to be ignored.
9820 * If @width is -1 the actor will use its preferred width request
9821 * instead of overriding it, i.e. you can "unset" the width with -1.
9823 * This function sets both the minimum and natural size of the actor.
9828 clutter_actor_set_width (ClutterActor *self,
9831 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9833 if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9837 /* minor optimization: if we don't have a duration
9838 * then we can skip the get_width() below, to avoid
9839 * the chance of going through get_preferred_width()
9840 * just to jump to a new desired width.
9842 if (clutter_actor_get_easing_duration (self) == 0)
9844 g_object_freeze_notify (G_OBJECT (self));
9846 clutter_actor_set_width_internal (self, width);
9848 g_object_thaw_notify (G_OBJECT (self));
9853 cur_size = clutter_actor_get_width (self);
9855 _clutter_actor_create_transition (self,
9856 obj_props[PROP_WIDTH],
9861 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9865 * clutter_actor_set_height:
9866 * @self: A #ClutterActor
9867 * @height: Requested new height for the actor, in pixels, or -1
9869 * Forces a height on an actor, causing the actor's preferred width
9870 * and height (if any) to be ignored.
9872 * If @height is -1 the actor will use its preferred height instead of
9873 * overriding it, i.e. you can "unset" the height with -1.
9875 * This function sets both the minimum and natural size of the actor.
9880 clutter_actor_set_height (ClutterActor *self,
9883 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9885 if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9889 /* see the comment in clutter_actor_set_width() above */
9890 if (clutter_actor_get_easing_duration (self) == 0)
9892 g_object_freeze_notify (G_OBJECT (self));
9894 clutter_actor_set_height_internal (self, height);
9896 g_object_thaw_notify (G_OBJECT (self));
9901 cur_size = clutter_actor_get_height (self);
9903 _clutter_actor_create_transition (self,
9904 obj_props[PROP_HEIGHT],
9909 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9913 clutter_actor_set_x_internal (ClutterActor *self,
9916 ClutterActorPrivate *priv = self->priv;
9917 ClutterLayoutInfo *linfo;
9918 ClutterActorBox old = { 0, };
9920 linfo = _clutter_actor_get_layout_info (self);
9922 if (priv->position_set && linfo->fixed_pos.x == x)
9925 clutter_actor_store_old_geometry (self, &old);
9927 linfo->fixed_pos.x = x;
9928 clutter_actor_set_fixed_position_set (self, TRUE);
9930 clutter_actor_notify_if_geometry_changed (self, &old);
9932 clutter_actor_queue_relayout (self);
9936 clutter_actor_set_y_internal (ClutterActor *self,
9939 ClutterActorPrivate *priv = self->priv;
9940 ClutterLayoutInfo *linfo;
9941 ClutterActorBox old = { 0, };
9943 linfo = _clutter_actor_get_layout_info (self);
9945 if (priv->position_set && linfo->fixed_pos.y == y)
9948 clutter_actor_store_old_geometry (self, &old);
9950 linfo->fixed_pos.y = y;
9951 clutter_actor_set_fixed_position_set (self, TRUE);
9953 clutter_actor_notify_if_geometry_changed (self, &old);
9955 clutter_actor_queue_relayout (self);
9959 clutter_actor_set_position_internal (ClutterActor *self,
9960 const ClutterPoint *position)
9962 ClutterActorPrivate *priv = self->priv;
9963 ClutterLayoutInfo *linfo;
9964 ClutterActorBox old = { 0, };
9966 linfo = _clutter_actor_get_layout_info (self);
9968 if (priv->position_set &&
9969 clutter_point_equals (position, &linfo->fixed_pos))
9972 clutter_actor_store_old_geometry (self, &old);
9974 if (position != NULL)
9976 linfo->fixed_pos = *position;
9977 clutter_actor_set_fixed_position_set (self, TRUE);
9980 clutter_actor_set_fixed_position_set (self, FALSE);
9982 clutter_actor_notify_if_geometry_changed (self, &old);
9984 clutter_actor_queue_relayout (self);
9988 * clutter_actor_set_x:
9989 * @self: a #ClutterActor
9990 * @x: the actor's position on the X axis
9992 * Sets the actor's X coordinate, relative to its parent, in pixels.
9994 * Overrides any layout manager and forces a fixed position for
9997 * The #ClutterActor:x property is animatable.
10002 clutter_actor_set_x (ClutterActor *self,
10005 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10007 if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
10009 float cur_position = clutter_actor_get_x (self);
10011 _clutter_actor_create_transition (self, obj_props[PROP_X],
10016 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
10020 * clutter_actor_set_y:
10021 * @self: a #ClutterActor
10022 * @y: the actor's position on the Y axis
10024 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
10026 * Overrides any layout manager and forces a fixed position for
10029 * The #ClutterActor:y property is animatable.
10034 clutter_actor_set_y (ClutterActor *self,
10037 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10039 if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
10041 float cur_position = clutter_actor_get_y (self);
10043 _clutter_actor_create_transition (self, obj_props[PROP_Y],
10048 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
10052 * clutter_actor_get_x:
10053 * @self: A #ClutterActor
10055 * Retrieves the X coordinate of a #ClutterActor.
10057 * This function tries to "do what you mean", by returning the
10058 * correct value depending on the actor's state.
10060 * If the actor has a valid allocation, this function will return
10061 * the X coordinate of the origin of the allocation box.
10063 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10064 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10065 * function will return that coordinate.
10067 * If both the allocation and a fixed position are missing, this function
10070 * Return value: the X coordinate, in pixels, ignoring any
10071 * transformation (i.e. scaling, rotation)
10074 clutter_actor_get_x (ClutterActor *self)
10076 ClutterActorPrivate *priv;
10078 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10082 if (priv->needs_allocation)
10084 if (priv->position_set)
10086 const ClutterLayoutInfo *info;
10088 info = _clutter_actor_get_layout_info_or_defaults (self);
10090 return info->fixed_pos.x;
10096 return priv->allocation.x1;
10100 * clutter_actor_get_y:
10101 * @self: A #ClutterActor
10103 * Retrieves the Y coordinate of a #ClutterActor.
10105 * This function tries to "do what you mean", by returning the
10106 * correct value depending on the actor's state.
10108 * If the actor has a valid allocation, this function will return
10109 * the Y coordinate of the origin of the allocation box.
10111 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10112 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10113 * function will return that coordinate.
10115 * If both the allocation and a fixed position are missing, this function
10118 * Return value: the Y coordinate, in pixels, ignoring any
10119 * transformation (i.e. scaling, rotation)
10122 clutter_actor_get_y (ClutterActor *self)
10124 ClutterActorPrivate *priv;
10126 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10130 if (priv->needs_allocation)
10132 if (priv->position_set)
10134 const ClutterLayoutInfo *info;
10136 info = _clutter_actor_get_layout_info_or_defaults (self);
10138 return info->fixed_pos.y;
10144 return priv->allocation.y1;
10148 * clutter_actor_set_scale:
10149 * @self: A #ClutterActor
10150 * @scale_x: double factor to scale actor by horizontally.
10151 * @scale_y: double factor to scale actor by vertically.
10153 * Scales an actor with the given factors. The scaling is relative to
10154 * the scale center and the anchor point. The scale center is
10155 * unchanged by this function and defaults to 0,0.
10157 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10163 clutter_actor_set_scale (ClutterActor *self,
10167 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10169 g_object_freeze_notify (G_OBJECT (self));
10171 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10172 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10174 g_object_thaw_notify (G_OBJECT (self));
10178 * clutter_actor_set_scale_full:
10179 * @self: A #ClutterActor
10180 * @scale_x: double factor to scale actor by horizontally.
10181 * @scale_y: double factor to scale actor by vertically.
10182 * @center_x: X coordinate of the center of the scale.
10183 * @center_y: Y coordinate of the center of the scale
10185 * Scales an actor with the given factors around the given center
10186 * point. The center point is specified in pixels relative to the
10187 * anchor point (usually the top left corner of the actor).
10189 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10195 clutter_actor_set_scale_full (ClutterActor *self,
10201 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10203 g_object_freeze_notify (G_OBJECT (self));
10205 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10206 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10207 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10208 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10210 g_object_thaw_notify (G_OBJECT (self));
10214 * clutter_actor_set_scale_with_gravity:
10215 * @self: A #ClutterActor
10216 * @scale_x: double factor to scale actor by horizontally.
10217 * @scale_y: double factor to scale actor by vertically.
10218 * @gravity: the location of the scale center expressed as a compass
10221 * Scales an actor with the given factors around the given
10222 * center point. The center point is specified as one of the compass
10223 * directions in #ClutterGravity. For example, setting it to north
10224 * will cause the top of the actor to remain unchanged and the rest of
10225 * the actor to expand left, right and downwards.
10227 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10233 clutter_actor_set_scale_with_gravity (ClutterActor *self,
10236 ClutterGravity gravity)
10238 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10240 g_object_freeze_notify (G_OBJECT (self));
10242 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10243 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10244 clutter_actor_set_scale_gravity (self, gravity);
10246 g_object_thaw_notify (G_OBJECT (self));
10250 * clutter_actor_get_scale:
10251 * @self: A #ClutterActor
10252 * @scale_x: (out) (allow-none): Location to store horizonal
10253 * scale factor, or %NULL.
10254 * @scale_y: (out) (allow-none): Location to store vertical
10255 * scale factor, or %NULL.
10257 * Retrieves an actors scale factors.
10262 clutter_actor_get_scale (ClutterActor *self,
10266 const ClutterTransformInfo *info;
10268 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10270 info = _clutter_actor_get_transform_info_or_defaults (self);
10273 *scale_x = info->scale_x;
10276 *scale_y = info->scale_y;
10280 * clutter_actor_get_scale_center:
10281 * @self: A #ClutterActor
10282 * @center_x: (out) (allow-none): Location to store the X position
10283 * of the scale center, or %NULL.
10284 * @center_y: (out) (allow-none): Location to store the Y position
10285 * of the scale center, or %NULL.
10287 * Retrieves the scale center coordinate in pixels relative to the top
10288 * left corner of the actor. If the scale center was specified using a
10289 * #ClutterGravity this will calculate the pixel offset using the
10290 * current size of the actor.
10295 clutter_actor_get_scale_center (ClutterActor *self,
10299 const ClutterTransformInfo *info;
10301 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10303 info = _clutter_actor_get_transform_info_or_defaults (self);
10305 clutter_anchor_coord_get_units (self, &info->scale_center,
10312 * clutter_actor_get_scale_gravity:
10313 * @self: A #ClutterActor
10315 * Retrieves the scale center as a compass direction. If the scale
10316 * center was specified in pixels or units this will return
10317 * %CLUTTER_GRAVITY_NONE.
10319 * Return value: the scale gravity
10324 clutter_actor_get_scale_gravity (ClutterActor *self)
10326 const ClutterTransformInfo *info;
10328 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10330 info = _clutter_actor_get_transform_info_or_defaults (self);
10332 return clutter_anchor_coord_get_gravity (&info->scale_center);
10336 clutter_actor_set_opacity_internal (ClutterActor *self,
10339 ClutterActorPrivate *priv = self->priv;
10341 if (priv->opacity != opacity)
10343 priv->opacity = opacity;
10345 /* Queue a redraw from the flatten effect so that it can use
10346 its cached image if available instead of having to redraw the
10347 actual actor. If it doesn't end up using the FBO then the
10348 effect is still able to continue the paint anyway. If there
10349 is no flatten effect yet then this is equivalent to queueing
10351 _clutter_actor_queue_redraw_full (self,
10354 priv->flatten_effect);
10356 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10361 * clutter_actor_set_opacity:
10362 * @self: A #ClutterActor
10363 * @opacity: New opacity value for the actor.
10365 * Sets the actor's opacity, with zero being completely transparent and
10366 * 255 (0xff) being fully opaque.
10368 * The #ClutterActor:opacity property is animatable.
10371 clutter_actor_set_opacity (ClutterActor *self,
10374 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10376 if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10378 _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10379 self->priv->opacity,
10383 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10387 * clutter_actor_get_paint_opacity_internal:
10388 * @self: a #ClutterActor
10390 * Retrieves the absolute opacity of the actor, as it appears on the stage
10392 * This function does not do type checks
10394 * Return value: the absolute opacity of the actor
10397 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10399 ClutterActorPrivate *priv = self->priv;
10400 ClutterActor *parent;
10402 /* override the top-level opacity to always be 255; even in
10403 * case of ClutterStage:use-alpha being TRUE we want the rest
10404 * of the scene to be painted
10406 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10409 if (priv->opacity_override >= 0)
10410 return priv->opacity_override;
10412 parent = priv->parent;
10414 /* Factor in the actual actors opacity with parents */
10415 if (parent != NULL)
10417 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10419 if (opacity != 0xff)
10420 return (opacity * priv->opacity) / 0xff;
10423 return priv->opacity;
10428 * clutter_actor_get_paint_opacity:
10429 * @self: A #ClutterActor
10431 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10433 * This function traverses the hierarchy chain and composites the opacity of
10434 * the actor with that of its parents.
10436 * This function is intended for subclasses to use in the paint virtual
10437 * function, to paint themselves with the correct opacity.
10439 * Return value: The actor opacity value.
10444 clutter_actor_get_paint_opacity (ClutterActor *self)
10446 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10448 return clutter_actor_get_paint_opacity_internal (self);
10452 * clutter_actor_get_opacity:
10453 * @self: a #ClutterActor
10455 * Retrieves the opacity value of an actor, as set by
10456 * clutter_actor_set_opacity().
10458 * For retrieving the absolute opacity of the actor inside a paint
10459 * virtual function, see clutter_actor_get_paint_opacity().
10461 * Return value: the opacity of the actor
10464 clutter_actor_get_opacity (ClutterActor *self)
10466 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10468 return self->priv->opacity;
10472 * clutter_actor_set_offscreen_redirect:
10473 * @self: A #ClutterActor
10474 * @redirect: New offscreen redirect flags for the actor.
10476 * Defines the circumstances where the actor should be redirected into
10477 * an offscreen image. The offscreen image is used to flatten the
10478 * actor into a single image while painting for two main reasons.
10479 * Firstly, when the actor is painted a second time without any of its
10480 * contents changing it can simply repaint the cached image without
10481 * descending further down the actor hierarchy. Secondly, it will make
10482 * the opacity look correct even if there are overlapping primitives
10485 * Caching the actor could in some cases be a performance win and in
10486 * some cases be a performance lose so it is important to determine
10487 * which value is right for an actor before modifying this value. For
10488 * example, there is never any reason to flatten an actor that is just
10489 * a single texture (such as a #ClutterTexture) because it is
10490 * effectively already cached in an image so the offscreen would be
10491 * redundant. Also if the actor contains primitives that are far apart
10492 * with a large transparent area in the middle (such as a large
10493 * CluterGroup with a small actor in the top left and a small actor in
10494 * the bottom right) then the cached image will contain the entire
10495 * image of the large area and the paint will waste time blending all
10496 * of the transparent pixels in the middle.
10498 * The default method of implementing opacity on a container simply
10499 * forwards on the opacity to all of the children. If the children are
10500 * overlapping then it will appear as if they are two separate glassy
10501 * objects and there will be a break in the color where they
10502 * overlap. By redirecting to an offscreen buffer it will be as if the
10503 * two opaque objects are combined into one and then made transparent
10504 * which is usually what is expected.
10506 * The image below demonstrates the difference between redirecting and
10507 * not. The image shows two Clutter groups, each containing a red and
10508 * a green rectangle which overlap. The opacity on the group is set to
10509 * 128 (which is 50%). When the offscreen redirect is not used, the
10510 * red rectangle can be seen through the blue rectangle as if the two
10511 * rectangles were separately transparent. When the redirect is used
10512 * the group as a whole is transparent instead so the red rectangle is
10513 * not visible where they overlap.
10515 * <figure id="offscreen-redirect">
10516 * <title>Sample of using an offscreen redirect for transparency</title>
10517 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10520 * The default value for this property is 0, so we effectively will
10521 * never redirect an actor offscreen by default. This means that there
10522 * are times that transparent actors may look glassy as described
10523 * above. The reason this is the default is because there is a
10524 * performance trade off between quality and performance here. In many
10525 * cases the default form of glassy opacity looks good enough, but if
10526 * it's not you will need to set the
10527 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10528 * redirection for opacity.
10530 * Custom actors that don't contain any overlapping primitives are
10531 * recommended to override the has_overlaps() virtual to return %FALSE
10532 * for maximum efficiency.
10537 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10538 ClutterOffscreenRedirect redirect)
10540 ClutterActorPrivate *priv;
10542 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10546 if (priv->offscreen_redirect != redirect)
10548 priv->offscreen_redirect = redirect;
10550 /* Queue a redraw from the effect so that it can use its cached
10551 image if available instead of having to redraw the actual
10552 actor. If it doesn't end up using the FBO then the effect is
10553 still able to continue the paint anyway. If there is no
10554 effect then this is equivalent to queuing a full redraw */
10555 _clutter_actor_queue_redraw_full (self,
10558 priv->flatten_effect);
10560 g_object_notify_by_pspec (G_OBJECT (self),
10561 obj_props[PROP_OFFSCREEN_REDIRECT]);
10566 * clutter_actor_get_offscreen_redirect:
10567 * @self: a #ClutterActor
10569 * Retrieves whether to redirect the actor to an offscreen buffer, as
10570 * set by clutter_actor_set_offscreen_redirect().
10572 * Return value: the value of the offscreen-redirect property of the actor
10576 ClutterOffscreenRedirect
10577 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10579 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10581 return self->priv->offscreen_redirect;
10585 * clutter_actor_set_name:
10586 * @self: A #ClutterActor
10587 * @name: Textual tag to apply to actor
10589 * Sets the given name to @self. The name can be used to identify
10593 clutter_actor_set_name (ClutterActor *self,
10596 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10598 g_free (self->priv->name);
10599 self->priv->name = g_strdup (name);
10601 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10605 * clutter_actor_get_name:
10606 * @self: A #ClutterActor
10608 * Retrieves the name of @self.
10610 * Return value: the name of the actor, or %NULL. The returned string is
10611 * owned by the actor and should not be modified or freed.
10614 clutter_actor_get_name (ClutterActor *self)
10616 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10618 return self->priv->name;
10622 * clutter_actor_get_gid:
10623 * @self: A #ClutterActor
10625 * Retrieves the unique id for @self.
10627 * Return value: Globally unique value for this object instance.
10631 * Deprecated: 1.8: The id is not used any longer.
10634 clutter_actor_get_gid (ClutterActor *self)
10636 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10638 return self->priv->id;
10642 clutter_actor_set_depth_internal (ClutterActor *self,
10645 ClutterTransformInfo *info;
10647 info = _clutter_actor_get_transform_info (self);
10649 if (info->depth != depth)
10651 /* Sets Z value - XXX 2.0: should we invert? */
10652 info->depth = depth;
10654 self->priv->transform_valid = FALSE;
10656 /* FIXME - remove this crap; sadly, there are still containers
10657 * in Clutter that depend on this utter brain damage
10659 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10661 clutter_actor_queue_redraw (self);
10663 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10668 * clutter_actor_set_depth:
10669 * @self: a #ClutterActor
10672 * Sets the Z coordinate of @self to @depth.
10674 * The unit used by @depth is dependant on the perspective setup. See
10675 * also clutter_stage_set_perspective().
10678 clutter_actor_set_depth (ClutterActor *self,
10681 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10683 if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10685 const ClutterTransformInfo *info;
10687 info = _clutter_actor_get_transform_info_or_defaults (self);
10689 _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10694 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10696 clutter_actor_queue_redraw (self);
10700 * clutter_actor_get_depth:
10701 * @self: a #ClutterActor
10703 * Retrieves the depth of @self.
10705 * Return value: the depth of the actor
10708 clutter_actor_get_depth (ClutterActor *self)
10710 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10712 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10716 * clutter_actor_set_rotation:
10717 * @self: a #ClutterActor
10718 * @axis: the axis of rotation
10719 * @angle: the angle of rotation
10720 * @x: X coordinate of the rotation center
10721 * @y: Y coordinate of the rotation center
10722 * @z: Z coordinate of the rotation center
10724 * Sets the rotation angle of @self around the given axis.
10726 * The rotation center coordinates used depend on the value of @axis:
10728 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10729 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10730 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10733 * The rotation coordinates are relative to the anchor point of the
10734 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10735 * point is set, the upper left corner is assumed as the origin.
10740 clutter_actor_set_rotation (ClutterActor *self,
10741 ClutterRotateAxis axis,
10749 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10755 g_object_freeze_notify (G_OBJECT (self));
10757 clutter_actor_set_rotation_angle (self, axis, angle);
10758 clutter_actor_set_rotation_center_internal (self, axis, &v);
10760 g_object_thaw_notify (G_OBJECT (self));
10764 * clutter_actor_set_z_rotation_from_gravity:
10765 * @self: a #ClutterActor
10766 * @angle: the angle of rotation
10767 * @gravity: the center point of the rotation
10769 * Sets the rotation angle of @self around the Z axis using the center
10770 * point specified as a compass point. For example to rotate such that
10771 * the center of the actor remains static you can use
10772 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10773 * will move accordingly.
10778 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10780 ClutterGravity gravity)
10782 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10784 if (gravity == CLUTTER_GRAVITY_NONE)
10785 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10788 GObject *obj = G_OBJECT (self);
10789 ClutterTransformInfo *info;
10791 info = _clutter_actor_get_transform_info (self);
10793 g_object_freeze_notify (obj);
10795 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10797 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10798 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10799 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10801 g_object_thaw_notify (obj);
10806 * clutter_actor_get_rotation:
10807 * @self: a #ClutterActor
10808 * @axis: the axis of rotation
10809 * @x: (out): return value for the X coordinate of the center of rotation
10810 * @y: (out): return value for the Y coordinate of the center of rotation
10811 * @z: (out): return value for the Z coordinate of the center of rotation
10813 * Retrieves the angle and center of rotation on the given axis,
10814 * set using clutter_actor_set_rotation().
10816 * Return value: the angle of rotation
10821 clutter_actor_get_rotation (ClutterActor *self,
10822 ClutterRotateAxis axis,
10827 const ClutterTransformInfo *info;
10828 const AnchorCoord *anchor_coord;
10829 gdouble retval = 0;
10831 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10833 info = _clutter_actor_get_transform_info_or_defaults (self);
10837 case CLUTTER_X_AXIS:
10838 anchor_coord = &info->rx_center;
10839 retval = info->rx_angle;
10842 case CLUTTER_Y_AXIS:
10843 anchor_coord = &info->ry_center;
10844 retval = info->ry_angle;
10847 case CLUTTER_Z_AXIS:
10848 anchor_coord = &info->rz_center;
10849 retval = info->rz_angle;
10853 anchor_coord = NULL;
10858 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10864 * clutter_actor_get_z_rotation_gravity:
10865 * @self: A #ClutterActor
10867 * Retrieves the center for the rotation around the Z axis as a
10868 * compass direction. If the center was specified in pixels or units
10869 * this will return %CLUTTER_GRAVITY_NONE.
10871 * Return value: the Z rotation center
10876 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10878 const ClutterTransformInfo *info;
10880 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10882 info = _clutter_actor_get_transform_info_or_defaults (self);
10884 return clutter_anchor_coord_get_gravity (&info->rz_center);
10888 * clutter_actor_set_clip:
10889 * @self: A #ClutterActor
10890 * @xoff: X offset of the clip rectangle
10891 * @yoff: Y offset of the clip rectangle
10892 * @width: Width of the clip rectangle
10893 * @height: Height of the clip rectangle
10895 * Sets clip area for @self. The clip area is always computed from the
10896 * upper left corner of the actor, even if the anchor point is set
10902 clutter_actor_set_clip (ClutterActor *self,
10908 ClutterActorPrivate *priv;
10910 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10914 if (priv->has_clip &&
10915 priv->clip.x == xoff &&
10916 priv->clip.y == yoff &&
10917 priv->clip.width == width &&
10918 priv->clip.height == height)
10921 priv->clip.x = xoff;
10922 priv->clip.y = yoff;
10923 priv->clip.width = width;
10924 priv->clip.height = height;
10926 priv->has_clip = TRUE;
10928 clutter_actor_queue_redraw (self);
10930 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10931 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10935 * clutter_actor_remove_clip:
10936 * @self: A #ClutterActor
10938 * Removes clip area from @self.
10941 clutter_actor_remove_clip (ClutterActor *self)
10943 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10945 if (!self->priv->has_clip)
10948 self->priv->has_clip = FALSE;
10950 clutter_actor_queue_redraw (self);
10952 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10956 * clutter_actor_has_clip:
10957 * @self: a #ClutterActor
10959 * Determines whether the actor has a clip area set or not.
10961 * Return value: %TRUE if the actor has a clip area set.
10966 clutter_actor_has_clip (ClutterActor *self)
10968 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10970 return self->priv->has_clip;
10974 * clutter_actor_get_clip:
10975 * @self: a #ClutterActor
10976 * @xoff: (out) (allow-none): return location for the X offset of
10977 * the clip rectangle, or %NULL
10978 * @yoff: (out) (allow-none): return location for the Y offset of
10979 * the clip rectangle, or %NULL
10980 * @width: (out) (allow-none): return location for the width of
10981 * the clip rectangle, or %NULL
10982 * @height: (out) (allow-none): return location for the height of
10983 * the clip rectangle, or %NULL
10985 * Gets the clip area for @self, if any is set
10990 clutter_actor_get_clip (ClutterActor *self,
10996 ClutterActorPrivate *priv;
10998 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11002 if (!priv->has_clip)
11006 *xoff = priv->clip.x;
11009 *yoff = priv->clip.y;
11012 *width = priv->clip.width;
11014 if (height != NULL)
11015 *height = priv->clip.height;
11019 * clutter_actor_get_children:
11020 * @self: a #ClutterActor
11022 * Retrieves the list of children of @self.
11024 * Return value: (transfer container) (element-type ClutterActor): A newly
11025 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
11031 clutter_actor_get_children (ClutterActor *self)
11033 ClutterActor *iter;
11036 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11038 /* we walk the list backward so that we can use prepend(),
11041 for (iter = self->priv->last_child, res = NULL;
11043 iter = iter->priv->prev_sibling)
11045 res = g_list_prepend (res, iter);
11052 * insert_child_at_depth:
11053 * @self: a #ClutterActor
11054 * @child: a #ClutterActor
11056 * Inserts @child inside the list of children held by @self, using
11057 * the depth as the insertion criteria.
11059 * This sadly makes the insertion not O(1), but we can keep the
11060 * list sorted so that the painters algorithm we use for painting
11061 * the children will work correctly.
11064 insert_child_at_depth (ClutterActor *self,
11065 ClutterActor *child,
11066 gpointer dummy G_GNUC_UNUSED)
11068 ClutterActor *iter;
11071 child->priv->parent = self;
11074 _clutter_actor_get_transform_info_or_defaults (child)->depth;
11076 /* special-case the first child */
11077 if (self->priv->n_children == 0)
11079 self->priv->first_child = child;
11080 self->priv->last_child = child;
11082 child->priv->next_sibling = NULL;
11083 child->priv->prev_sibling = NULL;
11088 /* Find the right place to insert the child so that it will still be
11089 sorted and the child will be after all of the actors at the same
11091 for (iter = self->priv->first_child;
11093 iter = iter->priv->next_sibling)
11098 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11100 if (iter_depth > child_depth)
11106 ClutterActor *tmp = iter->priv->prev_sibling;
11109 tmp->priv->next_sibling = child;
11111 /* Insert the node before the found one */
11112 child->priv->prev_sibling = iter->priv->prev_sibling;
11113 child->priv->next_sibling = iter;
11114 iter->priv->prev_sibling = child;
11118 ClutterActor *tmp = self->priv->last_child;
11121 tmp->priv->next_sibling = child;
11123 /* insert the node at the end of the list */
11124 child->priv->prev_sibling = self->priv->last_child;
11125 child->priv->next_sibling = NULL;
11128 if (child->priv->prev_sibling == NULL)
11129 self->priv->first_child = child;
11131 if (child->priv->next_sibling == NULL)
11132 self->priv->last_child = child;
11136 insert_child_at_index (ClutterActor *self,
11137 ClutterActor *child,
11140 gint index_ = GPOINTER_TO_INT (data_);
11142 child->priv->parent = self;
11146 ClutterActor *tmp = self->priv->first_child;
11149 tmp->priv->prev_sibling = child;
11151 child->priv->prev_sibling = NULL;
11152 child->priv->next_sibling = tmp;
11154 else if (index_ < 0 || index_ >= self->priv->n_children)
11156 ClutterActor *tmp = self->priv->last_child;
11159 tmp->priv->next_sibling = child;
11161 child->priv->prev_sibling = tmp;
11162 child->priv->next_sibling = NULL;
11166 ClutterActor *iter;
11169 for (iter = self->priv->first_child, i = 0;
11171 iter = iter->priv->next_sibling, i += 1)
11175 ClutterActor *tmp = iter->priv->prev_sibling;
11177 child->priv->prev_sibling = tmp;
11178 child->priv->next_sibling = iter;
11180 iter->priv->prev_sibling = child;
11183 tmp->priv->next_sibling = child;
11190 if (child->priv->prev_sibling == NULL)
11191 self->priv->first_child = child;
11193 if (child->priv->next_sibling == NULL)
11194 self->priv->last_child = child;
11198 insert_child_above (ClutterActor *self,
11199 ClutterActor *child,
11202 ClutterActor *sibling = data;
11204 child->priv->parent = self;
11206 if (sibling == NULL)
11207 sibling = self->priv->last_child;
11209 child->priv->prev_sibling = sibling;
11211 if (sibling != NULL)
11213 ClutterActor *tmp = sibling->priv->next_sibling;
11215 child->priv->next_sibling = tmp;
11218 tmp->priv->prev_sibling = child;
11220 sibling->priv->next_sibling = child;
11223 child->priv->next_sibling = NULL;
11225 if (child->priv->prev_sibling == NULL)
11226 self->priv->first_child = child;
11228 if (child->priv->next_sibling == NULL)
11229 self->priv->last_child = child;
11233 insert_child_below (ClutterActor *self,
11234 ClutterActor *child,
11237 ClutterActor *sibling = data;
11239 child->priv->parent = self;
11241 if (sibling == NULL)
11242 sibling = self->priv->first_child;
11244 child->priv->next_sibling = sibling;
11246 if (sibling != NULL)
11248 ClutterActor *tmp = sibling->priv->prev_sibling;
11250 child->priv->prev_sibling = tmp;
11253 tmp->priv->next_sibling = child;
11255 sibling->priv->prev_sibling = child;
11258 child->priv->prev_sibling = NULL;
11260 if (child->priv->prev_sibling == NULL)
11261 self->priv->first_child = child;
11263 if (child->priv->next_sibling == NULL)
11264 self->priv->last_child = child;
11267 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11268 ClutterActor *child,
11272 ADD_CHILD_CREATE_META = 1 << 0,
11273 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
11274 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
11275 ADD_CHILD_CHECK_STATE = 1 << 3,
11276 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
11277 ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11279 /* default flags for public API */
11280 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
11281 ADD_CHILD_EMIT_PARENT_SET |
11282 ADD_CHILD_EMIT_ACTOR_ADDED |
11283 ADD_CHILD_CHECK_STATE |
11284 ADD_CHILD_NOTIFY_FIRST_LAST |
11285 ADD_CHILD_SHOW_ON_SET_PARENT,
11287 /* flags for legacy/deprecated API */
11288 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
11289 ADD_CHILD_CHECK_STATE |
11290 ADD_CHILD_NOTIFY_FIRST_LAST |
11291 ADD_CHILD_SHOW_ON_SET_PARENT
11292 } ClutterActorAddChildFlags;
11295 * clutter_actor_add_child_internal:
11296 * @self: a #ClutterActor
11297 * @child: a #ClutterActor
11298 * @flags: control flags for actions
11299 * @add_func: delegate function
11300 * @data: (closure): data to pass to @add_func
11302 * Adds @child to the list of children of @self.
11304 * The actual insertion inside the list is delegated to @add_func: this
11305 * function will just set up the state, perform basic checks, and emit
11308 * The @flags argument is used to perform additional operations.
11311 clutter_actor_add_child_internal (ClutterActor *self,
11312 ClutterActor *child,
11313 ClutterActorAddChildFlags flags,
11314 ClutterActorAddChildFunc add_func,
11317 ClutterTextDirection text_dir;
11318 gboolean create_meta;
11319 gboolean emit_parent_set, emit_actor_added;
11320 gboolean check_state;
11321 gboolean notify_first_last;
11322 gboolean show_on_set_parent;
11323 ClutterActor *old_first_child, *old_last_child;
11325 if (child->priv->parent != NULL)
11327 g_warning ("The actor '%s' already has a parent, '%s'. You must "
11328 "use clutter_actor_remove_child() first.",
11329 _clutter_actor_get_debug_name (child),
11330 _clutter_actor_get_debug_name (child->priv->parent));
11334 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11336 g_warning ("The actor '%s' is a top-level actor, and cannot be "
11337 "a child of another actor.",
11338 _clutter_actor_get_debug_name (child));
11343 /* XXX - this check disallows calling methods that change the stacking
11344 * order within the destruction sequence, by triggering a critical
11345 * warning first, and leaving the actor in an undefined state, which
11346 * then ends up being caught by an assertion.
11348 * the reproducible sequence is:
11350 * - actor gets destroyed;
11351 * - another actor, linked to the first, will try to change the
11352 * stacking order of the first actor;
11353 * - changing the stacking order is a composite operation composed
11354 * by the following steps:
11355 * 1. ref() the child;
11356 * 2. remove_child_internal(), which removes the reference;
11357 * 3. add_child_internal(), which adds a reference;
11358 * - the state of the actor is not changed between (2) and (3), as
11359 * it could be an expensive recomputation;
11360 * - if (3) bails out, then the actor is in an undefined state, but
11362 * - the destruction sequence terminates, but the actor is unparented
11363 * while its state indicates being parented instead.
11364 * - assertion failure.
11366 * the obvious fix would be to decompose each set_child_*_sibling()
11367 * method into proper remove_child()/add_child(), with state validation;
11368 * this may cause excessive work, though, and trigger a cascade of other
11369 * bugs in code that assumes that a change in the stacking order is an
11370 * atomic operation.
11372 * another potential fix is to just remove this check here, and let
11373 * code doing stacking order changes inside the destruction sequence
11374 * of an actor continue doing the work.
11376 * the third fix is to silently bail out early from every
11377 * set_child_*_sibling() and set_child_at_index() method, and avoid
11380 * I have a preference for the second solution, since it involves the
11381 * least amount of work, and the least amount of code duplication.
11383 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11385 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11387 g_warning ("The actor '%s' is currently being destroyed, and "
11388 "cannot be added as a child of another actor.",
11389 _clutter_actor_get_debug_name (child));
11394 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11395 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11396 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11397 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11398 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11399 show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11401 old_first_child = self->priv->first_child;
11402 old_last_child = self->priv->last_child;
11404 g_object_freeze_notify (G_OBJECT (self));
11407 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11409 g_object_ref_sink (child);
11410 child->priv->parent = NULL;
11411 child->priv->next_sibling = NULL;
11412 child->priv->prev_sibling = NULL;
11414 /* delegate the actual insertion */
11415 add_func (self, child, data);
11417 g_assert (child->priv->parent == self);
11419 self->priv->n_children += 1;
11421 self->priv->age += 1;
11423 /* if push_internal() has been called then we automatically set
11424 * the flag on the actor
11426 if (self->priv->internal_child)
11427 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11429 /* children may cause their parent to expand, if they are set
11430 * to expand; if a child is not expanded then it cannot change
11431 * its parent's state. any further change later on will queue
11432 * an expand state check.
11434 * this check, with the initial state of the needs_compute_expand
11435 * flag set to FALSE, should avoid recomputing the expand flags
11436 * state while building the actor tree.
11438 if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11439 (child->priv->needs_compute_expand ||
11440 child->priv->needs_x_expand ||
11441 child->priv->needs_y_expand))
11443 clutter_actor_queue_compute_expand (self);
11446 /* clutter_actor_reparent() will emit ::parent-set for us */
11447 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11448 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11452 /* If parent is mapped or realized, we need to also be mapped or
11453 * realized once we're inside the parent.
11455 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11457 /* propagate the parent's text direction to the child */
11458 text_dir = clutter_actor_get_text_direction (self);
11459 clutter_actor_set_text_direction (child, text_dir);
11462 if (show_on_set_parent && child->priv->show_on_set_parent)
11463 clutter_actor_show (child);
11465 if (CLUTTER_ACTOR_IS_MAPPED (child))
11466 clutter_actor_queue_redraw (child);
11468 /* maintain the invariant that if an actor needs layout,
11469 * its parents do as well
11471 if (child->priv->needs_width_request ||
11472 child->priv->needs_height_request ||
11473 child->priv->needs_allocation)
11475 /* we work around the short-circuiting we do
11476 * in clutter_actor_queue_relayout() since we
11477 * want to force a relayout
11479 child->priv->needs_width_request = TRUE;
11480 child->priv->needs_height_request = TRUE;
11481 child->priv->needs_allocation = TRUE;
11483 clutter_actor_queue_relayout (child->priv->parent);
11486 if (emit_actor_added)
11487 g_signal_emit_by_name (self, "actor-added", child);
11489 if (notify_first_last)
11491 if (old_first_child != self->priv->first_child)
11492 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11494 if (old_last_child != self->priv->last_child)
11495 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11498 g_object_thaw_notify (G_OBJECT (self));
11502 * clutter_actor_add_child:
11503 * @self: a #ClutterActor
11504 * @child: a #ClutterActor
11506 * Adds @child to the children of @self.
11508 * This function will acquire a reference on @child that will only
11509 * be released when calling clutter_actor_remove_child().
11511 * This function will take into consideration the #ClutterActor:depth
11512 * of @child, and will keep the list of children sorted.
11514 * This function will emit the #ClutterContainer::actor-added signal
11520 clutter_actor_add_child (ClutterActor *self,
11521 ClutterActor *child)
11523 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11524 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11525 g_return_if_fail (self != child);
11526 g_return_if_fail (child->priv->parent == NULL);
11528 clutter_actor_add_child_internal (self, child,
11529 ADD_CHILD_DEFAULT_FLAGS,
11530 insert_child_at_depth,
11535 * clutter_actor_insert_child_at_index:
11536 * @self: a #ClutterActor
11537 * @child: a #ClutterActor
11538 * @index_: the index
11540 * Inserts @child into the list of children of @self, using the
11541 * given @index_. If @index_ is greater than the number of children
11542 * in @self, or is less than 0, then the new child is added at the end.
11544 * This function will acquire a reference on @child that will only
11545 * be released when calling clutter_actor_remove_child().
11547 * This function will not take into consideration the #ClutterActor:depth
11550 * This function will emit the #ClutterContainer::actor-added signal
11556 clutter_actor_insert_child_at_index (ClutterActor *self,
11557 ClutterActor *child,
11560 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11561 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11562 g_return_if_fail (self != child);
11563 g_return_if_fail (child->priv->parent == NULL);
11565 clutter_actor_add_child_internal (self, child,
11566 ADD_CHILD_DEFAULT_FLAGS,
11567 insert_child_at_index,
11568 GINT_TO_POINTER (index_));
11572 * clutter_actor_insert_child_above:
11573 * @self: a #ClutterActor
11574 * @child: a #ClutterActor
11575 * @sibling: (allow-none): a child of @self, or %NULL
11577 * Inserts @child into the list of children of @self, above another
11578 * child of @self or, if @sibling is %NULL, above all the children
11581 * This function will acquire a reference on @child that will only
11582 * be released when calling clutter_actor_remove_child().
11584 * This function will not take into consideration the #ClutterActor:depth
11587 * This function will emit the #ClutterContainer::actor-added signal
11593 clutter_actor_insert_child_above (ClutterActor *self,
11594 ClutterActor *child,
11595 ClutterActor *sibling)
11597 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11598 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11599 g_return_if_fail (self != child);
11600 g_return_if_fail (child != sibling);
11601 g_return_if_fail (child->priv->parent == NULL);
11602 g_return_if_fail (sibling == NULL ||
11603 (CLUTTER_IS_ACTOR (sibling) &&
11604 sibling->priv->parent == self));
11606 clutter_actor_add_child_internal (self, child,
11607 ADD_CHILD_DEFAULT_FLAGS,
11608 insert_child_above,
11613 * clutter_actor_insert_child_below:
11614 * @self: a #ClutterActor
11615 * @child: a #ClutterActor
11616 * @sibling: (allow-none): a child of @self, or %NULL
11618 * Inserts @child into the list of children of @self, below another
11619 * child of @self or, if @sibling is %NULL, below all the children
11622 * This function will acquire a reference on @child that will only
11623 * be released when calling clutter_actor_remove_child().
11625 * This function will not take into consideration the #ClutterActor:depth
11628 * This function will emit the #ClutterContainer::actor-added signal
11634 clutter_actor_insert_child_below (ClutterActor *self,
11635 ClutterActor *child,
11636 ClutterActor *sibling)
11638 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11639 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11640 g_return_if_fail (self != child);
11641 g_return_if_fail (child != sibling);
11642 g_return_if_fail (child->priv->parent == NULL);
11643 g_return_if_fail (sibling == NULL ||
11644 (CLUTTER_IS_ACTOR (sibling) &&
11645 sibling->priv->parent == self));
11647 clutter_actor_add_child_internal (self, child,
11648 ADD_CHILD_DEFAULT_FLAGS,
11649 insert_child_below,
11654 * clutter_actor_set_parent:
11655 * @self: A #ClutterActor
11656 * @parent: A new #ClutterActor parent
11658 * Sets the parent of @self to @parent.
11660 * This function will result in @parent acquiring a reference on @self,
11661 * eventually by sinking its floating reference first. The reference
11662 * will be released by clutter_actor_unparent().
11664 * This function should only be called by legacy #ClutterActor<!-- -->s
11665 * implementing the #ClutterContainer interface.
11667 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11670 clutter_actor_set_parent (ClutterActor *self,
11671 ClutterActor *parent)
11673 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11674 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11675 g_return_if_fail (self != parent);
11676 g_return_if_fail (self->priv->parent == NULL);
11678 /* as this function will be called inside ClutterContainer::add
11679 * implementations or when building up a composite actor, we have
11680 * to preserve the old behaviour, and not create child meta or
11681 * emit the ::actor-added signal, to avoid recursion or double
11684 clutter_actor_add_child_internal (parent, self,
11685 ADD_CHILD_LEGACY_FLAGS,
11686 insert_child_at_depth,
11691 * clutter_actor_get_parent:
11692 * @self: A #ClutterActor
11694 * Retrieves the parent of @self.
11696 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11697 * if no parent is set
11700 clutter_actor_get_parent (ClutterActor *self)
11702 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11704 return self->priv->parent;
11708 * clutter_actor_get_paint_visibility:
11709 * @self: A #ClutterActor
11711 * Retrieves the 'paint' visibility of an actor recursively checking for non
11714 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11716 * Return Value: %TRUE if the actor is visibile and will be painted.
11721 clutter_actor_get_paint_visibility (ClutterActor *actor)
11723 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11725 return CLUTTER_ACTOR_IS_MAPPED (actor);
11729 * clutter_actor_remove_child:
11730 * @self: a #ClutterActor
11731 * @child: a #ClutterActor
11733 * Removes @child from the children of @self.
11735 * This function will release the reference added by
11736 * clutter_actor_add_child(), so if you want to keep using @child
11737 * you will have to acquire a referenced on it before calling this
11740 * This function will emit the #ClutterContainer::actor-removed
11746 clutter_actor_remove_child (ClutterActor *self,
11747 ClutterActor *child)
11749 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11750 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11751 g_return_if_fail (self != child);
11752 g_return_if_fail (child->priv->parent != NULL);
11753 g_return_if_fail (child->priv->parent == self);
11755 clutter_actor_remove_child_internal (self, child,
11756 REMOVE_CHILD_DEFAULT_FLAGS);
11760 * clutter_actor_remove_all_children:
11761 * @self: a #ClutterActor
11763 * Removes all children of @self.
11765 * This function releases the reference added by inserting a child actor
11766 * in the list of children of @self.
11768 * If the reference count of a child drops to zero, the child will be
11769 * destroyed. If you want to ensure the destruction of all the children
11770 * of @self, use clutter_actor_destroy_all_children().
11775 clutter_actor_remove_all_children (ClutterActor *self)
11777 ClutterActorIter iter;
11779 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11781 if (self->priv->n_children == 0)
11784 g_object_freeze_notify (G_OBJECT (self));
11786 clutter_actor_iter_init (&iter, self);
11787 while (clutter_actor_iter_next (&iter, NULL))
11788 clutter_actor_iter_remove (&iter);
11790 g_object_thaw_notify (G_OBJECT (self));
11793 g_assert (self->priv->first_child == NULL);
11794 g_assert (self->priv->last_child == NULL);
11795 g_assert (self->priv->n_children == 0);
11799 * clutter_actor_destroy_all_children:
11800 * @self: a #ClutterActor
11802 * Destroys all children of @self.
11804 * This function releases the reference added by inserting a child
11805 * actor in the list of children of @self, and ensures that the
11806 * #ClutterActor::destroy signal is emitted on each child of the
11809 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11810 * when its reference count drops to 0; the default handler of the
11811 * #ClutterActor::destroy signal will destroy all the children of an
11812 * actor. This function ensures that all children are destroyed, instead
11813 * of just removed from @self, unlike clutter_actor_remove_all_children()
11814 * which will merely release the reference and remove each child.
11816 * Unless you acquired an additional reference on each child of @self
11817 * prior to calling clutter_actor_remove_all_children() and want to reuse
11818 * the actors, you should use clutter_actor_destroy_all_children() in
11819 * order to make sure that children are destroyed and signal handlers
11820 * are disconnected even in cases where circular references prevent this
11821 * from automatically happening through reference counting alone.
11826 clutter_actor_destroy_all_children (ClutterActor *self)
11828 ClutterActorIter iter;
11830 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11832 if (self->priv->n_children == 0)
11835 g_object_freeze_notify (G_OBJECT (self));
11837 clutter_actor_iter_init (&iter, self);
11838 while (clutter_actor_iter_next (&iter, NULL))
11839 clutter_actor_iter_destroy (&iter);
11841 g_object_thaw_notify (G_OBJECT (self));
11844 g_assert (self->priv->first_child == NULL);
11845 g_assert (self->priv->last_child == NULL);
11846 g_assert (self->priv->n_children == 0);
11849 typedef struct _InsertBetweenData {
11850 ClutterActor *prev_sibling;
11851 ClutterActor *next_sibling;
11852 } InsertBetweenData;
11855 insert_child_between (ClutterActor *self,
11856 ClutterActor *child,
11859 InsertBetweenData *data = data_;
11860 ClutterActor *prev_sibling = data->prev_sibling;
11861 ClutterActor *next_sibling = data->next_sibling;
11863 child->priv->parent = self;
11864 child->priv->prev_sibling = prev_sibling;
11865 child->priv->next_sibling = next_sibling;
11867 if (prev_sibling != NULL)
11868 prev_sibling->priv->next_sibling = child;
11870 if (next_sibling != NULL)
11871 next_sibling->priv->prev_sibling = child;
11873 if (child->priv->prev_sibling == NULL)
11874 self->priv->first_child = child;
11876 if (child->priv->next_sibling == NULL)
11877 self->priv->last_child = child;
11881 * clutter_actor_replace_child:
11882 * @self: a #ClutterActor
11883 * @old_child: the child of @self to replace
11884 * @new_child: the #ClutterActor to replace @old_child
11886 * Replaces @old_child with @new_child in the list of children of @self.
11891 clutter_actor_replace_child (ClutterActor *self,
11892 ClutterActor *old_child,
11893 ClutterActor *new_child)
11895 ClutterActor *prev_sibling, *next_sibling;
11896 InsertBetweenData clos;
11898 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11899 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11900 g_return_if_fail (old_child->priv->parent == self);
11901 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11902 g_return_if_fail (old_child != new_child);
11903 g_return_if_fail (new_child != self);
11904 g_return_if_fail (new_child->priv->parent == NULL);
11906 prev_sibling = old_child->priv->prev_sibling;
11907 next_sibling = old_child->priv->next_sibling;
11908 clutter_actor_remove_child_internal (self, old_child,
11909 REMOVE_CHILD_DEFAULT_FLAGS);
11911 clos.prev_sibling = prev_sibling;
11912 clos.next_sibling = next_sibling;
11913 clutter_actor_add_child_internal (self, new_child,
11914 ADD_CHILD_DEFAULT_FLAGS,
11915 insert_child_between,
11920 * clutter_actor_unparent:
11921 * @self: a #ClutterActor
11923 * Removes the parent of @self.
11925 * This will cause the parent of @self to release the reference
11926 * acquired when calling clutter_actor_set_parent(), so if you
11927 * want to keep @self you will have to acquire a reference of
11928 * your own, through g_object_ref().
11930 * This function should only be called by legacy #ClutterActor<!-- -->s
11931 * implementing the #ClutterContainer interface.
11935 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11938 clutter_actor_unparent (ClutterActor *self)
11940 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11942 if (self->priv->parent == NULL)
11945 clutter_actor_remove_child_internal (self->priv->parent, self,
11946 REMOVE_CHILD_LEGACY_FLAGS);
11950 * clutter_actor_reparent:
11951 * @self: a #ClutterActor
11952 * @new_parent: the new #ClutterActor parent
11954 * Resets the parent actor of @self.
11956 * This function is logically equivalent to calling clutter_actor_unparent()
11957 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11958 * ensures the child is not finalized when unparented, and emits the
11959 * #ClutterActor::parent-set signal only once.
11961 * In reality, calling this function is less useful than it sounds, as some
11962 * application code may rely on changes in the intermediate state between
11963 * removal and addition of the actor from its old parent to the @new_parent.
11964 * Thus, it is strongly encouraged to avoid using this function in application
11969 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11970 * clutter_actor_add_child() instead; remember to take a reference on
11971 * the actor being removed before calling clutter_actor_remove_child()
11972 * to avoid the reference count dropping to zero and the actor being
11976 clutter_actor_reparent (ClutterActor *self,
11977 ClutterActor *new_parent)
11979 ClutterActorPrivate *priv;
11981 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11982 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11983 g_return_if_fail (self != new_parent);
11985 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11987 g_warning ("Cannot set a parent on a toplevel actor");
11991 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11993 g_warning ("Cannot set a parent currently being destroyed");
11999 if (priv->parent != new_parent)
12001 ClutterActor *old_parent;
12003 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12005 old_parent = priv->parent;
12007 g_object_ref (self);
12009 if (old_parent != NULL)
12011 /* go through the Container implementation if this is a regular
12012 * child and not an internal one
12014 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12016 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
12018 /* this will have to call unparent() */
12019 clutter_container_remove_actor (parent, self);
12022 clutter_actor_remove_child_internal (old_parent, self,
12023 REMOVE_CHILD_LEGACY_FLAGS);
12026 /* Note, will call set_parent() */
12027 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12028 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
12030 clutter_actor_add_child_internal (new_parent, self,
12031 ADD_CHILD_LEGACY_FLAGS,
12032 insert_child_at_depth,
12035 /* we emit the ::parent-set signal once */
12036 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
12038 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12040 /* the IN_REPARENT flag suspends state updates */
12041 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
12043 g_object_unref (self);
12048 * clutter_actor_contains:
12049 * @self: A #ClutterActor
12050 * @descendant: A #ClutterActor, possibly contained in @self
12052 * Determines if @descendant is contained inside @self (either as an
12053 * immediate child, or as a deeper descendant). If @self and
12054 * @descendant point to the same actor then it will also return %TRUE.
12056 * Return value: whether @descendent is contained within @self
12061 clutter_actor_contains (ClutterActor *self,
12062 ClutterActor *descendant)
12064 ClutterActor *actor;
12066 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12067 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12069 for (actor = descendant; actor; actor = actor->priv->parent)
12077 * clutter_actor_set_child_above_sibling:
12078 * @self: a #ClutterActor
12079 * @child: a #ClutterActor child of @self
12080 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12082 * Sets @child to be above @sibling in the list of children of @self.
12084 * If @sibling is %NULL, @child will be the new last child of @self.
12086 * This function is logically equivalent to removing @child and using
12087 * clutter_actor_insert_child_above(), but it will not emit signals
12088 * or change state on @child.
12093 clutter_actor_set_child_above_sibling (ClutterActor *self,
12094 ClutterActor *child,
12095 ClutterActor *sibling)
12097 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12098 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12099 g_return_if_fail (child->priv->parent == self);
12100 g_return_if_fail (child != sibling);
12101 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12103 if (sibling != NULL)
12104 g_return_if_fail (sibling->priv->parent == self);
12106 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12107 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12108 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12111 /* we don't want to change the state of child, or emit signals, or
12112 * regenerate ChildMeta instances here, but we still want to follow
12113 * the correct sequence of steps encoded in remove_child() and
12114 * add_child(), so that correctness is ensured, and we only go
12115 * through one known code path.
12117 g_object_ref (child);
12118 clutter_actor_remove_child_internal (self, child, 0);
12119 clutter_actor_add_child_internal (self, child,
12120 ADD_CHILD_NOTIFY_FIRST_LAST,
12121 insert_child_above,
12124 clutter_actor_queue_relayout (self);
12128 * clutter_actor_set_child_below_sibling:
12129 * @self: a #ClutterActor
12130 * @child: a #ClutterActor child of @self
12131 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12133 * Sets @child to be below @sibling in the list of children of @self.
12135 * If @sibling is %NULL, @child will be the new first child of @self.
12137 * This function is logically equivalent to removing @self and using
12138 * clutter_actor_insert_child_below(), but it will not emit signals
12139 * or change state on @child.
12144 clutter_actor_set_child_below_sibling (ClutterActor *self,
12145 ClutterActor *child,
12146 ClutterActor *sibling)
12148 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12149 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12150 g_return_if_fail (child->priv->parent == self);
12151 g_return_if_fail (child != sibling);
12152 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12154 if (sibling != NULL)
12155 g_return_if_fail (sibling->priv->parent == self);
12157 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12158 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12159 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12162 /* see the comment in set_child_above_sibling() */
12163 g_object_ref (child);
12164 clutter_actor_remove_child_internal (self, child, 0);
12165 clutter_actor_add_child_internal (self, child,
12166 ADD_CHILD_NOTIFY_FIRST_LAST,
12167 insert_child_below,
12170 clutter_actor_queue_relayout (self);
12174 * clutter_actor_set_child_at_index:
12175 * @self: a #ClutterActor
12176 * @child: a #ClutterActor child of @self
12177 * @index_: the new index for @child
12179 * Changes the index of @child in the list of children of @self.
12181 * This function is logically equivalent to removing @child and
12182 * calling clutter_actor_insert_child_at_index(), but it will not
12183 * emit signals or change state on @child.
12188 clutter_actor_set_child_at_index (ClutterActor *self,
12189 ClutterActor *child,
12192 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12193 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12194 g_return_if_fail (child->priv->parent == self);
12195 g_return_if_fail (index_ <= self->priv->n_children);
12197 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12198 CLUTTER_ACTOR_IN_DESTRUCTION (child))
12201 g_object_ref (child);
12202 clutter_actor_remove_child_internal (self, child, 0);
12203 clutter_actor_add_child_internal (self, child,
12204 ADD_CHILD_NOTIFY_FIRST_LAST,
12205 insert_child_at_index,
12206 GINT_TO_POINTER (index_));
12208 clutter_actor_queue_relayout (self);
12212 * clutter_actor_raise:
12213 * @self: A #ClutterActor
12214 * @below: (allow-none): A #ClutterActor to raise above.
12216 * Puts @self above @below.
12218 * Both actors must have the same parent, and the parent must implement
12219 * the #ClutterContainer interface
12221 * This function calls clutter_container_raise_child() internally.
12223 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12226 clutter_actor_raise (ClutterActor *self,
12227 ClutterActor *below)
12229 ClutterActor *parent;
12231 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12233 parent = clutter_actor_get_parent (self);
12234 if (parent == NULL)
12236 g_warning ("%s: Actor '%s' is not inside a container",
12238 _clutter_actor_get_debug_name (self));
12244 if (parent != clutter_actor_get_parent (below))
12246 g_warning ("%s Actor '%s' is not in the same container as "
12249 _clutter_actor_get_debug_name (self),
12250 _clutter_actor_get_debug_name (below));
12255 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12259 * clutter_actor_lower:
12260 * @self: A #ClutterActor
12261 * @above: (allow-none): A #ClutterActor to lower below
12263 * Puts @self below @above.
12265 * Both actors must have the same parent, and the parent must implement
12266 * the #ClutterContainer interface.
12268 * This function calls clutter_container_lower_child() internally.
12270 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12273 clutter_actor_lower (ClutterActor *self,
12274 ClutterActor *above)
12276 ClutterActor *parent;
12278 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12280 parent = clutter_actor_get_parent (self);
12281 if (parent == NULL)
12283 g_warning ("%s: Actor of type %s is not inside a container",
12285 _clutter_actor_get_debug_name (self));
12291 if (parent != clutter_actor_get_parent (above))
12293 g_warning ("%s: Actor '%s' is not in the same container as "
12296 _clutter_actor_get_debug_name (self),
12297 _clutter_actor_get_debug_name (above));
12302 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12306 * clutter_actor_raise_top:
12307 * @self: A #ClutterActor
12309 * Raises @self to the top.
12311 * This function calls clutter_actor_raise() internally.
12313 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12314 * a %NULL sibling, instead.
12317 clutter_actor_raise_top (ClutterActor *self)
12319 clutter_actor_raise (self, NULL);
12323 * clutter_actor_lower_bottom:
12324 * @self: A #ClutterActor
12326 * Lowers @self to the bottom.
12328 * This function calls clutter_actor_lower() internally.
12330 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12331 * a %NULL sibling, instead.
12334 clutter_actor_lower_bottom (ClutterActor *self)
12336 clutter_actor_lower (self, NULL);
12344 * clutter_actor_event:
12345 * @actor: a #ClutterActor
12346 * @event: a #ClutterEvent
12347 * @capture: TRUE if event in in capture phase, FALSE otherwise.
12349 * This function is used to emit an event on the main stage.
12350 * You should rarely need to use this function, except for
12351 * synthetising events.
12353 * Return value: the return value from the signal emission: %TRUE
12354 * if the actor handled the event, or %FALSE if the event was
12360 clutter_actor_event (ClutterActor *actor,
12361 ClutterEvent *event,
12364 gboolean retval = FALSE;
12365 gint signal_num = -1;
12367 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12368 g_return_val_if_fail (event != NULL, FALSE);
12370 g_object_ref (actor);
12374 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12380 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12384 switch (event->type)
12386 case CLUTTER_NOTHING:
12388 case CLUTTER_BUTTON_PRESS:
12389 signal_num = BUTTON_PRESS_EVENT;
12391 case CLUTTER_BUTTON_RELEASE:
12392 signal_num = BUTTON_RELEASE_EVENT;
12394 case CLUTTER_SCROLL:
12395 signal_num = SCROLL_EVENT;
12397 case CLUTTER_KEY_PRESS:
12398 signal_num = KEY_PRESS_EVENT;
12400 case CLUTTER_KEY_RELEASE:
12401 signal_num = KEY_RELEASE_EVENT;
12403 case CLUTTER_MOTION:
12404 signal_num = MOTION_EVENT;
12406 case CLUTTER_ENTER:
12407 signal_num = ENTER_EVENT;
12409 case CLUTTER_LEAVE:
12410 signal_num = LEAVE_EVENT;
12412 case CLUTTER_DELETE:
12413 case CLUTTER_DESTROY_NOTIFY:
12414 case CLUTTER_CLIENT_MESSAGE:
12420 if (signal_num != -1)
12421 g_signal_emit (actor, actor_signals[signal_num], 0,
12426 g_object_unref (actor);
12432 * clutter_actor_set_reactive:
12433 * @actor: a #ClutterActor
12434 * @reactive: whether the actor should be reactive to events
12436 * Sets @actor as reactive. Reactive actors will receive events.
12441 clutter_actor_set_reactive (ClutterActor *actor,
12444 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12446 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12450 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12452 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12454 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12458 * clutter_actor_get_reactive:
12459 * @actor: a #ClutterActor
12461 * Checks whether @actor is marked as reactive.
12463 * Return value: %TRUE if the actor is reactive
12468 clutter_actor_get_reactive (ClutterActor *actor)
12470 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12472 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12476 * clutter_actor_get_anchor_point:
12477 * @self: a #ClutterActor
12478 * @anchor_x: (out): return location for the X coordinate of the anchor point
12479 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12481 * Gets the current anchor point of the @actor in pixels.
12486 clutter_actor_get_anchor_point (ClutterActor *self,
12490 const ClutterTransformInfo *info;
12492 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12494 info = _clutter_actor_get_transform_info_or_defaults (self);
12495 clutter_anchor_coord_get_units (self, &info->anchor,
12502 * clutter_actor_set_anchor_point:
12503 * @self: a #ClutterActor
12504 * @anchor_x: X coordinate of the anchor point
12505 * @anchor_y: Y coordinate of the anchor point
12507 * Sets an anchor point for @self. The anchor point is a point in the
12508 * coordinate space of an actor to which the actor position within its
12509 * parent is relative; the default is (0, 0), i.e. the top-left corner
12515 clutter_actor_set_anchor_point (ClutterActor *self,
12519 ClutterTransformInfo *info;
12520 ClutterActorPrivate *priv;
12521 gboolean changed = FALSE;
12522 gfloat old_anchor_x, old_anchor_y;
12525 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12527 obj = G_OBJECT (self);
12529 info = _clutter_actor_get_transform_info (self);
12531 g_object_freeze_notify (obj);
12533 clutter_anchor_coord_get_units (self, &info->anchor,
12538 if (info->anchor.is_fractional)
12539 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12541 if (old_anchor_x != anchor_x)
12543 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12547 if (old_anchor_y != anchor_y)
12549 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12553 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12557 priv->transform_valid = FALSE;
12558 clutter_actor_queue_redraw (self);
12561 g_object_thaw_notify (obj);
12565 * clutter_actor_get_anchor_point_gravity:
12566 * @self: a #ClutterActor
12568 * Retrieves the anchor position expressed as a #ClutterGravity. If
12569 * the anchor point was specified using pixels or units this will
12570 * return %CLUTTER_GRAVITY_NONE.
12572 * Return value: the #ClutterGravity used by the anchor point
12577 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12579 const ClutterTransformInfo *info;
12581 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12583 info = _clutter_actor_get_transform_info_or_defaults (self);
12585 return clutter_anchor_coord_get_gravity (&info->anchor);
12589 * clutter_actor_move_anchor_point:
12590 * @self: a #ClutterActor
12591 * @anchor_x: X coordinate of the anchor point
12592 * @anchor_y: Y coordinate of the anchor point
12594 * Sets an anchor point for the actor, and adjusts the actor postion so that
12595 * the relative position of the actor toward its parent remains the same.
12600 clutter_actor_move_anchor_point (ClutterActor *self,
12604 gfloat old_anchor_x, old_anchor_y;
12605 const ClutterTransformInfo *info;
12607 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12609 info = _clutter_actor_get_transform_info (self);
12610 clutter_anchor_coord_get_units (self, &info->anchor,
12615 g_object_freeze_notify (G_OBJECT (self));
12617 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12619 if (self->priv->position_set)
12620 clutter_actor_move_by (self,
12621 anchor_x - old_anchor_x,
12622 anchor_y - old_anchor_y);
12624 g_object_thaw_notify (G_OBJECT (self));
12628 * clutter_actor_move_anchor_point_from_gravity:
12629 * @self: a #ClutterActor
12630 * @gravity: #ClutterGravity.
12632 * Sets an anchor point on the actor based on the given gravity, adjusting the
12633 * actor postion so that its relative position within its parent remains
12636 * Since version 1.0 the anchor point will be stored as a gravity so
12637 * that if the actor changes size then the anchor point will move. For
12638 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12639 * and later double the size of the actor, the anchor point will move
12640 * to the bottom right.
12645 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12646 ClutterGravity gravity)
12648 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12649 const ClutterTransformInfo *info;
12650 ClutterActorPrivate *priv;
12652 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12655 info = _clutter_actor_get_transform_info (self);
12657 g_object_freeze_notify (G_OBJECT (self));
12659 clutter_anchor_coord_get_units (self, &info->anchor,
12663 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12664 clutter_anchor_coord_get_units (self, &info->anchor,
12669 if (priv->position_set)
12670 clutter_actor_move_by (self,
12671 new_anchor_x - old_anchor_x,
12672 new_anchor_y - old_anchor_y);
12674 g_object_thaw_notify (G_OBJECT (self));
12678 * clutter_actor_set_anchor_point_from_gravity:
12679 * @self: a #ClutterActor
12680 * @gravity: #ClutterGravity.
12682 * Sets an anchor point on the actor, based on the given gravity (this is a
12683 * convenience function wrapping clutter_actor_set_anchor_point()).
12685 * Since version 1.0 the anchor point will be stored as a gravity so
12686 * that if the actor changes size then the anchor point will move. For
12687 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12688 * and later double the size of the actor, the anchor point will move
12689 * to the bottom right.
12694 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12695 ClutterGravity gravity)
12697 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12699 if (gravity == CLUTTER_GRAVITY_NONE)
12700 clutter_actor_set_anchor_point (self, 0, 0);
12703 GObject *obj = G_OBJECT (self);
12704 ClutterTransformInfo *info;
12706 g_object_freeze_notify (obj);
12708 info = _clutter_actor_get_transform_info (self);
12709 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12711 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12712 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12713 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12715 self->priv->transform_valid = FALSE;
12717 clutter_actor_queue_redraw (self);
12719 g_object_thaw_notify (obj);
12724 clutter_actor_store_content_box (ClutterActor *self,
12725 const ClutterActorBox *box)
12729 self->priv->content_box = *box;
12730 self->priv->content_box_valid = TRUE;
12733 self->priv->content_box_valid = FALSE;
12735 clutter_actor_queue_redraw (self);
12737 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12741 clutter_container_iface_init (ClutterContainerIface *iface)
12743 /* we don't override anything, as ClutterContainer already has a default
12744 * implementation that we can use, and which calls into our own API.
12759 parse_units (ClutterActor *self,
12760 ParseDimension dimension,
12763 GValue value = G_VALUE_INIT;
12766 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12769 json_node_get_value (node, &value);
12771 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12773 retval = (gfloat) g_value_get_int64 (&value);
12775 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12777 retval = g_value_get_double (&value);
12779 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12781 ClutterUnits units;
12784 res = clutter_units_from_string (&units, g_value_get_string (&value));
12786 retval = clutter_units_to_pixels (&units);
12789 g_warning ("Invalid value '%s': integers, strings or floating point "
12790 "values can be used for the x, y, width and height "
12791 "properties. Valid modifiers for strings are 'px', 'mm', "
12793 g_value_get_string (&value));
12799 g_warning ("Invalid value of type '%s': integers, strings of floating "
12800 "point values can be used for the x, y, width, height "
12801 "anchor-x and anchor-y properties.",
12802 g_type_name (G_VALUE_TYPE (&value)));
12805 g_value_unset (&value);
12811 ClutterRotateAxis axis;
12820 static inline gboolean
12821 parse_rotation_array (ClutterActor *actor,
12823 RotationInfo *info)
12827 if (json_array_get_length (array) != 2)
12831 element = json_array_get_element (array, 0);
12832 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12833 info->angle = json_node_get_double (element);
12838 element = json_array_get_element (array, 1);
12839 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12841 JsonArray *center = json_node_get_array (element);
12843 if (json_array_get_length (center) != 2)
12846 switch (info->axis)
12848 case CLUTTER_X_AXIS:
12849 info->center_y = parse_units (actor, PARSE_Y,
12850 json_array_get_element (center, 0));
12851 info->center_z = parse_units (actor, PARSE_Y,
12852 json_array_get_element (center, 1));
12855 case CLUTTER_Y_AXIS:
12856 info->center_x = parse_units (actor, PARSE_X,
12857 json_array_get_element (center, 0));
12858 info->center_z = parse_units (actor, PARSE_X,
12859 json_array_get_element (center, 1));
12862 case CLUTTER_Z_AXIS:
12863 info->center_x = parse_units (actor, PARSE_X,
12864 json_array_get_element (center, 0));
12865 info->center_y = parse_units (actor, PARSE_Y,
12866 json_array_get_element (center, 1));
12875 parse_rotation (ClutterActor *actor,
12877 RotationInfo *info)
12881 gboolean retval = FALSE;
12883 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12885 g_warning ("Invalid node of type '%s' found, expecting an array",
12886 json_node_type_name (node));
12890 array = json_node_get_array (node);
12891 len = json_array_get_length (array);
12893 for (i = 0; i < len; i++)
12895 JsonNode *element = json_array_get_element (array, i);
12896 JsonObject *object;
12899 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12901 g_warning ("Invalid node of type '%s' found, expecting an object",
12902 json_node_type_name (element));
12906 object = json_node_get_object (element);
12908 if (json_object_has_member (object, "x-axis"))
12910 member = json_object_get_member (object, "x-axis");
12912 info->axis = CLUTTER_X_AXIS;
12914 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12916 info->angle = json_node_get_double (member);
12919 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12920 retval = parse_rotation_array (actor,
12921 json_node_get_array (member),
12926 else if (json_object_has_member (object, "y-axis"))
12928 member = json_object_get_member (object, "y-axis");
12930 info->axis = CLUTTER_Y_AXIS;
12932 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12934 info->angle = json_node_get_double (member);
12937 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12938 retval = parse_rotation_array (actor,
12939 json_node_get_array (member),
12944 else if (json_object_has_member (object, "z-axis"))
12946 member = json_object_get_member (object, "z-axis");
12948 info->axis = CLUTTER_Z_AXIS;
12950 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12952 info->angle = json_node_get_double (member);
12955 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12956 retval = parse_rotation_array (actor,
12957 json_node_get_array (member),
12968 parse_actor_metas (ClutterScript *script,
12969 ClutterActor *actor,
12972 GList *elements, *l;
12973 GSList *retval = NULL;
12975 if (!JSON_NODE_HOLDS_ARRAY (node))
12978 elements = json_array_get_elements (json_node_get_array (node));
12980 for (l = elements; l != NULL; l = l->next)
12982 JsonNode *element = l->data;
12983 const gchar *id_ = _clutter_script_get_id_from_node (element);
12986 if (id_ == NULL || *id_ == '\0')
12989 meta = clutter_script_get_object (script, id_);
12993 retval = g_slist_prepend (retval, meta);
12996 g_list_free (elements);
12998 return g_slist_reverse (retval);
13002 parse_behaviours (ClutterScript *script,
13003 ClutterActor *actor,
13006 GList *elements, *l;
13007 GSList *retval = NULL;
13009 if (!JSON_NODE_HOLDS_ARRAY (node))
13012 elements = json_array_get_elements (json_node_get_array (node));
13014 for (l = elements; l != NULL; l = l->next)
13016 JsonNode *element = l->data;
13017 const gchar *id_ = _clutter_script_get_id_from_node (element);
13018 GObject *behaviour;
13020 if (id_ == NULL || *id_ == '\0')
13023 behaviour = clutter_script_get_object (script, id_);
13024 if (behaviour == NULL)
13027 retval = g_slist_prepend (retval, behaviour);
13030 g_list_free (elements);
13032 return g_slist_reverse (retval);
13035 static ClutterMargin *
13036 parse_margin (ClutterActor *self,
13039 ClutterMargin *margin;
13042 if (!JSON_NODE_HOLDS_ARRAY (node))
13044 g_warning ("The margin property must be an array of 1 to 4 elements");
13048 margin = clutter_margin_new ();
13049 array = json_node_get_array (node);
13050 switch (json_array_get_length (array))
13053 margin->top = margin->right = margin->bottom = margin->left =
13054 parse_units (self, 0, json_array_get_element (array, 0));
13058 margin->top = margin->bottom =
13059 parse_units (self, 0, json_array_get_element (array, 0));
13060 margin->right = margin->left =
13061 parse_units (self, 0, json_array_get_element (array, 1));
13066 parse_units (self, 0, json_array_get_element (array, 0));
13067 margin->right = margin->left =
13068 parse_units (self, 0, json_array_get_element (array, 1));
13070 parse_units (self, 0, json_array_get_element (array, 2));
13075 parse_units (self, 0, json_array_get_element (array, 0));
13077 parse_units (self, 0, json_array_get_element (array, 1));
13079 parse_units (self, 0, json_array_get_element (array, 2));
13081 parse_units (self, 0, json_array_get_element (array, 3));
13085 g_warning ("The margin property must be an array of 1 to 4 elements");
13086 clutter_margin_free (margin);
13093 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
13094 ClutterScript *script,
13099 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13100 gboolean retval = FALSE;
13102 if ((name[0] == 'x' && name[1] == '\0') ||
13103 (name[0] == 'y' && name[1] == '\0') ||
13104 (strcmp (name, "width") == 0) ||
13105 (strcmp (name, "height") == 0) ||
13106 (strcmp (name, "anchor_x") == 0) ||
13107 (strcmp (name, "anchor_y") == 0))
13109 ParseDimension dimension;
13112 if (name[0] == 'x')
13113 dimension = PARSE_X;
13114 else if (name[0] == 'y')
13115 dimension = PARSE_Y;
13116 else if (name[0] == 'w')
13117 dimension = PARSE_WIDTH;
13118 else if (name[0] == 'h')
13119 dimension = PARSE_HEIGHT;
13120 else if (name[0] == 'a' && name[7] == 'x')
13121 dimension = PARSE_ANCHOR_X;
13122 else if (name[0] == 'a' && name[7] == 'y')
13123 dimension = PARSE_ANCHOR_Y;
13127 units = parse_units (actor, dimension, node);
13129 /* convert back to pixels: all properties are pixel-based */
13130 g_value_init (value, G_TYPE_FLOAT);
13131 g_value_set_float (value, units);
13135 else if (strcmp (name, "rotation") == 0)
13137 RotationInfo *info;
13139 info = g_slice_new0 (RotationInfo);
13140 retval = parse_rotation (actor, node, info);
13144 g_value_init (value, G_TYPE_POINTER);
13145 g_value_set_pointer (value, info);
13148 g_slice_free (RotationInfo, info);
13150 else if (strcmp (name, "behaviours") == 0)
13154 #ifdef CLUTTER_ENABLE_DEBUG
13155 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13156 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13157 "and it should not be used in newly "
13158 "written ClutterScript definitions.");
13161 l = parse_behaviours (script, actor, node);
13163 g_value_init (value, G_TYPE_POINTER);
13164 g_value_set_pointer (value, l);
13168 else if (strcmp (name, "actions") == 0 ||
13169 strcmp (name, "constraints") == 0 ||
13170 strcmp (name, "effects") == 0)
13174 l = parse_actor_metas (script, actor, node);
13176 g_value_init (value, G_TYPE_POINTER);
13177 g_value_set_pointer (value, l);
13181 else if (strcmp (name, "margin") == 0)
13183 ClutterMargin *margin = parse_margin (actor, node);
13187 g_value_init (value, CLUTTER_TYPE_MARGIN);
13188 g_value_set_boxed (value, margin);
13197 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13198 ClutterScript *script,
13200 const GValue *value)
13202 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13204 #ifdef CLUTTER_ENABLE_DEBUG
13205 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13207 gchar *tmp = g_strdup_value_contents (value);
13209 CLUTTER_NOTE (SCRIPT,
13210 "in ClutterActor::set_custom_property('%s') = %s",
13216 #endif /* CLUTTER_ENABLE_DEBUG */
13218 if (strcmp (name, "rotation") == 0)
13220 RotationInfo *info;
13222 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13225 info = g_value_get_pointer (value);
13227 clutter_actor_set_rotation (actor,
13228 info->axis, info->angle,
13233 g_slice_free (RotationInfo, info);
13238 if (strcmp (name, "behaviours") == 0)
13240 GSList *behaviours, *l;
13242 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13245 behaviours = g_value_get_pointer (value);
13246 for (l = behaviours; l != NULL; l = l->next)
13248 ClutterBehaviour *behaviour = l->data;
13250 clutter_behaviour_apply (behaviour, actor);
13253 g_slist_free (behaviours);
13258 if (strcmp (name, "actions") == 0 ||
13259 strcmp (name, "constraints") == 0 ||
13260 strcmp (name, "effects") == 0)
13264 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13267 metas = g_value_get_pointer (value);
13268 for (l = metas; l != NULL; l = l->next)
13270 if (name[0] == 'a')
13271 clutter_actor_add_action (actor, l->data);
13273 if (name[0] == 'c')
13274 clutter_actor_add_constraint (actor, l->data);
13276 if (name[0] == 'e')
13277 clutter_actor_add_effect (actor, l->data);
13280 g_slist_free (metas);
13284 if (strcmp (name, "margin") == 0)
13286 clutter_actor_set_margin (actor, g_value_get_boxed (value));
13290 g_object_set_property (G_OBJECT (scriptable), name, value);
13294 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13296 iface->parse_custom_node = clutter_actor_parse_custom_node;
13297 iface->set_custom_property = clutter_actor_set_custom_property;
13300 static ClutterActorMeta *
13301 get_meta_from_animation_property (ClutterActor *actor,
13305 ClutterActorPrivate *priv = actor->priv;
13306 ClutterActorMeta *meta = NULL;
13309 /* if this is not a special property, fall through */
13310 if (name[0] != '@')
13313 /* detect the properties named using the following spec:
13315 * @<section>.<meta-name>.<property-name>
13317 * where <section> can be one of the following:
13323 * and <meta-name> is the name set on a specific ActorMeta
13326 tokens = g_strsplit (name + 1, ".", -1);
13327 if (tokens == NULL || g_strv_length (tokens) != 3)
13329 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13331 g_strfreev (tokens);
13335 if (strcmp (tokens[0], "actions") == 0)
13336 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13338 if (strcmp (tokens[0], "constraints") == 0)
13339 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13341 if (strcmp (tokens[0], "effects") == 0)
13342 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13344 if (name_p != NULL)
13345 *name_p = g_strdup (tokens[2]);
13347 CLUTTER_NOTE (ANIMATION,
13348 "Looking for property '%s' of object '%s' in section '%s'",
13353 g_strfreev (tokens);
13358 static GParamSpec *
13359 clutter_actor_find_property (ClutterAnimatable *animatable,
13360 const gchar *property_name)
13362 ClutterActorMeta *meta = NULL;
13363 GObjectClass *klass = NULL;
13364 GParamSpec *pspec = NULL;
13365 gchar *p_name = NULL;
13367 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13373 klass = G_OBJECT_GET_CLASS (meta);
13375 pspec = g_object_class_find_property (klass, p_name);
13379 klass = G_OBJECT_GET_CLASS (animatable);
13381 pspec = g_object_class_find_property (klass, property_name);
13390 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13391 const gchar *property_name,
13394 ClutterActorMeta *meta = NULL;
13395 gchar *p_name = NULL;
13397 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13402 g_object_get_property (G_OBJECT (meta), p_name, initial);
13404 g_object_get_property (G_OBJECT (animatable), property_name, initial);
13410 * clutter_actor_set_animatable_property:
13411 * @actor: a #ClutterActor
13412 * @prop_id: the paramspec id
13413 * @value: the value to set
13414 * @pspec: the paramspec
13416 * Sets values of animatable properties.
13418 * This is a variant of clutter_actor_set_property() that gets called
13419 * by the #ClutterAnimatable implementation of #ClutterActor for the
13420 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13423 * Unlike the implementation of #GObjectClass.set_property(), this
13424 * function will not update the interval if a transition involving an
13425 * animatable property is in progress - this avoids cycles with the
13426 * transition API calling the public API.
13429 clutter_actor_set_animatable_property (ClutterActor *actor,
13431 const GValue *value,
13434 GObject *obj = G_OBJECT (actor);
13436 g_object_freeze_notify (obj);
13441 clutter_actor_set_x_internal (actor, g_value_get_float (value));
13445 clutter_actor_set_y_internal (actor, g_value_get_float (value));
13448 case PROP_POSITION:
13449 clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13453 clutter_actor_set_width_internal (actor, g_value_get_float (value));
13457 clutter_actor_set_height_internal (actor, g_value_get_float (value));
13461 clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13464 case PROP_ALLOCATION:
13465 clutter_actor_allocate_internal (actor,
13466 g_value_get_boxed (value),
13467 actor->priv->allocation_flags);
13471 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13475 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13478 case PROP_BACKGROUND_COLOR:
13479 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13483 clutter_actor_set_scale_factor_internal (actor,
13484 g_value_get_double (value),
13489 clutter_actor_set_scale_factor_internal (actor,
13490 g_value_get_double (value),
13494 case PROP_ROTATION_ANGLE_X:
13495 clutter_actor_set_rotation_angle_internal (actor,
13497 g_value_get_double (value));
13500 case PROP_ROTATION_ANGLE_Y:
13501 clutter_actor_set_rotation_angle_internal (actor,
13503 g_value_get_double (value));
13506 case PROP_ROTATION_ANGLE_Z:
13507 clutter_actor_set_rotation_angle_internal (actor,
13509 g_value_get_double (value));
13512 case PROP_CONTENT_BOX:
13513 clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13517 g_object_set_property (obj, pspec->name, value);
13521 g_object_thaw_notify (obj);
13525 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13526 const gchar *property_name,
13527 const GValue *final)
13529 ClutterActor *actor = CLUTTER_ACTOR (animatable);
13530 ClutterActorMeta *meta = NULL;
13531 gchar *p_name = NULL;
13533 meta = get_meta_from_animation_property (actor,
13537 g_object_set_property (G_OBJECT (meta), p_name, final);
13540 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13543 pspec = g_object_class_find_property (obj_class, property_name);
13545 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13547 /* XXX - I'm going to the special hell for this */
13548 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13551 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13558 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13560 iface->find_property = clutter_actor_find_property;
13561 iface->get_initial_state = clutter_actor_get_initial_state;
13562 iface->set_final_state = clutter_actor_set_final_state;
13566 * clutter_actor_transform_stage_point:
13567 * @self: A #ClutterActor
13568 * @x: (in): x screen coordinate of the point to unproject
13569 * @y: (in): y screen coordinate of the point to unproject
13570 * @x_out: (out): return location for the unprojected x coordinance
13571 * @y_out: (out): return location for the unprojected y coordinance
13573 * This function translates screen coordinates (@x, @y) to
13574 * coordinates relative to the actor. For example, it can be used to translate
13575 * screen events from global screen coordinates into actor-local coordinates.
13577 * The conversion can fail, notably if the transform stack results in the
13578 * actor being projected on the screen as a mere line.
13580 * The conversion should not be expected to be pixel-perfect due to the
13581 * nature of the operation. In general the error grows when the skewing
13582 * of the actor rectangle on screen increases.
13584 * <note><para>This function can be computationally intensive.</para></note>
13586 * <note><para>This function only works when the allocation is up-to-date,
13587 * i.e. inside of paint().</para></note>
13589 * Return value: %TRUE if conversion was successful.
13594 clutter_actor_transform_stage_point (ClutterActor *self,
13600 ClutterVertex v[4];
13603 int du, dv, xi, yi;
13605 float xf, yf, wf, det;
13606 ClutterActorPrivate *priv;
13608 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13612 /* This implementation is based on the quad -> quad projection algorithm
13613 * described by Paul Heckbert in:
13615 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13617 * and the sample implementation at:
13619 * http://www.cs.cmu.edu/~ph/src/texfund/
13621 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13622 * quad to rectangle only, which significantly simplifies things; the
13623 * function calls have been unrolled, and most of the math is done in fixed
13627 clutter_actor_get_abs_allocation_vertices (self, v);
13629 /* Keeping these as ints simplifies the multiplication (no significant
13630 * loss of precision here).
13632 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13633 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13638 #define UX2FP(x) (x)
13639 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13641 /* First, find mapping from unit uv square to xy quadrilateral; this
13642 * equivalent to the pmap_square_quad() functions in the sample
13643 * implementation, which we can simplify, since our target is always
13646 px = v[0].x - v[1].x + v[3].x - v[2].x;
13647 py = v[0].y - v[1].y + v[3].y - v[2].y;
13651 /* affine transform */
13652 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13653 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13654 RQ[2][0] = UX2FP (v[0].x);
13655 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13656 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13657 RQ[2][1] = UX2FP (v[0].y);
13664 /* projective transform */
13665 double dx1, dx2, dy1, dy2, del;
13667 dx1 = UX2FP (v[1].x - v[3].x);
13668 dx2 = UX2FP (v[2].x - v[3].x);
13669 dy1 = UX2FP (v[1].y - v[3].y);
13670 dy2 = UX2FP (v[2].y - v[3].y);
13672 del = DET2FP (dx1, dx2, dy1, dy2);
13677 * The division here needs to be done in floating point for
13678 * precisions reasons.
13680 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13681 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13682 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13684 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13685 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13686 RQ[2][0] = UX2FP (v[0].x);
13687 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13688 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13689 RQ[2][1] = UX2FP (v[0].y);
13693 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13694 * square. Since our rectangle is based at 0,0 we only need to scale.
13704 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13707 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13708 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13709 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13710 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13711 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13712 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13713 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13714 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13715 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13718 * Check the resulting matrix is OK.
13720 det = (RQ[0][0] * ST[0][0])
13721 + (RQ[0][1] * ST[0][1])
13722 + (RQ[0][2] * ST[0][2]);
13727 * Now transform our point with the ST matrix; the notional w
13728 * coordinate is 1, hence the last part is simply added.
13733 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13734 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13735 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13750 * clutter_actor_is_rotated:
13751 * @self: a #ClutterActor
13753 * Checks whether any rotation is applied to the actor.
13755 * Return value: %TRUE if the actor is rotated.
13760 clutter_actor_is_rotated (ClutterActor *self)
13762 const ClutterTransformInfo *info;
13764 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13766 info = _clutter_actor_get_transform_info_or_defaults (self);
13768 if (info->rx_angle || info->ry_angle || info->rz_angle)
13775 * clutter_actor_is_scaled:
13776 * @self: a #ClutterActor
13778 * Checks whether the actor is scaled in either dimension.
13780 * Return value: %TRUE if the actor is scaled.
13785 clutter_actor_is_scaled (ClutterActor *self)
13787 const ClutterTransformInfo *info;
13789 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13791 info = _clutter_actor_get_transform_info_or_defaults (self);
13793 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13800 _clutter_actor_get_stage_internal (ClutterActor *actor)
13802 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13803 actor = actor->priv->parent;
13809 * clutter_actor_get_stage:
13810 * @actor: a #ClutterActor
13812 * Retrieves the #ClutterStage where @actor is contained.
13814 * Return value: (transfer none) (type Clutter.Stage): the stage
13815 * containing the actor, or %NULL
13820 clutter_actor_get_stage (ClutterActor *actor)
13822 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13824 return _clutter_actor_get_stage_internal (actor);
13828 * clutter_actor_allocate_available_size:
13829 * @self: a #ClutterActor
13830 * @x: the actor's X coordinate
13831 * @y: the actor's Y coordinate
13832 * @available_width: the maximum available width, or -1 to use the
13833 * actor's natural width
13834 * @available_height: the maximum available height, or -1 to use the
13835 * actor's natural height
13836 * @flags: flags controlling the allocation
13838 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13839 * preferred size, but limiting it to the maximum available width
13840 * and height provided.
13842 * This function will do the right thing when dealing with the
13843 * actor's request mode.
13845 * The implementation of this function is equivalent to:
13848 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13850 * clutter_actor_get_preferred_width (self, available_height,
13852 * &natural_width);
13853 * width = CLAMP (natural_width, min_width, available_width);
13855 * clutter_actor_get_preferred_height (self, width,
13857 * &natural_height);
13858 * height = CLAMP (natural_height, min_height, available_height);
13862 * clutter_actor_get_preferred_height (self, available_width,
13864 * &natural_height);
13865 * height = CLAMP (natural_height, min_height, available_height);
13867 * clutter_actor_get_preferred_width (self, height,
13869 * &natural_width);
13870 * width = CLAMP (natural_width, min_width, available_width);
13873 * box.x1 = x; box.y1 = y;
13874 * box.x2 = box.x1 + available_width;
13875 * box.y2 = box.y1 + available_height;
13876 * clutter_actor_allocate (self, &box, flags);
13879 * This function can be used by fluid layout managers to allocate
13880 * an actor's preferred size without making it bigger than the area
13881 * available for the container.
13886 clutter_actor_allocate_available_size (ClutterActor *self,
13889 gfloat available_width,
13890 gfloat available_height,
13891 ClutterAllocationFlags flags)
13893 ClutterActorPrivate *priv;
13894 gfloat width, height;
13895 gfloat min_width, min_height;
13896 gfloat natural_width, natural_height;
13897 ClutterActorBox box;
13899 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13903 width = height = 0.0;
13905 switch (priv->request_mode)
13907 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13908 clutter_actor_get_preferred_width (self, available_height,
13911 width = CLAMP (natural_width, min_width, available_width);
13913 clutter_actor_get_preferred_height (self, width,
13916 height = CLAMP (natural_height, min_height, available_height);
13919 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13920 clutter_actor_get_preferred_height (self, available_width,
13923 height = CLAMP (natural_height, min_height, available_height);
13925 clutter_actor_get_preferred_width (self, height,
13928 width = CLAMP (natural_width, min_width, available_width);
13935 box.x2 = box.x1 + width;
13936 box.y2 = box.y1 + height;
13937 clutter_actor_allocate (self, &box, flags);
13941 * clutter_actor_allocate_preferred_size:
13942 * @self: a #ClutterActor
13943 * @flags: flags controlling the allocation
13945 * Allocates the natural size of @self.
13947 * This function is a utility call for #ClutterActor implementations
13948 * that allocates the actor's preferred natural size. It can be used
13949 * by fixed layout managers (like #ClutterGroup or so called
13950 * 'composite actors') inside the ClutterActor::allocate
13951 * implementation to give each child exactly how much space it
13954 * This function is not meant to be used by applications. It is also
13955 * not meant to be used outside the implementation of the
13956 * ClutterActor::allocate virtual function.
13961 clutter_actor_allocate_preferred_size (ClutterActor *self,
13962 ClutterAllocationFlags flags)
13964 gfloat actor_x, actor_y;
13965 gfloat natural_width, natural_height;
13966 ClutterActorBox actor_box;
13968 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13970 actor_x = clutter_actor_get_x (self);
13971 actor_y = clutter_actor_get_y (self);
13973 clutter_actor_get_preferred_size (self,
13978 actor_box.x1 = actor_x;
13979 actor_box.y1 = actor_y;
13980 actor_box.x2 = actor_box.x1 + natural_width;
13981 actor_box.y2 = actor_box.y1 + natural_height;
13983 clutter_actor_allocate (self, &actor_box, flags);
13987 * clutter_actor_allocate_align_fill:
13988 * @self: a #ClutterActor
13989 * @box: a #ClutterActorBox, containing the available width and height
13990 * @x_align: the horizontal alignment, between 0 and 1
13991 * @y_align: the vertical alignment, between 0 and 1
13992 * @x_fill: whether the actor should fill horizontally
13993 * @y_fill: whether the actor should fill vertically
13994 * @flags: allocation flags to be passed to clutter_actor_allocate()
13996 * Allocates @self by taking into consideration the available allocation
13997 * area; an alignment factor on either axis; and whether the actor should
13998 * fill the allocation on either axis.
14000 * The @box should contain the available allocation width and height;
14001 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
14002 * allocation will be offset by their value.
14004 * This function takes into consideration the geometry request specified by
14005 * the #ClutterActor:request-mode property, and the text direction.
14007 * This function is useful for fluid layout managers, like #ClutterBinLayout
14008 * or #ClutterTableLayout
14013 clutter_actor_allocate_align_fill (ClutterActor *self,
14014 const ClutterActorBox *box,
14019 ClutterAllocationFlags flags)
14021 ClutterActorPrivate *priv;
14022 ClutterActorBox allocation = { 0, };
14023 gfloat x_offset, y_offset;
14024 gfloat available_width, available_height;
14025 gfloat child_width, child_height;
14027 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14028 g_return_if_fail (box != NULL);
14029 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
14030 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
14034 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
14035 clutter_actor_box_get_size (box, &available_width, &available_height);
14037 if (available_width < 0)
14038 available_width = 0;
14040 if (available_height < 0)
14041 available_height = 0;
14045 allocation.x1 = x_offset;
14046 allocation.x2 = allocation.x1 + available_width;
14051 allocation.y1 = y_offset;
14052 allocation.y2 = allocation.y1 + available_height;
14055 /* if we are filling horizontally and vertically then we're done */
14056 if (x_fill && y_fill)
14059 child_width = child_height = 0.0f;
14061 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
14063 gfloat min_width, natural_width;
14064 gfloat min_height, natural_height;
14066 clutter_actor_get_preferred_width (self, available_height,
14070 child_width = CLAMP (natural_width, min_width, available_width);
14074 clutter_actor_get_preferred_height (self, child_width,
14078 child_height = CLAMP (natural_height, min_height, available_height);
14083 gfloat min_width, natural_width;
14084 gfloat min_height, natural_height;
14086 clutter_actor_get_preferred_height (self, available_width,
14090 child_height = CLAMP (natural_height, min_height, available_height);
14094 clutter_actor_get_preferred_width (self, child_height,
14098 child_width = CLAMP (natural_width, min_width, available_width);
14102 /* invert the horizontal alignment for RTL languages */
14103 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
14104 x_align = 1.0 - x_align;
14108 allocation.x1 = x_offset
14109 + ((available_width - child_width) * x_align);
14110 allocation.x2 = allocation.x1 + child_width;
14115 allocation.y1 = y_offset
14116 + ((available_height - child_height) * y_align);
14117 allocation.y2 = allocation.y1 + child_height;
14121 clutter_actor_box_clamp_to_pixel (&allocation);
14122 clutter_actor_allocate (self, &allocation, flags);
14126 * clutter_actor_grab_key_focus:
14127 * @self: a #ClutterActor
14129 * Sets the key focus of the #ClutterStage including @self
14130 * to this #ClutterActor.
14135 clutter_actor_grab_key_focus (ClutterActor *self)
14137 ClutterActor *stage;
14139 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14141 stage = _clutter_actor_get_stage_internal (self);
14143 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14147 * clutter_actor_get_pango_context:
14148 * @self: a #ClutterActor
14150 * Retrieves the #PangoContext for @self. The actor's #PangoContext
14151 * is already configured using the appropriate font map, resolution
14152 * and font options.
14154 * Unlike clutter_actor_create_pango_context(), this context is owend
14155 * by the #ClutterActor and it will be updated each time the options
14156 * stored by the #ClutterBackend change.
14158 * You can use the returned #PangoContext to create a #PangoLayout
14159 * and render text using cogl_pango_render_layout() to reuse the
14160 * glyphs cache also used by Clutter.
14162 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14163 * The returned #PangoContext is owned by the actor and should not be
14164 * unreferenced by the application code
14169 clutter_actor_get_pango_context (ClutterActor *self)
14171 ClutterActorPrivate *priv;
14173 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14177 if (priv->pango_context != NULL)
14178 return priv->pango_context;
14180 priv->pango_context = _clutter_context_get_pango_context ();
14181 g_object_ref (priv->pango_context);
14183 return priv->pango_context;
14187 * clutter_actor_create_pango_context:
14188 * @self: a #ClutterActor
14190 * Creates a #PangoContext for the given actor. The #PangoContext
14191 * is already configured using the appropriate font map, resolution
14192 * and font options.
14194 * See also clutter_actor_get_pango_context().
14196 * Return value: (transfer full): the newly created #PangoContext.
14197 * Use g_object_unref() on the returned value to deallocate its
14203 clutter_actor_create_pango_context (ClutterActor *self)
14205 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14207 return _clutter_context_create_pango_context ();
14211 * clutter_actor_create_pango_layout:
14212 * @self: a #ClutterActor
14213 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14215 * Creates a new #PangoLayout from the same #PangoContext used
14216 * by the #ClutterActor. The #PangoLayout is already configured
14217 * with the font map, resolution and font options, and the
14220 * If you want to keep around a #PangoLayout created by this
14221 * function you will have to connect to the #ClutterBackend::font-changed
14222 * and #ClutterBackend::resolution-changed signals, and call
14223 * pango_layout_context_changed() in response to them.
14225 * Return value: (transfer full): the newly created #PangoLayout.
14226 * Use g_object_unref() when done
14231 clutter_actor_create_pango_layout (ClutterActor *self,
14234 PangoContext *context;
14235 PangoLayout *layout;
14237 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14239 context = clutter_actor_get_pango_context (self);
14240 layout = pango_layout_new (context);
14243 pango_layout_set_text (layout, text, -1);
14248 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14249 * ClutterOffscreenEffect.
14252 _clutter_actor_set_opacity_override (ClutterActor *self,
14255 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14257 self->priv->opacity_override = opacity;
14261 _clutter_actor_get_opacity_override (ClutterActor *self)
14263 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14265 return self->priv->opacity_override;
14268 /* Allows you to disable applying the actors model view transform during
14269 * a paint. Used by ClutterClone. */
14271 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14274 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14276 self->priv->enable_model_view_transform = enable;
14280 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14283 ClutterActorPrivate *priv;
14285 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14289 priv->enable_paint_unmapped = enable;
14291 if (priv->enable_paint_unmapped)
14293 /* Make sure that the parents of the widget are realized first;
14294 * otherwise checks in clutter_actor_update_map_state() will
14297 clutter_actor_realize (self);
14299 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14303 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14308 clutter_anchor_coord_get_units (ClutterActor *self,
14309 const AnchorCoord *coord,
14314 if (coord->is_fractional)
14316 gfloat actor_width, actor_height;
14318 clutter_actor_get_size (self, &actor_width, &actor_height);
14321 *x = actor_width * coord->v.fraction.x;
14324 *y = actor_height * coord->v.fraction.y;
14332 *x = coord->v.units.x;
14335 *y = coord->v.units.y;
14338 *z = coord->v.units.z;
14343 clutter_anchor_coord_set_units (AnchorCoord *coord,
14348 coord->is_fractional = FALSE;
14349 coord->v.units.x = x;
14350 coord->v.units.y = y;
14351 coord->v.units.z = z;
14354 static ClutterGravity
14355 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14357 if (coord->is_fractional)
14359 if (coord->v.fraction.x == 0.0)
14361 if (coord->v.fraction.y == 0.0)
14362 return CLUTTER_GRAVITY_NORTH_WEST;
14363 else if (coord->v.fraction.y == 0.5)
14364 return CLUTTER_GRAVITY_WEST;
14365 else if (coord->v.fraction.y == 1.0)
14366 return CLUTTER_GRAVITY_SOUTH_WEST;
14368 return CLUTTER_GRAVITY_NONE;
14370 else if (coord->v.fraction.x == 0.5)
14372 if (coord->v.fraction.y == 0.0)
14373 return CLUTTER_GRAVITY_NORTH;
14374 else if (coord->v.fraction.y == 0.5)
14375 return CLUTTER_GRAVITY_CENTER;
14376 else if (coord->v.fraction.y == 1.0)
14377 return CLUTTER_GRAVITY_SOUTH;
14379 return CLUTTER_GRAVITY_NONE;
14381 else if (coord->v.fraction.x == 1.0)
14383 if (coord->v.fraction.y == 0.0)
14384 return CLUTTER_GRAVITY_NORTH_EAST;
14385 else if (coord->v.fraction.y == 0.5)
14386 return CLUTTER_GRAVITY_EAST;
14387 else if (coord->v.fraction.y == 1.0)
14388 return CLUTTER_GRAVITY_SOUTH_EAST;
14390 return CLUTTER_GRAVITY_NONE;
14393 return CLUTTER_GRAVITY_NONE;
14396 return CLUTTER_GRAVITY_NONE;
14400 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14401 ClutterGravity gravity)
14405 case CLUTTER_GRAVITY_NORTH:
14406 coord->v.fraction.x = 0.5;
14407 coord->v.fraction.y = 0.0;
14410 case CLUTTER_GRAVITY_NORTH_EAST:
14411 coord->v.fraction.x = 1.0;
14412 coord->v.fraction.y = 0.0;
14415 case CLUTTER_GRAVITY_EAST:
14416 coord->v.fraction.x = 1.0;
14417 coord->v.fraction.y = 0.5;
14420 case CLUTTER_GRAVITY_SOUTH_EAST:
14421 coord->v.fraction.x = 1.0;
14422 coord->v.fraction.y = 1.0;
14425 case CLUTTER_GRAVITY_SOUTH:
14426 coord->v.fraction.x = 0.5;
14427 coord->v.fraction.y = 1.0;
14430 case CLUTTER_GRAVITY_SOUTH_WEST:
14431 coord->v.fraction.x = 0.0;
14432 coord->v.fraction.y = 1.0;
14435 case CLUTTER_GRAVITY_WEST:
14436 coord->v.fraction.x = 0.0;
14437 coord->v.fraction.y = 0.5;
14440 case CLUTTER_GRAVITY_NORTH_WEST:
14441 coord->v.fraction.x = 0.0;
14442 coord->v.fraction.y = 0.0;
14445 case CLUTTER_GRAVITY_CENTER:
14446 coord->v.fraction.x = 0.5;
14447 coord->v.fraction.y = 0.5;
14451 coord->v.fraction.x = 0.0;
14452 coord->v.fraction.y = 0.0;
14456 coord->is_fractional = TRUE;
14460 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14462 if (coord->is_fractional)
14463 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14465 return (coord->v.units.x == 0.0
14466 && coord->v.units.y == 0.0
14467 && coord->v.units.z == 0.0);
14471 * clutter_actor_get_flags:
14472 * @self: a #ClutterActor
14474 * Retrieves the flags set on @self
14476 * Return value: a bitwise or of #ClutterActorFlags or 0
14481 clutter_actor_get_flags (ClutterActor *self)
14483 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14485 return self->flags;
14489 * clutter_actor_set_flags:
14490 * @self: a #ClutterActor
14491 * @flags: the flags to set
14493 * Sets @flags on @self
14495 * This function will emit notifications for the changed properties
14500 clutter_actor_set_flags (ClutterActor *self,
14501 ClutterActorFlags flags)
14503 ClutterActorFlags old_flags;
14505 gboolean was_reactive_set, reactive_set;
14506 gboolean was_realized_set, realized_set;
14507 gboolean was_mapped_set, mapped_set;
14508 gboolean was_visible_set, visible_set;
14510 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14512 if (self->flags == flags)
14515 obj = G_OBJECT (self);
14516 g_object_ref (obj);
14517 g_object_freeze_notify (obj);
14519 old_flags = self->flags;
14521 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14522 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14523 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14524 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14526 self->flags |= flags;
14528 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14529 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14530 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14531 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14533 if (reactive_set != was_reactive_set)
14534 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14536 if (realized_set != was_realized_set)
14537 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14539 if (mapped_set != was_mapped_set)
14540 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14542 if (visible_set != was_visible_set)
14543 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14545 g_object_thaw_notify (obj);
14546 g_object_unref (obj);
14550 * clutter_actor_unset_flags:
14551 * @self: a #ClutterActor
14552 * @flags: the flags to unset
14554 * Unsets @flags on @self
14556 * This function will emit notifications for the changed properties
14561 clutter_actor_unset_flags (ClutterActor *self,
14562 ClutterActorFlags flags)
14564 ClutterActorFlags old_flags;
14566 gboolean was_reactive_set, reactive_set;
14567 gboolean was_realized_set, realized_set;
14568 gboolean was_mapped_set, mapped_set;
14569 gboolean was_visible_set, visible_set;
14571 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14573 obj = G_OBJECT (self);
14574 g_object_freeze_notify (obj);
14576 old_flags = self->flags;
14578 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14579 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14580 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14581 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14583 self->flags &= ~flags;
14585 if (self->flags == old_flags)
14588 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14589 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14590 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14591 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14593 if (reactive_set != was_reactive_set)
14594 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14596 if (realized_set != was_realized_set)
14597 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14599 if (mapped_set != was_mapped_set)
14600 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14602 if (visible_set != was_visible_set)
14603 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14605 g_object_thaw_notify (obj);
14609 * clutter_actor_get_transformation_matrix:
14610 * @self: a #ClutterActor
14611 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14613 * Retrieves the transformations applied to @self relative to its
14619 clutter_actor_get_transformation_matrix (ClutterActor *self,
14620 CoglMatrix *matrix)
14622 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14624 cogl_matrix_init_identity (matrix);
14626 _clutter_actor_apply_modelview_transform (self, matrix);
14630 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14631 gboolean is_in_clone_paint)
14633 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14634 self->priv->in_clone_paint = is_in_clone_paint;
14638 * clutter_actor_is_in_clone_paint:
14639 * @self: a #ClutterActor
14641 * Checks whether @self is being currently painted by a #ClutterClone
14643 * This function is useful only inside the ::paint virtual function
14644 * implementations or within handlers for the #ClutterActor::paint
14647 * This function should not be used by applications
14649 * Return value: %TRUE if the #ClutterActor is currently being painted
14650 * by a #ClutterClone, and %FALSE otherwise
14655 clutter_actor_is_in_clone_paint (ClutterActor *self)
14657 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14659 return self->priv->in_clone_paint;
14663 set_direction_recursive (ClutterActor *actor,
14664 gpointer user_data)
14666 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14668 clutter_actor_set_text_direction (actor, text_dir);
14674 * clutter_actor_set_text_direction:
14675 * @self: a #ClutterActor
14676 * @text_dir: the text direction for @self
14678 * Sets the #ClutterTextDirection for an actor
14680 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14682 * If @self implements #ClutterContainer then this function will recurse
14683 * inside all the children of @self (including the internal ones).
14685 * Composite actors not implementing #ClutterContainer, or actors requiring
14686 * special handling when the text direction changes, should connect to
14687 * the #GObject::notify signal for the #ClutterActor:text-direction property
14692 clutter_actor_set_text_direction (ClutterActor *self,
14693 ClutterTextDirection text_dir)
14695 ClutterActorPrivate *priv;
14697 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14698 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14702 if (priv->text_direction != text_dir)
14704 priv->text_direction = text_dir;
14706 /* we need to emit the notify::text-direction first, so that
14707 * the sub-classes can catch that and do specific handling of
14708 * the text direction; see clutter_text_direction_changed_cb()
14709 * inside clutter-text.c
14711 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14713 _clutter_actor_foreach_child (self, set_direction_recursive,
14714 GINT_TO_POINTER (text_dir));
14716 clutter_actor_queue_relayout (self);
14721 _clutter_actor_set_has_pointer (ClutterActor *self,
14722 gboolean has_pointer)
14724 ClutterActorPrivate *priv = self->priv;
14726 if (priv->has_pointer != has_pointer)
14728 priv->has_pointer = has_pointer;
14730 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14735 * clutter_actor_get_text_direction:
14736 * @self: a #ClutterActor
14738 * Retrieves the value set using clutter_actor_set_text_direction()
14740 * If no text direction has been previously set, the default text
14741 * direction, as returned by clutter_get_default_text_direction(), will
14742 * be returned instead
14744 * Return value: the #ClutterTextDirection for the actor
14748 ClutterTextDirection
14749 clutter_actor_get_text_direction (ClutterActor *self)
14751 ClutterActorPrivate *priv;
14753 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14754 CLUTTER_TEXT_DIRECTION_LTR);
14758 /* if no direction has been set yet use the default */
14759 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14760 priv->text_direction = clutter_get_default_text_direction ();
14762 return priv->text_direction;
14766 * clutter_actor_push_internal:
14767 * @self: a #ClutterActor
14769 * Should be used by actors implementing the #ClutterContainer and with
14770 * internal children added through clutter_actor_set_parent(), for instance:
14774 * my_actor_init (MyActor *self)
14776 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14778 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14780 * /* calling clutter_actor_set_parent() now will result in
14781 * * the internal flag being set on a child of MyActor
14784 * /* internal child - a background texture */
14785 * self->priv->background_tex = clutter_texture_new ();
14786 * clutter_actor_set_parent (self->priv->background_tex,
14787 * CLUTTER_ACTOR (self));
14789 * /* internal child - a label */
14790 * self->priv->label = clutter_text_new ();
14791 * clutter_actor_set_parent (self->priv->label,
14792 * CLUTTER_ACTOR (self));
14794 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14796 * /* calling clutter_actor_set_parent() now will not result in
14797 * * the internal flag being set on a child of MyActor
14802 * This function will be used by Clutter to toggle an "internal child"
14803 * flag whenever clutter_actor_set_parent() is called; internal children
14804 * are handled differently by Clutter, specifically when destroying their
14807 * Call clutter_actor_pop_internal() when you finished adding internal
14810 * Nested calls to clutter_actor_push_internal() are allowed, but each
14811 * one must by followed by a clutter_actor_pop_internal() call.
14815 * Deprecated: 1.10: All children of an actor are accessible through
14816 * the #ClutterActor API, and #ClutterActor implements the
14817 * #ClutterContainer interface, so this function is only useful
14818 * for legacy containers overriding the default implementation.
14821 clutter_actor_push_internal (ClutterActor *self)
14823 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14825 self->priv->internal_child += 1;
14829 * clutter_actor_pop_internal:
14830 * @self: a #ClutterActor
14832 * Disables the effects of clutter_actor_push_internal().
14836 * Deprecated: 1.10: All children of an actor are accessible through
14837 * the #ClutterActor API. This function is only useful for legacy
14838 * containers overriding the default implementation of the
14839 * #ClutterContainer interface.
14842 clutter_actor_pop_internal (ClutterActor *self)
14844 ClutterActorPrivate *priv;
14846 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14850 if (priv->internal_child == 0)
14852 g_warning ("Mismatched %s: you need to call "
14853 "clutter_actor_push_composite() at least once before "
14854 "calling this function", G_STRFUNC);
14858 priv->internal_child -= 1;
14862 * clutter_actor_has_pointer:
14863 * @self: a #ClutterActor
14865 * Checks whether an actor contains the pointer of a
14866 * #ClutterInputDevice
14868 * Return value: %TRUE if the actor contains the pointer, and
14874 clutter_actor_has_pointer (ClutterActor *self)
14876 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14878 return self->priv->has_pointer;
14881 /* XXX: This is a workaround for not being able to break the ABI of
14882 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14883 * clutter_actor_queue_clipped_redraw() for details.
14885 ClutterPaintVolume *
14886 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14888 return g_object_get_data (G_OBJECT (self),
14889 "-clutter-actor-queue-redraw-clip");
14893 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14894 ClutterPaintVolume *clip)
14896 g_object_set_data (G_OBJECT (self),
14897 "-clutter-actor-queue-redraw-clip",
14902 * clutter_actor_has_allocation:
14903 * @self: a #ClutterActor
14905 * Checks if the actor has an up-to-date allocation assigned to
14906 * it. This means that the actor should have an allocation: it's
14907 * visible and has a parent. It also means that there is no
14908 * outstanding relayout request in progress for the actor or its
14909 * children (There might be other outstanding layout requests in
14910 * progress that will cause the actor to get a new allocation
14911 * when the stage is laid out, however).
14913 * If this function returns %FALSE, then the actor will normally
14914 * be allocated before it is next drawn on the screen.
14916 * Return value: %TRUE if the actor has an up-to-date allocation
14921 clutter_actor_has_allocation (ClutterActor *self)
14923 ClutterActorPrivate *priv;
14925 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14929 return priv->parent != NULL &&
14930 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14931 !priv->needs_allocation;
14935 * clutter_actor_add_action:
14936 * @self: a #ClutterActor
14937 * @action: a #ClutterAction
14939 * Adds @action to the list of actions applied to @self
14941 * A #ClutterAction can only belong to one actor at a time
14943 * The #ClutterActor will hold a reference on @action until either
14944 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14950 clutter_actor_add_action (ClutterActor *self,
14951 ClutterAction *action)
14953 ClutterActorPrivate *priv;
14955 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14956 g_return_if_fail (CLUTTER_IS_ACTION (action));
14960 if (priv->actions == NULL)
14962 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14963 priv->actions->actor = self;
14966 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14968 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14972 * clutter_actor_add_action_with_name:
14973 * @self: a #ClutterActor
14974 * @name: the name to set on the action
14975 * @action: a #ClutterAction
14977 * A convenience function for setting the name of a #ClutterAction
14978 * while adding it to the list of actions applied to @self
14980 * This function is the logical equivalent of:
14983 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14984 * clutter_actor_add_action (self, action);
14990 clutter_actor_add_action_with_name (ClutterActor *self,
14992 ClutterAction *action)
14994 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14995 g_return_if_fail (name != NULL);
14996 g_return_if_fail (CLUTTER_IS_ACTION (action));
14998 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14999 clutter_actor_add_action (self, action);
15003 * clutter_actor_remove_action:
15004 * @self: a #ClutterActor
15005 * @action: a #ClutterAction
15007 * Removes @action from the list of actions applied to @self
15009 * The reference held by @self on the #ClutterAction will be released
15014 clutter_actor_remove_action (ClutterActor *self,
15015 ClutterAction *action)
15017 ClutterActorPrivate *priv;
15019 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15020 g_return_if_fail (CLUTTER_IS_ACTION (action));
15024 if (priv->actions == NULL)
15027 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
15029 if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
15030 g_clear_object (&priv->actions);
15032 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15036 * clutter_actor_remove_action_by_name:
15037 * @self: a #ClutterActor
15038 * @name: the name of the action to remove
15040 * Removes the #ClutterAction with the given name from the list
15041 * of actions applied to @self
15046 clutter_actor_remove_action_by_name (ClutterActor *self,
15049 ClutterActorPrivate *priv;
15050 ClutterActorMeta *meta;
15052 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15053 g_return_if_fail (name != NULL);
15057 if (priv->actions == NULL)
15060 meta = _clutter_meta_group_get_meta (priv->actions, name);
15064 _clutter_meta_group_remove_meta (priv->actions, meta);
15066 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15070 * clutter_actor_get_actions:
15071 * @self: a #ClutterActor
15073 * Retrieves the list of actions applied to @self
15075 * Return value: (transfer container) (element-type Clutter.Action): a copy
15076 * of the list of #ClutterAction<!-- -->s. The contents of the list are
15077 * owned by the #ClutterActor. Use g_list_free() to free the resources
15078 * allocated by the returned #GList
15083 clutter_actor_get_actions (ClutterActor *self)
15085 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15087 if (self->priv->actions == NULL)
15090 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
15094 * clutter_actor_get_action:
15095 * @self: a #ClutterActor
15096 * @name: the name of the action to retrieve
15098 * Retrieves the #ClutterAction with the given name in the list
15099 * of actions applied to @self
15101 * Return value: (transfer none): a #ClutterAction for the given
15102 * name, or %NULL. The returned #ClutterAction is owned by the
15103 * actor and it should not be unreferenced directly
15108 clutter_actor_get_action (ClutterActor *self,
15111 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15112 g_return_val_if_fail (name != NULL, NULL);
15114 if (self->priv->actions == NULL)
15117 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
15121 * clutter_actor_clear_actions:
15122 * @self: a #ClutterActor
15124 * Clears the list of actions applied to @self
15129 clutter_actor_clear_actions (ClutterActor *self)
15131 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15133 if (self->priv->actions == NULL)
15136 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
15140 * clutter_actor_add_constraint:
15141 * @self: a #ClutterActor
15142 * @constraint: a #ClutterConstraint
15144 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15147 * The #ClutterActor will hold a reference on the @constraint until
15148 * either clutter_actor_remove_constraint() or
15149 * clutter_actor_clear_constraints() is called.
15154 clutter_actor_add_constraint (ClutterActor *self,
15155 ClutterConstraint *constraint)
15157 ClutterActorPrivate *priv;
15159 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15160 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15164 if (priv->constraints == NULL)
15166 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15167 priv->constraints->actor = self;
15170 _clutter_meta_group_add_meta (priv->constraints,
15171 CLUTTER_ACTOR_META (constraint));
15172 clutter_actor_queue_relayout (self);
15174 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15178 * clutter_actor_add_constraint_with_name:
15179 * @self: a #ClutterActor
15180 * @name: the name to set on the constraint
15181 * @constraint: a #ClutterConstraint
15183 * A convenience function for setting the name of a #ClutterConstraint
15184 * while adding it to the list of constraints applied to @self
15186 * This function is the logical equivalent of:
15189 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15190 * clutter_actor_add_constraint (self, constraint);
15196 clutter_actor_add_constraint_with_name (ClutterActor *self,
15198 ClutterConstraint *constraint)
15200 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15201 g_return_if_fail (name != NULL);
15202 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15204 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15205 clutter_actor_add_constraint (self, constraint);
15209 * clutter_actor_remove_constraint:
15210 * @self: a #ClutterActor
15211 * @constraint: a #ClutterConstraint
15213 * Removes @constraint from the list of constraints applied to @self
15215 * The reference held by @self on the #ClutterConstraint will be released
15220 clutter_actor_remove_constraint (ClutterActor *self,
15221 ClutterConstraint *constraint)
15223 ClutterActorPrivate *priv;
15225 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15226 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15230 if (priv->constraints == NULL)
15233 _clutter_meta_group_remove_meta (priv->constraints,
15234 CLUTTER_ACTOR_META (constraint));
15236 if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15237 g_clear_object (&priv->constraints);
15239 clutter_actor_queue_relayout (self);
15241 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15245 * clutter_actor_remove_constraint_by_name:
15246 * @self: a #ClutterActor
15247 * @name: the name of the constraint to remove
15249 * Removes the #ClutterConstraint with the given name from the list
15250 * of constraints applied to @self
15255 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15258 ClutterActorPrivate *priv;
15259 ClutterActorMeta *meta;
15261 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15262 g_return_if_fail (name != NULL);
15266 if (priv->constraints == NULL)
15269 meta = _clutter_meta_group_get_meta (priv->constraints, name);
15273 _clutter_meta_group_remove_meta (priv->constraints, meta);
15274 clutter_actor_queue_relayout (self);
15278 * clutter_actor_get_constraints:
15279 * @self: a #ClutterActor
15281 * Retrieves the list of constraints applied to @self
15283 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15284 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15285 * owned by the #ClutterActor. Use g_list_free() to free the resources
15286 * allocated by the returned #GList
15291 clutter_actor_get_constraints (ClutterActor *self)
15293 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15295 if (self->priv->constraints == NULL)
15298 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15302 * clutter_actor_get_constraint:
15303 * @self: a #ClutterActor
15304 * @name: the name of the constraint to retrieve
15306 * Retrieves the #ClutterConstraint with the given name in the list
15307 * of constraints applied to @self
15309 * Return value: (transfer none): a #ClutterConstraint for the given
15310 * name, or %NULL. The returned #ClutterConstraint is owned by the
15311 * actor and it should not be unreferenced directly
15315 ClutterConstraint *
15316 clutter_actor_get_constraint (ClutterActor *self,
15319 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15320 g_return_val_if_fail (name != NULL, NULL);
15322 if (self->priv->constraints == NULL)
15325 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15329 * clutter_actor_clear_constraints:
15330 * @self: a #ClutterActor
15332 * Clears the list of constraints applied to @self
15337 clutter_actor_clear_constraints (ClutterActor *self)
15339 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15341 if (self->priv->constraints == NULL)
15344 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15346 clutter_actor_queue_relayout (self);
15350 * clutter_actor_set_clip_to_allocation:
15351 * @self: a #ClutterActor
15352 * @clip_set: %TRUE to apply a clip tracking the allocation
15354 * Sets whether @self should be clipped to the same size as its
15360 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15363 ClutterActorPrivate *priv;
15365 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15367 clip_set = !!clip_set;
15371 if (priv->clip_to_allocation != clip_set)
15373 priv->clip_to_allocation = clip_set;
15375 clutter_actor_queue_redraw (self);
15377 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15382 * clutter_actor_get_clip_to_allocation:
15383 * @self: a #ClutterActor
15385 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15387 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15392 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15394 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15396 return self->priv->clip_to_allocation;
15400 * clutter_actor_add_effect:
15401 * @self: a #ClutterActor
15402 * @effect: a #ClutterEffect
15404 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15406 * The #ClutterActor will hold a reference on the @effect until either
15407 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15413 clutter_actor_add_effect (ClutterActor *self,
15414 ClutterEffect *effect)
15416 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15417 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15419 _clutter_actor_add_effect_internal (self, effect);
15421 clutter_actor_queue_redraw (self);
15423 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15427 * clutter_actor_add_effect_with_name:
15428 * @self: a #ClutterActor
15429 * @name: the name to set on the effect
15430 * @effect: a #ClutterEffect
15432 * A convenience function for setting the name of a #ClutterEffect
15433 * while adding it to the list of effectss applied to @self
15435 * This function is the logical equivalent of:
15438 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15439 * clutter_actor_add_effect (self, effect);
15445 clutter_actor_add_effect_with_name (ClutterActor *self,
15447 ClutterEffect *effect)
15449 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15450 g_return_if_fail (name != NULL);
15451 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15453 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15454 clutter_actor_add_effect (self, effect);
15458 * clutter_actor_remove_effect:
15459 * @self: a #ClutterActor
15460 * @effect: a #ClutterEffect
15462 * Removes @effect from the list of effects applied to @self
15464 * The reference held by @self on the #ClutterEffect will be released
15469 clutter_actor_remove_effect (ClutterActor *self,
15470 ClutterEffect *effect)
15472 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15473 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15475 _clutter_actor_remove_effect_internal (self, effect);
15477 clutter_actor_queue_redraw (self);
15479 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15483 * clutter_actor_remove_effect_by_name:
15484 * @self: a #ClutterActor
15485 * @name: the name of the effect to remove
15487 * Removes the #ClutterEffect with the given name from the list
15488 * of effects applied to @self
15493 clutter_actor_remove_effect_by_name (ClutterActor *self,
15496 ClutterActorPrivate *priv;
15497 ClutterActorMeta *meta;
15499 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15500 g_return_if_fail (name != NULL);
15504 if (priv->effects == NULL)
15507 meta = _clutter_meta_group_get_meta (priv->effects, name);
15511 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15515 * clutter_actor_get_effects:
15516 * @self: a #ClutterActor
15518 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15520 * Return value: (transfer container) (element-type Clutter.Effect): a list
15521 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15522 * list are owned by Clutter and they should not be freed. You should
15523 * free the returned list using g_list_free() when done
15528 clutter_actor_get_effects (ClutterActor *self)
15530 ClutterActorPrivate *priv;
15532 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15536 if (priv->effects == NULL)
15539 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15543 * clutter_actor_get_effect:
15544 * @self: a #ClutterActor
15545 * @name: the name of the effect to retrieve
15547 * Retrieves the #ClutterEffect with the given name in the list
15548 * of effects applied to @self
15550 * Return value: (transfer none): a #ClutterEffect for the given
15551 * name, or %NULL. The returned #ClutterEffect is owned by the
15552 * actor and it should not be unreferenced directly
15557 clutter_actor_get_effect (ClutterActor *self,
15560 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15561 g_return_val_if_fail (name != NULL, NULL);
15563 if (self->priv->effects == NULL)
15566 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15570 * clutter_actor_clear_effects:
15571 * @self: a #ClutterActor
15573 * Clears the list of effects applied to @self
15578 clutter_actor_clear_effects (ClutterActor *self)
15580 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15582 if (self->priv->effects == NULL)
15585 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15587 clutter_actor_queue_redraw (self);
15591 * clutter_actor_has_key_focus:
15592 * @self: a #ClutterActor
15594 * Checks whether @self is the #ClutterActor that has key focus
15596 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15601 clutter_actor_has_key_focus (ClutterActor *self)
15603 ClutterActor *stage;
15605 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15607 stage = _clutter_actor_get_stage_internal (self);
15611 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15615 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15616 ClutterPaintVolume *pv)
15618 ClutterActorPrivate *priv = self->priv;
15620 /* Actors are only expected to report a valid paint volume
15621 * while they have a valid allocation. */
15622 if (G_UNLIKELY (priv->needs_allocation))
15624 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15625 "Actor needs allocation",
15626 _clutter_actor_get_debug_name (self));
15630 /* Check if there are any handlers connected to the paint
15631 * signal. If there are then all bets are off for what the paint
15632 * volume for this actor might possibly be!
15634 * XXX: It's expected that this is going to end up being quite a
15635 * costly check to have to do here, but we haven't come up with
15636 * another solution that can reliably catch paint signal handlers at
15637 * the right time to either avoid artefacts due to invalid stage
15638 * clipping or due to incorrect culling.
15640 * Previously we checked in clutter_actor_paint(), but at that time
15641 * we may already be using a stage clip that could be derived from
15642 * an invalid paint-volume. We used to try and handle that by
15643 * queuing a follow up, unclipped, redraw but still the previous
15644 * checking wasn't enough to catch invalid volumes involved in
15645 * culling (considering that containers may derive their volume from
15646 * children that haven't yet been painted)
15648 * Longer term, improved solutions could be:
15649 * - Disallow painting in the paint signal, only allow using it
15650 * for tracking when paints happen. We can add another API that
15651 * allows monkey patching the paint of arbitrary actors but in a
15652 * more controlled way and that also supports modifying the
15654 * - If we could be notified somehow when signal handlers are
15655 * connected we wouldn't have to poll for handlers like this.
15657 if (g_signal_has_handler_pending (self,
15658 actor_signals[PAINT],
15662 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15663 "Actor has \"paint\" signal handlers",
15664 _clutter_actor_get_debug_name (self));
15668 _clutter_paint_volume_init_static (pv, self);
15670 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15672 clutter_paint_volume_free (pv);
15673 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15674 "Actor failed to report a volume",
15675 _clutter_actor_get_debug_name (self));
15679 /* since effects can modify the paint volume, we allow them to actually
15680 * do this by making get_paint_volume() "context sensitive"
15682 if (priv->effects != NULL)
15684 if (priv->current_effect != NULL)
15686 const GList *effects, *l;
15688 /* if we are being called from within the paint sequence of
15689 * an actor, get the paint volume up to the current effect
15691 effects = _clutter_meta_group_peek_metas (priv->effects);
15693 l != NULL || (l != NULL && l->data != priv->current_effect);
15696 if (!_clutter_effect_get_paint_volume (l->data, pv))
15698 clutter_paint_volume_free (pv);
15699 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15700 "Effect (%s) failed to report a volume",
15701 _clutter_actor_get_debug_name (self),
15702 _clutter_actor_meta_get_debug_name (l->data));
15709 const GList *effects, *l;
15711 /* otherwise, get the cumulative volume */
15712 effects = _clutter_meta_group_peek_metas (priv->effects);
15713 for (l = effects; l != NULL; l = l->next)
15714 if (!_clutter_effect_get_paint_volume (l->data, pv))
15716 clutter_paint_volume_free (pv);
15717 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15718 "Effect (%s) failed to report a volume",
15719 _clutter_actor_get_debug_name (self),
15720 _clutter_actor_meta_get_debug_name (l->data));
15729 /* The public clutter_actor_get_paint_volume API returns a const
15730 * pointer since we return a pointer directly to the cached
15731 * PaintVolume associated with the actor and don't want the user to
15732 * inadvertently modify it, but for internal uses we sometimes need
15733 * access to the same PaintVolume but need to apply some book-keeping
15734 * modifications to it so we don't want a const pointer.
15736 static ClutterPaintVolume *
15737 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15739 ClutterActorPrivate *priv;
15743 if (priv->paint_volume_valid)
15744 clutter_paint_volume_free (&priv->paint_volume);
15746 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15748 priv->paint_volume_valid = TRUE;
15749 return &priv->paint_volume;
15753 priv->paint_volume_valid = FALSE;
15759 * clutter_actor_get_paint_volume:
15760 * @self: a #ClutterActor
15762 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15763 * when a paint volume can't be determined.
15765 * The paint volume is defined as the 3D space occupied by an actor
15766 * when being painted.
15768 * This function will call the <function>get_paint_volume()</function>
15769 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15770 * should not usually care about overriding the default implementation,
15771 * unless they are, for instance: painting outside their allocation, or
15772 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15775 * <note>2D actors overriding <function>get_paint_volume()</function>
15776 * ensure their volume has a depth of 0. (This will be true so long as
15777 * you don't call clutter_paint_volume_set_depth().)</note>
15779 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15780 * or %NULL if no volume could be determined. The returned pointer
15781 * is not guaranteed to be valid across multiple frames; if you want
15782 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15786 const ClutterPaintVolume *
15787 clutter_actor_get_paint_volume (ClutterActor *self)
15789 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15791 return _clutter_actor_get_paint_volume_mutable (self);
15795 * clutter_actor_get_transformed_paint_volume:
15796 * @self: a #ClutterActor
15797 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15798 * (or %NULL for the stage)
15800 * Retrieves the 3D paint volume of an actor like
15801 * clutter_actor_get_paint_volume() does (Please refer to the
15802 * documentation of clutter_actor_get_paint_volume() for more
15803 * details.) and it additionally transforms the paint volume into the
15804 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15805 * is passed for @relative_to_ancestor)
15807 * This can be used by containers that base their paint volume on
15808 * the volume of their children. Such containers can query the
15809 * transformed paint volume of all of its children and union them
15810 * together using clutter_paint_volume_union().
15812 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15813 * or %NULL if no volume could be determined. The returned pointer is
15814 * not guaranteed to be valid across multiple frames; if you wish to
15815 * keep it, you will have to copy it using clutter_paint_volume_copy().
15819 const ClutterPaintVolume *
15820 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15821 ClutterActor *relative_to_ancestor)
15823 const ClutterPaintVolume *volume;
15824 ClutterActor *stage;
15825 ClutterPaintVolume *transformed_volume;
15827 stage = _clutter_actor_get_stage_internal (self);
15828 if (G_UNLIKELY (stage == NULL))
15831 if (relative_to_ancestor == NULL)
15832 relative_to_ancestor = stage;
15834 volume = clutter_actor_get_paint_volume (self);
15835 if (volume == NULL)
15838 transformed_volume =
15839 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15841 _clutter_paint_volume_copy_static (volume, transformed_volume);
15843 _clutter_paint_volume_transform_relative (transformed_volume,
15844 relative_to_ancestor);
15846 return transformed_volume;
15850 * clutter_actor_get_paint_box:
15851 * @self: a #ClutterActor
15852 * @box: (out): return location for a #ClutterActorBox
15854 * Retrieves the paint volume of the passed #ClutterActor, and
15855 * transforms it into a 2D bounding box in stage coordinates.
15857 * This function is useful to determine the on screen area occupied by
15858 * the actor. The box is only an approximation and may often be
15859 * considerably larger due to the optimizations used to calculate the
15860 * box. The box is never smaller though, so it can reliably be used
15863 * There are times when a 2D paint box can't be determined, e.g.
15864 * because the actor isn't yet parented under a stage or because
15865 * the actor is unable to determine a paint volume.
15867 * Return value: %TRUE if a 2D paint box could be determined, else
15873 clutter_actor_get_paint_box (ClutterActor *self,
15874 ClutterActorBox *box)
15876 ClutterActor *stage;
15877 ClutterPaintVolume *pv;
15879 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15880 g_return_val_if_fail (box != NULL, FALSE);
15882 stage = _clutter_actor_get_stage_internal (self);
15883 if (G_UNLIKELY (!stage))
15886 pv = _clutter_actor_get_paint_volume_mutable (self);
15887 if (G_UNLIKELY (!pv))
15890 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15896 * clutter_actor_has_overlaps:
15897 * @self: A #ClutterActor
15899 * Asks the actor's implementation whether it may contain overlapping
15902 * For example; Clutter may use this to determine whether the painting
15903 * should be redirected to an offscreen buffer to correctly implement
15904 * the opacity property.
15906 * Custom actors can override the default response by implementing the
15907 * #ClutterActor <function>has_overlaps</function> virtual function. See
15908 * clutter_actor_set_offscreen_redirect() for more information.
15910 * Return value: %TRUE if the actor may have overlapping primitives, and
15916 clutter_actor_has_overlaps (ClutterActor *self)
15918 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15920 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15924 * clutter_actor_has_effects:
15925 * @self: A #ClutterActor
15927 * Returns whether the actor has any effects applied.
15929 * Return value: %TRUE if the actor has any effects,
15935 clutter_actor_has_effects (ClutterActor *self)
15937 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15939 if (self->priv->effects == NULL)
15942 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15946 * clutter_actor_has_constraints:
15947 * @self: A #ClutterActor
15949 * Returns whether the actor has any constraints applied.
15951 * Return value: %TRUE if the actor has any constraints,
15957 clutter_actor_has_constraints (ClutterActor *self)
15959 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15961 return self->priv->constraints != NULL;
15965 * clutter_actor_has_actions:
15966 * @self: A #ClutterActor
15968 * Returns whether the actor has any actions applied.
15970 * Return value: %TRUE if the actor has any actions,
15976 clutter_actor_has_actions (ClutterActor *self)
15978 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15980 return self->priv->actions != NULL;
15984 * clutter_actor_get_n_children:
15985 * @self: a #ClutterActor
15987 * Retrieves the number of children of @self.
15989 * Return value: the number of children of an actor
15994 clutter_actor_get_n_children (ClutterActor *self)
15996 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15998 return self->priv->n_children;
16002 * clutter_actor_get_child_at_index:
16003 * @self: a #ClutterActor
16004 * @index_: the position in the list of children
16006 * Retrieves the actor at the given @index_ inside the list of
16007 * children of @self.
16009 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16014 clutter_actor_get_child_at_index (ClutterActor *self,
16017 ClutterActor *iter;
16020 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16021 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
16023 for (iter = self->priv->first_child, i = 0;
16024 iter != NULL && i < index_;
16025 iter = iter->priv->next_sibling, i += 1)
16032 * _clutter_actor_foreach_child:
16033 * @actor: The actor whos children you want to iterate
16034 * @callback: The function to call for each child
16035 * @user_data: Private data to pass to @callback
16037 * Calls a given @callback once for each child of the specified @actor and
16038 * passing the @user_data pointer each time.
16040 * Return value: returns %TRUE if all children were iterated, else
16041 * %FALSE if a callback broke out of iteration early.
16044 _clutter_actor_foreach_child (ClutterActor *self,
16045 ClutterForeachCallback callback,
16046 gpointer user_data)
16048 ClutterActor *iter;
16051 if (self->priv->first_child == NULL)
16055 iter = self->priv->first_child;
16057 /* we use this form so that it's safe to change the children
16058 * list while iterating it
16060 while (cont && iter != NULL)
16062 ClutterActor *next = iter->priv->next_sibling;
16064 cont = callback (iter, user_data);
16073 /* For debugging purposes this gives us a simple way to print out
16074 * the scenegraph e.g in gdb using:
16076 * _clutter_actor_traverse (stage,
16078 * clutter_debug_print_actor_cb,
16083 static ClutterActorTraverseVisitFlags
16084 clutter_debug_print_actor_cb (ClutterActor *actor,
16088 g_print ("%*s%s:%p\n",
16090 _clutter_actor_get_debug_name (actor),
16093 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16098 _clutter_actor_traverse_breadth (ClutterActor *actor,
16099 ClutterTraverseCallback callback,
16100 gpointer user_data)
16102 GQueue *queue = g_queue_new ();
16103 ClutterActor dummy;
16104 int current_depth = 0;
16106 g_queue_push_tail (queue, actor);
16107 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
16109 while ((actor = g_queue_pop_head (queue)))
16111 ClutterActorTraverseVisitFlags flags;
16113 if (actor == &dummy)
16116 g_queue_push_tail (queue, &dummy);
16120 flags = callback (actor, current_depth, user_data);
16121 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16123 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16125 ClutterActor *iter;
16127 for (iter = actor->priv->first_child;
16129 iter = iter->priv->next_sibling)
16131 g_queue_push_tail (queue, iter);
16136 g_queue_free (queue);
16139 static ClutterActorTraverseVisitFlags
16140 _clutter_actor_traverse_depth (ClutterActor *actor,
16141 ClutterTraverseCallback before_children_callback,
16142 ClutterTraverseCallback after_children_callback,
16144 gpointer user_data)
16146 ClutterActorTraverseVisitFlags flags;
16148 flags = before_children_callback (actor, current_depth, user_data);
16149 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16150 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16152 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16154 ClutterActor *iter;
16156 for (iter = actor->priv->first_child;
16158 iter = iter->priv->next_sibling)
16160 flags = _clutter_actor_traverse_depth (iter,
16161 before_children_callback,
16162 after_children_callback,
16166 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16167 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16171 if (after_children_callback)
16172 return after_children_callback (actor, current_depth, user_data);
16174 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16177 /* _clutter_actor_traverse:
16178 * @actor: The actor to start traversing the graph from
16179 * @flags: These flags may affect how the traversal is done
16180 * @before_children_callback: A function to call before visiting the
16181 * children of the current actor.
16182 * @after_children_callback: A function to call after visiting the
16183 * children of the current actor. (Ignored if
16184 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16185 * @user_data: The private data to pass to the callbacks
16187 * Traverses the scenegraph starting at the specified @actor and
16188 * descending through all its children and its children's children.
16189 * For each actor traversed @before_children_callback and
16190 * @after_children_callback are called with the specified
16191 * @user_data, before and after visiting that actor's children.
16193 * The callbacks can return flags that affect the ongoing traversal
16194 * such as by skipping over an actors children or bailing out of
16195 * any further traversing.
16198 _clutter_actor_traverse (ClutterActor *actor,
16199 ClutterActorTraverseFlags flags,
16200 ClutterTraverseCallback before_children_callback,
16201 ClutterTraverseCallback after_children_callback,
16202 gpointer user_data)
16204 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16205 _clutter_actor_traverse_breadth (actor,
16206 before_children_callback,
16208 else /* DEPTH_FIRST */
16209 _clutter_actor_traverse_depth (actor,
16210 before_children_callback,
16211 after_children_callback,
16212 0, /* start depth */
16217 on_layout_manager_changed (ClutterLayoutManager *manager,
16218 ClutterActor *self)
16220 clutter_actor_queue_relayout (self);
16224 * clutter_actor_set_layout_manager:
16225 * @self: a #ClutterActor
16226 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16228 * Sets the #ClutterLayoutManager delegate object that will be used to
16229 * lay out the children of @self.
16231 * The #ClutterActor will take a reference on the passed @manager which
16232 * will be released either when the layout manager is removed, or when
16233 * the actor is destroyed.
16238 clutter_actor_set_layout_manager (ClutterActor *self,
16239 ClutterLayoutManager *manager)
16241 ClutterActorPrivate *priv;
16243 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16244 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16248 if (priv->layout_manager != NULL)
16250 g_signal_handlers_disconnect_by_func (priv->layout_manager,
16251 G_CALLBACK (on_layout_manager_changed),
16253 clutter_layout_manager_set_container (priv->layout_manager, NULL);
16254 g_clear_object (&priv->layout_manager);
16257 priv->layout_manager = manager;
16259 if (priv->layout_manager != NULL)
16261 g_object_ref_sink (priv->layout_manager);
16262 clutter_layout_manager_set_container (priv->layout_manager,
16263 CLUTTER_CONTAINER (self));
16264 g_signal_connect (priv->layout_manager, "layout-changed",
16265 G_CALLBACK (on_layout_manager_changed),
16269 clutter_actor_queue_relayout (self);
16271 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16275 * clutter_actor_get_layout_manager:
16276 * @self: a #ClutterActor
16278 * Retrieves the #ClutterLayoutManager used by @self.
16280 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16285 ClutterLayoutManager *
16286 clutter_actor_get_layout_manager (ClutterActor *self)
16288 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16290 return self->priv->layout_manager;
16293 static const ClutterLayoutInfo default_layout_info = {
16294 CLUTTER_POINT_INIT_ZERO, /* fixed-pos */
16295 { 0, 0, 0, 0 }, /* margin */
16296 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
16297 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
16298 FALSE, FALSE, /* expand */
16299 CLUTTER_SIZE_INIT_ZERO, /* minimum */
16300 CLUTTER_SIZE_INIT_ZERO, /* natural */
16304 layout_info_free (gpointer data)
16306 if (G_LIKELY (data != NULL))
16307 g_slice_free (ClutterLayoutInfo, data);
16311 * _clutter_actor_get_layout_info:
16312 * @self: a #ClutterActor
16314 * Retrieves a pointer to the ClutterLayoutInfo structure.
16316 * If the actor does not have a ClutterLayoutInfo associated to it, one
16317 * will be created and initialized to the default values.
16319 * This function should be used for setters.
16321 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16324 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16326 ClutterLayoutInfo *
16327 _clutter_actor_get_layout_info (ClutterActor *self)
16329 ClutterLayoutInfo *retval;
16331 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16332 if (retval == NULL)
16334 retval = g_slice_new (ClutterLayoutInfo);
16336 *retval = default_layout_info;
16338 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16347 * _clutter_actor_get_layout_info_or_defaults:
16348 * @self: a #ClutterActor
16350 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16352 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16353 * then the default structure will be returned.
16355 * This function should only be used for getters.
16357 * Return value: a const pointer to the ClutterLayoutInfo structure
16359 const ClutterLayoutInfo *
16360 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16362 const ClutterLayoutInfo *info;
16364 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16366 return &default_layout_info;
16372 * clutter_actor_set_x_align:
16373 * @self: a #ClutterActor
16374 * @x_align: the horizontal alignment policy
16376 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16377 * actor received extra horizontal space.
16379 * See also the #ClutterActor:x-align property.
16384 clutter_actor_set_x_align (ClutterActor *self,
16385 ClutterActorAlign x_align)
16387 ClutterLayoutInfo *info;
16389 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16391 info = _clutter_actor_get_layout_info (self);
16393 if (info->x_align != x_align)
16395 info->x_align = x_align;
16397 clutter_actor_queue_relayout (self);
16399 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16404 * clutter_actor_get_x_align:
16405 * @self: a #ClutterActor
16407 * Retrieves the horizontal alignment policy set using
16408 * clutter_actor_set_x_align().
16410 * Return value: the horizontal alignment policy.
16415 clutter_actor_get_x_align (ClutterActor *self)
16417 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16419 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16423 * clutter_actor_set_y_align:
16424 * @self: a #ClutterActor
16425 * @y_align: the vertical alignment policy
16427 * Sets the vertical alignment policy of a #ClutterActor, in case the
16428 * actor received extra vertical space.
16430 * See also the #ClutterActor:y-align property.
16435 clutter_actor_set_y_align (ClutterActor *self,
16436 ClutterActorAlign y_align)
16438 ClutterLayoutInfo *info;
16440 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16442 info = _clutter_actor_get_layout_info (self);
16444 if (info->y_align != y_align)
16446 info->y_align = y_align;
16448 clutter_actor_queue_relayout (self);
16450 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16455 * clutter_actor_get_y_align:
16456 * @self: a #ClutterActor
16458 * Retrieves the vertical alignment policy set using
16459 * clutter_actor_set_y_align().
16461 * Return value: the vertical alignment policy.
16466 clutter_actor_get_y_align (ClutterActor *self)
16468 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16470 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16474 * clutter_actor_set_margin:
16475 * @self: a #ClutterActor
16476 * @margin: a #ClutterMargin
16478 * Sets all the components of the margin of a #ClutterActor.
16483 clutter_actor_set_margin (ClutterActor *self,
16484 const ClutterMargin *margin)
16486 ClutterLayoutInfo *info;
16490 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16491 g_return_if_fail (margin != NULL);
16493 obj = G_OBJECT (self);
16496 g_object_freeze_notify (obj);
16498 info = _clutter_actor_get_layout_info (self);
16500 if (info->margin.top != margin->top)
16502 info->margin.top = margin->top;
16503 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16507 if (info->margin.right != margin->right)
16509 info->margin.right = margin->right;
16510 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16514 if (info->margin.bottom != margin->bottom)
16516 info->margin.bottom = margin->bottom;
16517 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16521 if (info->margin.left != margin->left)
16523 info->margin.left = margin->left;
16524 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16529 clutter_actor_queue_relayout (self);
16531 g_object_thaw_notify (obj);
16535 * clutter_actor_get_margin:
16536 * @self: a #ClutterActor
16537 * @margin: (out caller-allocates): return location for a #ClutterMargin
16539 * Retrieves all the components of the margin of a #ClutterActor.
16544 clutter_actor_get_margin (ClutterActor *self,
16545 ClutterMargin *margin)
16547 const ClutterLayoutInfo *info;
16549 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16550 g_return_if_fail (margin != NULL);
16552 info = _clutter_actor_get_layout_info_or_defaults (self);
16554 *margin = info->margin;
16558 * clutter_actor_set_margin_top:
16559 * @self: a #ClutterActor
16560 * @margin: the top margin
16562 * Sets the margin from the top of a #ClutterActor.
16567 clutter_actor_set_margin_top (ClutterActor *self,
16570 ClutterLayoutInfo *info;
16572 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16573 g_return_if_fail (margin >= 0.f);
16575 info = _clutter_actor_get_layout_info (self);
16577 if (info->margin.top == margin)
16580 info->margin.top = margin;
16582 clutter_actor_queue_relayout (self);
16584 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16588 * clutter_actor_get_margin_top:
16589 * @self: a #ClutterActor
16591 * Retrieves the top margin of a #ClutterActor.
16593 * Return value: the top margin
16598 clutter_actor_get_margin_top (ClutterActor *self)
16600 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16602 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16606 * clutter_actor_set_margin_bottom:
16607 * @self: a #ClutterActor
16608 * @margin: the bottom margin
16610 * Sets the margin from the bottom of a #ClutterActor.
16615 clutter_actor_set_margin_bottom (ClutterActor *self,
16618 ClutterLayoutInfo *info;
16620 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16621 g_return_if_fail (margin >= 0.f);
16623 info = _clutter_actor_get_layout_info (self);
16625 if (info->margin.bottom == margin)
16628 info->margin.bottom = margin;
16630 clutter_actor_queue_relayout (self);
16632 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16636 * clutter_actor_get_margin_bottom:
16637 * @self: a #ClutterActor
16639 * Retrieves the bottom margin of a #ClutterActor.
16641 * Return value: the bottom margin
16646 clutter_actor_get_margin_bottom (ClutterActor *self)
16648 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16650 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16654 * clutter_actor_set_margin_left:
16655 * @self: a #ClutterActor
16656 * @margin: the left margin
16658 * Sets the margin from the left of a #ClutterActor.
16663 clutter_actor_set_margin_left (ClutterActor *self,
16666 ClutterLayoutInfo *info;
16668 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16669 g_return_if_fail (margin >= 0.f);
16671 info = _clutter_actor_get_layout_info (self);
16673 if (info->margin.left == margin)
16676 info->margin.left = margin;
16678 clutter_actor_queue_relayout (self);
16680 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16684 * clutter_actor_get_margin_left:
16685 * @self: a #ClutterActor
16687 * Retrieves the left margin of a #ClutterActor.
16689 * Return value: the left margin
16694 clutter_actor_get_margin_left (ClutterActor *self)
16696 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16698 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16702 * clutter_actor_set_margin_right:
16703 * @self: a #ClutterActor
16704 * @margin: the right margin
16706 * Sets the margin from the right of a #ClutterActor.
16711 clutter_actor_set_margin_right (ClutterActor *self,
16714 ClutterLayoutInfo *info;
16716 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16717 g_return_if_fail (margin >= 0.f);
16719 info = _clutter_actor_get_layout_info (self);
16721 if (info->margin.right == margin)
16724 info->margin.right = margin;
16726 clutter_actor_queue_relayout (self);
16728 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16732 * clutter_actor_get_margin_right:
16733 * @self: a #ClutterActor
16735 * Retrieves the right margin of a #ClutterActor.
16737 * Return value: the right margin
16742 clutter_actor_get_margin_right (ClutterActor *self)
16744 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16746 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16750 clutter_actor_set_background_color_internal (ClutterActor *self,
16751 const ClutterColor *color)
16753 ClutterActorPrivate *priv = self->priv;
16756 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16759 obj = G_OBJECT (self);
16761 priv->bg_color = *color;
16762 priv->bg_color_set = TRUE;
16764 clutter_actor_queue_redraw (self);
16766 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16767 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16771 * clutter_actor_set_background_color:
16772 * @self: a #ClutterActor
16773 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16776 * Sets the background color of a #ClutterActor.
16778 * The background color will be used to cover the whole allocation of the
16779 * actor. The default background color of an actor is transparent.
16781 * To check whether an actor has a background color, you can use the
16782 * #ClutterActor:background-color-set actor property.
16784 * The #ClutterActor:background-color property is animatable.
16789 clutter_actor_set_background_color (ClutterActor *self,
16790 const ClutterColor *color)
16792 ClutterActorPrivate *priv;
16794 GParamSpec *bg_color_pspec;
16796 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16798 obj = G_OBJECT (self);
16804 priv->bg_color_set = FALSE;
16805 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16806 clutter_actor_queue_redraw (self);
16810 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16811 if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16813 _clutter_actor_create_transition (self, bg_color_pspec,
16818 _clutter_actor_update_transition (self, bg_color_pspec, color);
16820 clutter_actor_queue_redraw (self);
16824 * clutter_actor_get_background_color:
16825 * @self: a #ClutterActor
16826 * @color: (out caller-allocates): return location for a #ClutterColor
16828 * Retrieves the color set using clutter_actor_set_background_color().
16833 clutter_actor_get_background_color (ClutterActor *self,
16834 ClutterColor *color)
16836 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16837 g_return_if_fail (color != NULL);
16839 *color = self->priv->bg_color;
16843 * clutter_actor_get_previous_sibling:
16844 * @self: a #ClutterActor
16846 * Retrieves the sibling of @self that comes before it in the list
16847 * of children of @self's parent.
16849 * The returned pointer is only valid until the scene graph changes; it
16850 * is not safe to modify the list of children of @self while iterating
16853 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16858 clutter_actor_get_previous_sibling (ClutterActor *self)
16860 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16862 return self->priv->prev_sibling;
16866 * clutter_actor_get_next_sibling:
16867 * @self: a #ClutterActor
16869 * Retrieves the sibling of @self that comes after it in the list
16870 * of children of @self's parent.
16872 * The returned pointer is only valid until the scene graph changes; it
16873 * is not safe to modify the list of children of @self while iterating
16876 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16881 clutter_actor_get_next_sibling (ClutterActor *self)
16883 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16885 return self->priv->next_sibling;
16889 * clutter_actor_get_first_child:
16890 * @self: a #ClutterActor
16892 * Retrieves the first child of @self.
16894 * The returned pointer is only valid until the scene graph changes; it
16895 * is not safe to modify the list of children of @self while iterating
16898 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16903 clutter_actor_get_first_child (ClutterActor *self)
16905 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16907 return self->priv->first_child;
16911 * clutter_actor_get_last_child:
16912 * @self: a #ClutterActor
16914 * Retrieves the last child of @self.
16916 * The returned pointer is only valid until the scene graph changes; it
16917 * is not safe to modify the list of children of @self while iterating
16920 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16925 clutter_actor_get_last_child (ClutterActor *self)
16927 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16929 return self->priv->last_child;
16932 /* easy way to have properly named fields instead of the dummy ones
16933 * we use in the public structure
16935 typedef struct _RealActorIter
16937 ClutterActor *root; /* dummy1 */
16938 ClutterActor *current; /* dummy2 */
16939 gpointer padding_1; /* dummy3 */
16940 gint age; /* dummy4 */
16941 gpointer padding_2; /* dummy5 */
16945 * clutter_actor_iter_init:
16946 * @iter: a #ClutterActorIter
16947 * @root: a #ClutterActor
16949 * Initializes a #ClutterActorIter, which can then be used to iterate
16950 * efficiently over a section of the scene graph, and associates it
16953 * Modifying the scene graph section that contains @root will invalidate
16957 * ClutterActorIter iter;
16958 * ClutterActor *child;
16960 * clutter_actor_iter_init (&iter, container);
16961 * while (clutter_actor_iter_next (&iter, &child))
16963 * /* do something with child */
16970 clutter_actor_iter_init (ClutterActorIter *iter,
16971 ClutterActor *root)
16973 RealActorIter *ri = (RealActorIter *) iter;
16975 g_return_if_fail (iter != NULL);
16976 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16979 ri->current = NULL;
16980 ri->age = root->priv->age;
16984 * clutter_actor_iter_next:
16985 * @iter: a #ClutterActorIter
16986 * @child: (out): return location for a #ClutterActor
16988 * Advances the @iter and retrieves the next child of the root #ClutterActor
16989 * that was used to initialize the #ClutterActorIterator.
16991 * If the iterator can advance, this function returns %TRUE and sets the
16994 * If the iterator cannot advance, this function returns %FALSE, and
16995 * the contents of @child are undefined.
16997 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17002 clutter_actor_iter_next (ClutterActorIter *iter,
17003 ClutterActor **child)
17005 RealActorIter *ri = (RealActorIter *) iter;
17007 g_return_val_if_fail (iter != NULL, FALSE);
17008 g_return_val_if_fail (ri->root != NULL, FALSE);
17009 #ifndef G_DISABLE_ASSERT
17010 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17013 if (ri->current == NULL)
17014 ri->current = ri->root->priv->first_child;
17016 ri->current = ri->current->priv->next_sibling;
17019 *child = ri->current;
17021 return ri->current != NULL;
17025 * clutter_actor_iter_prev:
17026 * @iter: a #ClutterActorIter
17027 * @child: (out): return location for a #ClutterActor
17029 * Advances the @iter and retrieves the previous child of the root
17030 * #ClutterActor that was used to initialize the #ClutterActorIterator.
17032 * If the iterator can advance, this function returns %TRUE and sets the
17035 * If the iterator cannot advance, this function returns %FALSE, and
17036 * the contents of @child are undefined.
17038 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17043 clutter_actor_iter_prev (ClutterActorIter *iter,
17044 ClutterActor **child)
17046 RealActorIter *ri = (RealActorIter *) iter;
17048 g_return_val_if_fail (iter != NULL, FALSE);
17049 g_return_val_if_fail (ri->root != NULL, FALSE);
17050 #ifndef G_DISABLE_ASSERT
17051 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17054 if (ri->current == NULL)
17055 ri->current = ri->root->priv->last_child;
17057 ri->current = ri->current->priv->prev_sibling;
17060 *child = ri->current;
17062 return ri->current != NULL;
17066 * clutter_actor_iter_remove:
17067 * @iter: a #ClutterActorIter
17069 * Safely removes the #ClutterActor currently pointer to by the iterator
17072 * This function can only be called after clutter_actor_iter_next() or
17073 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17074 * than once for the same actor.
17076 * This function will call clutter_actor_remove_child() internally.
17081 clutter_actor_iter_remove (ClutterActorIter *iter)
17083 RealActorIter *ri = (RealActorIter *) iter;
17086 g_return_if_fail (iter != NULL);
17087 g_return_if_fail (ri->root != NULL);
17088 #ifndef G_DISABLE_ASSERT
17089 g_return_if_fail (ri->age == ri->root->priv->age);
17091 g_return_if_fail (ri->current != NULL);
17097 ri->current = cur->priv->prev_sibling;
17099 clutter_actor_remove_child_internal (ri->root, cur,
17100 REMOVE_CHILD_DEFAULT_FLAGS);
17107 * clutter_actor_iter_destroy:
17108 * @iter: a #ClutterActorIter
17110 * Safely destroys the #ClutterActor currently pointer to by the iterator
17113 * This function can only be called after clutter_actor_iter_next() or
17114 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17115 * than once for the same actor.
17117 * This function will call clutter_actor_destroy() internally.
17122 clutter_actor_iter_destroy (ClutterActorIter *iter)
17124 RealActorIter *ri = (RealActorIter *) iter;
17127 g_return_if_fail (iter != NULL);
17128 g_return_if_fail (ri->root != NULL);
17129 #ifndef G_DISABLE_ASSERT
17130 g_return_if_fail (ri->age == ri->root->priv->age);
17132 g_return_if_fail (ri->current != NULL);
17138 ri->current = cur->priv->prev_sibling;
17140 clutter_actor_destroy (cur);
17146 static const ClutterAnimationInfo default_animation_info = {
17147 NULL, /* transitions */
17149 NULL, /* cur_state */
17153 clutter_animation_info_free (gpointer data)
17157 ClutterAnimationInfo *info = data;
17159 if (info->transitions != NULL)
17160 g_hash_table_unref (info->transitions);
17162 if (info->states != NULL)
17163 g_array_unref (info->states);
17165 g_slice_free (ClutterAnimationInfo, info);
17169 const ClutterAnimationInfo *
17170 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17172 const ClutterAnimationInfo *res;
17173 GObject *obj = G_OBJECT (self);
17175 res = g_object_get_qdata (obj, quark_actor_animation_info);
17179 return &default_animation_info;
17182 ClutterAnimationInfo *
17183 _clutter_actor_get_animation_info (ClutterActor *self)
17185 GObject *obj = G_OBJECT (self);
17186 ClutterAnimationInfo *res;
17188 res = g_object_get_qdata (obj, quark_actor_animation_info);
17191 res = g_slice_new (ClutterAnimationInfo);
17193 *res = default_animation_info;
17195 g_object_set_qdata_full (obj, quark_actor_animation_info,
17197 clutter_animation_info_free);
17203 ClutterTransition *
17204 _clutter_actor_get_transition (ClutterActor *actor,
17207 const ClutterAnimationInfo *info;
17209 info = _clutter_actor_get_animation_info_or_defaults (actor);
17211 if (info->transitions == NULL)
17214 return g_hash_table_lookup (info->transitions, pspec->name);
17217 typedef struct _TransitionClosure
17219 ClutterActor *actor;
17220 ClutterTransition *transition;
17222 gulong completed_id;
17223 } TransitionClosure;
17226 transition_closure_free (gpointer data)
17228 if (G_LIKELY (data != NULL))
17230 TransitionClosure *clos = data;
17231 ClutterTimeline *timeline;
17233 timeline = CLUTTER_TIMELINE (clos->transition);
17235 if (clutter_timeline_is_playing (timeline))
17236 clutter_timeline_stop (timeline);
17238 g_signal_handler_disconnect (clos->transition, clos->completed_id);
17240 g_object_unref (clos->transition);
17241 g_free (clos->name);
17243 g_slice_free (TransitionClosure, clos);
17248 on_transition_completed (ClutterTransition *transition,
17249 TransitionClosure *clos)
17251 ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
17252 ClutterActor *actor = clos->actor;
17253 ClutterAnimationInfo *info;
17254 gint n_repeats, cur_repeat;
17256 info = _clutter_actor_get_animation_info (actor);
17258 /* reset the caches used by animations */
17259 clutter_actor_store_content_box (actor, NULL);
17261 /* ensure that we remove the transition only at the end
17262 * of its run; we emit ::completed for every repeat
17264 n_repeats = clutter_timeline_get_repeat_count (timeline);
17265 cur_repeat = clutter_timeline_get_current_repeat (timeline);
17267 if (cur_repeat == n_repeats)
17269 if (clutter_transition_get_remove_on_complete (transition))
17271 /* we take a reference here because removing the closure
17272 * will release the reference on the transition, and we
17273 * want the transition to survive the signal emission;
17274 * the master clock will release the last reference at
17275 * the end of the frame processing.
17277 g_object_ref (transition);
17278 g_hash_table_remove (info->transitions, clos->name);
17282 /* if it's the last transition then we clean up */
17283 if (g_hash_table_size (info->transitions) == 0)
17285 g_hash_table_unref (info->transitions);
17286 info->transitions = NULL;
17288 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17289 _clutter_actor_get_debug_name (actor));
17291 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17296 _clutter_actor_update_transition (ClutterActor *actor,
17300 TransitionClosure *clos;
17301 ClutterTimeline *timeline;
17302 ClutterInterval *interval;
17303 const ClutterAnimationInfo *info;
17306 GValue initial = G_VALUE_INIT;
17307 GValue final = G_VALUE_INIT;
17308 char *error = NULL;
17310 info = _clutter_actor_get_animation_info_or_defaults (actor);
17312 if (info->transitions == NULL)
17315 clos = g_hash_table_lookup (info->transitions, pspec->name);
17319 timeline = CLUTTER_TIMELINE (clos->transition);
17321 va_start (var_args, pspec);
17323 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17325 g_value_init (&initial, ptype);
17326 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17330 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17333 g_critical ("%s: %s", G_STRLOC, error);
17338 interval = clutter_transition_get_interval (clos->transition);
17339 clutter_interval_set_initial_value (interval, &initial);
17340 clutter_interval_set_final_value (interval, &final);
17342 /* if we're updating with an easing duration of zero milliseconds,
17343 * we just jump the timeline to the end and let it run its course
17345 if (info->cur_state != NULL &&
17346 info->cur_state->easing_duration != 0)
17348 guint cur_duration = clutter_timeline_get_duration (timeline);
17349 ClutterAnimationMode cur_mode =
17350 clutter_timeline_get_progress_mode (timeline);
17352 if (cur_duration != info->cur_state->easing_duration)
17353 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17355 if (cur_mode != info->cur_state->easing_mode)
17356 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17358 clutter_timeline_rewind (timeline);
17362 guint duration = clutter_timeline_get_duration (timeline);
17364 clutter_timeline_advance (timeline, duration);
17368 g_value_unset (&initial);
17369 g_value_unset (&final);
17375 * _clutter_actor_create_transition:
17376 * @actor: a #ClutterActor
17377 * @pspec: the property used for the transition
17378 * @...: initial and final state
17380 * Creates a #ClutterTransition for the property represented by @pspec.
17382 * Return value: a #ClutterTransition
17384 ClutterTransition *
17385 _clutter_actor_create_transition (ClutterActor *actor,
17389 ClutterAnimationInfo *info;
17390 ClutterTransition *res = NULL;
17391 gboolean call_restore = FALSE;
17392 TransitionClosure *clos;
17395 info = _clutter_actor_get_animation_info (actor);
17397 /* XXX - this will go away in 2.0
17399 * if no state has been pushed, we assume that the easing state is
17400 * in "compatibility mode": all transitions have a duration of 0
17401 * msecs, which means that they happen immediately. in Clutter 2.0
17402 * this will turn into a g_assert(info->states != NULL), as every
17403 * actor will start with a predefined easing state
17405 if (info->states == NULL)
17407 clutter_actor_save_easing_state (actor);
17408 clutter_actor_set_easing_duration (actor, 0);
17409 call_restore = TRUE;
17412 if (info->transitions == NULL)
17413 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17415 transition_closure_free);
17417 va_start (var_args, pspec);
17419 clos = g_hash_table_lookup (info->transitions, pspec->name);
17422 ClutterTimeline *timeline;
17423 ClutterInterval *interval;
17424 GValue initial = G_VALUE_INIT;
17425 GValue final = G_VALUE_INIT;
17429 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17431 G_VALUE_COLLECT_INIT (&initial, ptype,
17436 g_critical ("%s: %s", G_STRLOC, error);
17441 G_VALUE_COLLECT_INIT (&final, ptype,
17447 g_critical ("%s: %s", G_STRLOC, error);
17448 g_value_unset (&initial);
17453 /* if the current easing state has a duration of 0, then we don't
17454 * bother to create the transition, and we just set the final value
17455 * directly on the actor; we don't go through the Animatable
17456 * interface because we know we got here through an animatable
17459 if (info->cur_state->easing_duration == 0)
17461 clutter_actor_set_animatable_property (actor,
17465 g_value_unset (&initial);
17466 g_value_unset (&final);
17471 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17473 g_value_unset (&initial);
17474 g_value_unset (&final);
17476 res = clutter_property_transition_new (pspec->name);
17478 clutter_transition_set_interval (res, interval);
17479 clutter_transition_set_remove_on_complete (res, TRUE);
17481 timeline = CLUTTER_TIMELINE (res);
17482 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17483 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17484 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17486 /* this will start the transition as well */
17487 clutter_actor_add_transition (actor, pspec->name, res);
17489 /* the actor now owns the transition */
17490 g_object_unref (res);
17493 res = clos->transition;
17497 clutter_actor_restore_easing_state (actor);
17505 * clutter_actor_add_transition:
17506 * @self: a #ClutterActor
17507 * @name: the name of the transition to add
17508 * @transition: the #ClutterTransition to add
17510 * Adds a @transition to the #ClutterActor's list of animations.
17512 * The @name string is a per-actor unique identifier of the @transition: only
17513 * one #ClutterTransition can be associated to the specified @name.
17515 * The @transition will be started once added.
17517 * This function will take a reference on the @transition.
17519 * This function is usually called implicitly when modifying an animatable
17525 clutter_actor_add_transition (ClutterActor *self,
17527 ClutterTransition *transition)
17529 ClutterTimeline *timeline;
17530 TransitionClosure *clos;
17531 ClutterAnimationInfo *info;
17533 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17534 g_return_if_fail (name != NULL);
17535 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17537 info = _clutter_actor_get_animation_info (self);
17539 if (info->transitions == NULL)
17540 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17542 transition_closure_free);
17544 if (g_hash_table_lookup (info->transitions, name) != NULL)
17546 g_warning ("A transition with name '%s' already exists for "
17549 _clutter_actor_get_debug_name (self));
17553 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17555 timeline = CLUTTER_TIMELINE (transition);
17557 clos = g_slice_new (TransitionClosure);
17558 clos->actor = self;
17559 clos->transition = g_object_ref (transition);
17560 clos->name = g_strdup (name);
17561 clos->completed_id = g_signal_connect (timeline, "completed",
17562 G_CALLBACK (on_transition_completed),
17565 CLUTTER_NOTE (ANIMATION,
17566 "Adding transition '%s' [%p] to actor '%s'",
17569 _clutter_actor_get_debug_name (self));
17571 g_hash_table_insert (info->transitions, clos->name, clos);
17572 clutter_timeline_start (timeline);
17576 * clutter_actor_remove_transition:
17577 * @self: a #ClutterActor
17578 * @name: the name of the transition to remove
17580 * Removes the transition stored inside a #ClutterActor using @name
17583 * If the transition is currently in progress, it will be stopped.
17585 * This function releases the reference acquired when the transition
17586 * was added to the #ClutterActor.
17591 clutter_actor_remove_transition (ClutterActor *self,
17594 const ClutterAnimationInfo *info;
17596 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17597 g_return_if_fail (name != NULL);
17599 info = _clutter_actor_get_animation_info_or_defaults (self);
17601 if (info->transitions == NULL)
17604 g_hash_table_remove (info->transitions, name);
17608 * clutter_actor_remove_all_transitions:
17609 * @self: a #ClutterActor
17611 * Removes all transitions associated to @self.
17616 clutter_actor_remove_all_transitions (ClutterActor *self)
17618 const ClutterAnimationInfo *info;
17620 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17622 info = _clutter_actor_get_animation_info_or_defaults (self);
17623 if (info->transitions == NULL)
17626 g_hash_table_remove_all (info->transitions);
17630 * clutter_actor_set_easing_duration:
17631 * @self: a #ClutterActor
17632 * @msecs: the duration of the easing, or %NULL
17634 * Sets the duration of the tweening for animatable properties
17635 * of @self for the current easing state.
17640 clutter_actor_set_easing_duration (ClutterActor *self,
17643 ClutterAnimationInfo *info;
17645 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17647 info = _clutter_actor_get_animation_info (self);
17649 if (info->cur_state == NULL)
17651 g_warning ("You must call clutter_actor_save_easing_state() prior "
17652 "to calling clutter_actor_set_easing_duration().");
17656 if (info->cur_state->easing_duration != msecs)
17657 info->cur_state->easing_duration = msecs;
17661 * clutter_actor_get_easing_duration:
17662 * @self: a #ClutterActor
17664 * Retrieves the duration of the tweening for animatable
17665 * properties of @self for the current easing state.
17667 * Return value: the duration of the tweening, in milliseconds
17672 clutter_actor_get_easing_duration (ClutterActor *self)
17674 const ClutterAnimationInfo *info;
17676 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17678 info = _clutter_actor_get_animation_info_or_defaults (self);
17680 if (info->cur_state != NULL)
17681 return info->cur_state->easing_duration;
17687 * clutter_actor_set_easing_mode:
17688 * @self: a #ClutterActor
17689 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17691 * Sets the easing mode for the tweening of animatable properties
17697 clutter_actor_set_easing_mode (ClutterActor *self,
17698 ClutterAnimationMode mode)
17700 ClutterAnimationInfo *info;
17702 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17703 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17704 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17706 info = _clutter_actor_get_animation_info (self);
17708 if (info->cur_state == NULL)
17710 g_warning ("You must call clutter_actor_save_easing_state() prior "
17711 "to calling clutter_actor_set_easing_mode().");
17715 if (info->cur_state->easing_mode != mode)
17716 info->cur_state->easing_mode = mode;
17720 * clutter_actor_get_easing_mode:
17721 * @self: a #ClutterActor
17723 * Retrieves the easing mode for the tweening of animatable properties
17724 * of @self for the current easing state.
17726 * Return value: an easing mode
17730 ClutterAnimationMode
17731 clutter_actor_get_easing_mode (ClutterActor *self)
17733 const ClutterAnimationInfo *info;
17735 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17737 info = _clutter_actor_get_animation_info_or_defaults (self);
17739 if (info->cur_state != NULL)
17740 return info->cur_state->easing_mode;
17742 return CLUTTER_EASE_OUT_CUBIC;
17746 * clutter_actor_set_easing_delay:
17747 * @self: a #ClutterActor
17748 * @msecs: the delay before the start of the tweening, in milliseconds
17750 * Sets the delay that should be applied before tweening animatable
17756 clutter_actor_set_easing_delay (ClutterActor *self,
17759 ClutterAnimationInfo *info;
17761 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17763 info = _clutter_actor_get_animation_info (self);
17765 if (info->cur_state == NULL)
17767 g_warning ("You must call clutter_actor_save_easing_state() prior "
17768 "to calling clutter_actor_set_easing_delay().");
17772 if (info->cur_state->easing_delay != msecs)
17773 info->cur_state->easing_delay = msecs;
17777 * clutter_actor_get_easing_delay:
17778 * @self: a #ClutterActor
17780 * Retrieves the delay that should be applied when tweening animatable
17783 * Return value: a delay, in milliseconds
17788 clutter_actor_get_easing_delay (ClutterActor *self)
17790 const ClutterAnimationInfo *info;
17792 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17794 info = _clutter_actor_get_animation_info_or_defaults (self);
17796 if (info->cur_state != NULL)
17797 return info->cur_state->easing_delay;
17803 * clutter_actor_get_transition:
17804 * @self: a #ClutterActor
17805 * @name: the name of the transition
17807 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17808 * transition @name.
17810 * Transitions created for animatable properties use the name of the
17811 * property itself, for instance the code below:
17814 * clutter_actor_set_easing_duration (actor, 1000);
17815 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17817 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17818 * g_signal_connect (transition, "completed",
17819 * G_CALLBACK (on_transition_complete),
17823 * will call the <function>on_transition_complete</function> callback when
17824 * the transition is complete.
17826 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17827 * was found to match the passed name; the returned instance is owned
17828 * by Clutter and it should not be freed
17832 ClutterTransition *
17833 clutter_actor_get_transition (ClutterActor *self,
17836 TransitionClosure *clos;
17837 const ClutterAnimationInfo *info;
17839 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17840 g_return_val_if_fail (name != NULL, NULL);
17842 info = _clutter_actor_get_animation_info_or_defaults (self);
17843 if (info->transitions == NULL)
17846 clos = g_hash_table_lookup (info->transitions, name);
17850 return clos->transition;
17854 * clutter_actor_save_easing_state:
17855 * @self: a #ClutterActor
17857 * Saves the current easing state for animatable properties, and creates
17858 * a new state with the default values for easing mode and duration.
17863 clutter_actor_save_easing_state (ClutterActor *self)
17865 ClutterAnimationInfo *info;
17868 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17870 info = _clutter_actor_get_animation_info (self);
17872 if (info->states == NULL)
17873 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17875 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17876 new_state.easing_duration = 250;
17877 new_state.easing_delay = 0;
17879 g_array_append_val (info->states, new_state);
17881 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17885 * clutter_actor_restore_easing_state:
17886 * @self: a #ClutterActor
17888 * Restores the easing state as it was prior to a call to
17889 * clutter_actor_save_easing_state().
17894 clutter_actor_restore_easing_state (ClutterActor *self)
17896 ClutterAnimationInfo *info;
17898 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17900 info = _clutter_actor_get_animation_info (self);
17902 if (info->states == NULL)
17904 g_critical ("The function clutter_actor_restore_easing_state() has "
17905 "called without a previous call to "
17906 "clutter_actor_save_easing_state().");
17910 g_array_remove_index (info->states, info->states->len - 1);
17912 if (info->states->len > 0)
17913 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17916 g_array_unref (info->states);
17917 info->states = NULL;
17918 info->cur_state = NULL;
17923 * clutter_actor_set_content:
17924 * @self: a #ClutterActor
17925 * @content: (allow-none): a #ClutterContent, or %NULL
17927 * Sets the contents of a #ClutterActor.
17932 clutter_actor_set_content (ClutterActor *self,
17933 ClutterContent *content)
17935 ClutterActorPrivate *priv;
17937 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17938 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17942 if (priv->content != NULL)
17944 _clutter_content_detached (priv->content, self);
17945 g_clear_object (&priv->content);
17948 priv->content = content;
17950 if (priv->content != NULL)
17952 g_object_ref (priv->content);
17953 _clutter_content_attached (priv->content, self);
17956 /* given that the content is always painted within the allocation,
17957 * we only need to queue a redraw here
17959 clutter_actor_queue_redraw (self);
17961 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17963 /* if the content gravity is not resize-fill, and the new content has a
17964 * different preferred size than the previous one, then the content box
17965 * may have been changed. since we compute that lazily, we just notify
17966 * here, and let whomever watches :content-box do whatever they need to
17969 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17970 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17974 * clutter_actor_get_content:
17975 * @self: a #ClutterActor
17977 * Retrieves the contents of @self.
17979 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17980 * or %NULL if none was set
17985 clutter_actor_get_content (ClutterActor *self)
17987 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17989 return self->priv->content;
17993 * clutter_actor_set_content_gravity:
17994 * @self: a #ClutterActor
17995 * @gravity: the #ClutterContentGravity
17997 * Sets the gravity of the #ClutterContent used by @self.
17999 * See the description of the #ClutterActor:content-gravity property for
18000 * more information.
18002 * The #ClutterActor:content-gravity property is animatable.
18007 clutter_actor_set_content_gravity (ClutterActor *self,
18008 ClutterContentGravity gravity)
18010 ClutterActorPrivate *priv;
18012 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18016 if (priv->content_gravity == gravity)
18019 priv->content_box_valid = FALSE;
18021 if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
18023 ClutterActorBox from_box, to_box;
18025 clutter_actor_get_content_box (self, &from_box);
18027 priv->content_gravity = gravity;
18029 clutter_actor_get_content_box (self, &to_box);
18031 _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
18037 ClutterActorBox to_box;
18039 priv->content_gravity = gravity;
18041 clutter_actor_get_content_box (self, &to_box);
18043 _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
18047 clutter_actor_queue_redraw (self);
18049 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
18053 * clutter_actor_get_content_gravity:
18054 * @self: a #ClutterActor
18056 * Retrieves the content gravity as set using
18057 * clutter_actor_get_content_gravity().
18059 * Return value: the content gravity
18063 ClutterContentGravity
18064 clutter_actor_get_content_gravity (ClutterActor *self)
18066 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
18067 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
18069 return self->priv->content_gravity;
18073 * clutter_actor_get_content_box:
18074 * @self: a #ClutterActor
18075 * @box: (out caller-allocates): the return location for the bounding
18076 * box for the #ClutterContent
18078 * Retrieves the bounding box for the #ClutterContent of @self.
18080 * The bounding box is relative to the actor's allocation.
18082 * If no #ClutterContent is set for @self, or if @self has not been
18083 * allocated yet, then the result is undefined.
18085 * The content box is guaranteed to be, at most, as big as the allocation
18086 * of the #ClutterActor.
18088 * If the #ClutterContent used by the actor has a preferred size, then
18089 * it is possible to modify the content box by using the
18090 * #ClutterActor:content-gravity property.
18095 clutter_actor_get_content_box (ClutterActor *self,
18096 ClutterActorBox *box)
18098 ClutterActorPrivate *priv;
18099 gfloat content_w, content_h;
18100 gfloat alloc_w, alloc_h;
18102 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18103 g_return_if_fail (box != NULL);
18109 box->x2 = priv->allocation.x2 - priv->allocation.x1;
18110 box->y2 = priv->allocation.y2 - priv->allocation.y1;
18112 if (priv->content_box_valid)
18114 *box = priv->content_box;
18118 /* no need to do any more work */
18119 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18122 if (priv->content == NULL)
18125 /* if the content does not have a preferred size then there is
18126 * no point in computing the content box
18128 if (!clutter_content_get_preferred_size (priv->content,
18136 switch (priv->content_gravity)
18138 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18139 box->x2 = box->x1 + MIN (content_w, alloc_w);
18140 box->y2 = box->y1 + MIN (content_h, alloc_h);
18143 case CLUTTER_CONTENT_GRAVITY_TOP:
18144 if (alloc_w > content_w)
18146 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18147 box->x2 = box->x1 + content_w;
18149 box->y2 = box->y1 + MIN (content_h, alloc_h);
18152 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18153 if (alloc_w > content_w)
18155 box->x1 += (alloc_w - content_w);
18156 box->x2 = box->x1 + content_w;
18158 box->y2 = box->y1 + MIN (content_h, alloc_h);
18161 case CLUTTER_CONTENT_GRAVITY_LEFT:
18162 box->x2 = box->x1 + MIN (content_w, alloc_w);
18163 if (alloc_h > content_h)
18165 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18166 box->y2 = box->y1 + content_h;
18170 case CLUTTER_CONTENT_GRAVITY_CENTER:
18171 if (alloc_w > content_w)
18173 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18174 box->x2 = box->x1 + content_w;
18176 if (alloc_h > content_h)
18178 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18179 box->y2 = box->y1 + content_h;
18183 case CLUTTER_CONTENT_GRAVITY_RIGHT:
18184 if (alloc_w > content_w)
18186 box->x1 += (alloc_w - content_w);
18187 box->x2 = box->x1 + content_w;
18189 if (alloc_h > content_h)
18191 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18192 box->y2 = box->y1 + content_h;
18196 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18197 box->x2 = box->x1 + MIN (content_w, alloc_w);
18198 if (alloc_h > content_h)
18200 box->y1 += (alloc_h - content_h);
18201 box->y2 = box->y1 + content_h;
18205 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18206 if (alloc_w > content_w)
18208 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18209 box->x2 = box->x1 + content_w;
18211 if (alloc_h > content_h)
18213 box->y1 += (alloc_h - content_h);
18214 box->y2 = box->y1 + content_h;
18218 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18219 if (alloc_w > content_w)
18221 box->x1 += (alloc_w - content_w);
18222 box->x2 = box->x1 + content_w;
18224 if (alloc_h > content_h)
18226 box->y1 += (alloc_h - content_h);
18227 box->y2 = box->y1 + content_h;
18231 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18232 g_assert_not_reached ();
18235 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18237 double r_c = content_w / content_h;
18241 if ((alloc_w / r_c) > alloc_h)
18246 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18247 box->y2 = box->y1 + (alloc_w / r_c);
18254 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18255 box->x2 = box->x1 + (alloc_h * r_c);
18260 if ((alloc_w / r_c) > alloc_h)
18265 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18266 box->x2 = box->x1 + (alloc_h * r_c);
18273 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18274 box->y2 = box->y1 + (alloc_w / r_c);
18278 CLUTTER_NOTE (LAYOUT,
18279 "r_c: %.3f, r_a: %.3f\t"
18280 "a: [%.2fx%.2f], c: [%.2fx%.2f]\t"
18281 "b: [%.2f, %.2f, %.2f, %.2f]",
18282 r_c, alloc_w / alloc_h,
18284 content_w, content_h,
18285 box->x1, box->y1, box->x2, box->y2);
18292 * clutter_actor_set_content_scaling_filters:
18293 * @self: a #ClutterActor
18294 * @min_filter: the minification filter for the content
18295 * @mag_filter: the magnification filter for the content
18297 * Sets the minification and magnification filter to be applied when
18298 * scaling the #ClutterActor:content of a #ClutterActor.
18300 * The #ClutterActor:minification-filter will be used when reducing
18301 * the size of the content; the #ClutterActor:magnification-filter
18302 * will be used when increasing the size of the content.
18307 clutter_actor_set_content_scaling_filters (ClutterActor *self,
18308 ClutterScalingFilter min_filter,
18309 ClutterScalingFilter mag_filter)
18311 ClutterActorPrivate *priv;
18315 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18318 obj = G_OBJECT (self);
18320 g_object_freeze_notify (obj);
18324 if (priv->min_filter != min_filter)
18326 priv->min_filter = min_filter;
18329 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18332 if (priv->mag_filter != mag_filter)
18334 priv->mag_filter = mag_filter;
18337 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18341 clutter_actor_queue_redraw (self);
18343 g_object_thaw_notify (obj);
18347 * clutter_actor_get_content_scaling_filters:
18348 * @self: a #ClutterActor
18349 * @min_filter: (out) (allow-none): return location for the minification
18351 * @mag_filter: (out) (allow-none): return location for the magnification
18354 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18359 clutter_actor_get_content_scaling_filters (ClutterActor *self,
18360 ClutterScalingFilter *min_filter,
18361 ClutterScalingFilter *mag_filter)
18363 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18365 if (min_filter != NULL)
18366 *min_filter = self->priv->min_filter;
18368 if (mag_filter != NULL)
18369 *mag_filter = self->priv->mag_filter;
18373 * clutter_actor_queue_compute_expand:
18374 * @self: a #ClutterActor
18376 * Invalidates the needs_x_expand and needs_y_expand flags on @self
18377 * and its parents up to the top-level actor.
18379 * This function also queues a relayout if anything changed.
18382 clutter_actor_queue_compute_expand (ClutterActor *self)
18384 ClutterActor *parent;
18387 if (self->priv->needs_compute_expand)
18392 while (parent != NULL)
18394 if (!parent->priv->needs_compute_expand)
18396 parent->priv->needs_compute_expand = TRUE;
18400 parent = parent->priv->parent;
18404 clutter_actor_queue_relayout (self);
18408 * clutter_actor_set_x_expand:
18409 * @self: a #ClutterActor
18410 * @expand: whether the actor should expand horizontally
18412 * Sets whether a #ClutterActor should expand horizontally; this means
18413 * that layout manager should allocate extra space for the actor, if
18416 * Setting an actor to expand will also make all its parent expand, so
18417 * that it's possible to build an actor tree and only set this flag on
18418 * its leaves and not on every single actor.
18423 clutter_actor_set_x_expand (ClutterActor *self,
18426 ClutterLayoutInfo *info;
18428 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18432 info = _clutter_actor_get_layout_info (self);
18433 if (info->x_expand != expand)
18435 info->x_expand = expand;
18437 self->priv->x_expand_set = TRUE;
18439 clutter_actor_queue_compute_expand (self);
18441 g_object_notify_by_pspec (G_OBJECT (self),
18442 obj_props[PROP_X_EXPAND]);
18447 * clutter_actor_get_x_expand:
18448 * @self: a #ClutterActor
18450 * Retrieves the value set with clutter_actor_set_x_expand().
18452 * See also: clutter_actor_needs_expand()
18454 * Return value: %TRUE if the actor has been set to expand
18459 clutter_actor_get_x_expand (ClutterActor *self)
18461 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18463 return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18467 * clutter_actor_set_y_expand:
18468 * @self: a #ClutterActor
18469 * @expand: whether the actor should expand vertically
18471 * Sets whether a #ClutterActor should expand horizontally; this means
18472 * that layout manager should allocate extra space for the actor, if
18475 * Setting an actor to expand will also make all its parent expand, so
18476 * that it's possible to build an actor tree and only set this flag on
18477 * its leaves and not on every single actor.
18482 clutter_actor_set_y_expand (ClutterActor *self,
18485 ClutterLayoutInfo *info;
18487 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18491 info = _clutter_actor_get_layout_info (self);
18492 if (info->y_expand != expand)
18494 info->y_expand = expand;
18496 self->priv->y_expand_set = TRUE;
18498 clutter_actor_queue_compute_expand (self);
18500 g_object_notify_by_pspec (G_OBJECT (self),
18501 obj_props[PROP_Y_EXPAND]);
18506 * clutter_actor_get_y_expand:
18507 * @self: a #ClutterActor
18509 * Retrieves the value set with clutter_actor_set_y_expand().
18511 * See also: clutter_actor_needs_expand()
18513 * Return value: %TRUE if the actor has been set to expand
18518 clutter_actor_get_y_expand (ClutterActor *self)
18520 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18522 return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18526 clutter_actor_compute_expand_recursive (ClutterActor *self,
18527 gboolean *x_expand_p,
18528 gboolean *y_expand_p)
18530 ClutterActorIter iter;
18531 ClutterActor *child;
18532 gboolean x_expand, y_expand;
18534 x_expand = y_expand = FALSE;
18536 /* note that we don't recurse into children if we're already set to expand;
18537 * this avoids traversing the whole actor tree, even if it may lead to some
18538 * child left with the needs_compute_expand flag set.
18540 clutter_actor_iter_init (&iter, self);
18541 while (clutter_actor_iter_next (&iter, &child))
18543 x_expand = x_expand ||
18544 clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL);
18546 y_expand = y_expand ||
18547 clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL);
18550 *x_expand_p = x_expand;
18551 *y_expand_p = y_expand;
18555 clutter_actor_compute_expand (ClutterActor *self)
18557 if (self->priv->needs_compute_expand)
18559 const ClutterLayoutInfo *info;
18560 gboolean x_expand, y_expand;
18562 info = _clutter_actor_get_layout_info_or_defaults (self);
18564 if (self->priv->x_expand_set)
18565 x_expand = info->x_expand;
18569 if (self->priv->y_expand_set)
18570 y_expand = info->y_expand;
18574 /* we don't need to recurse down to the children if the
18575 * actor has been forcibly set to expand
18577 if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18579 if (self->priv->n_children != 0)
18581 gboolean *x_expand_p, *y_expand_p;
18582 gboolean ignored = FALSE;
18584 x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18585 y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18587 clutter_actor_compute_expand_recursive (self,
18593 self->priv->needs_compute_expand = FALSE;
18594 self->priv->needs_x_expand = (x_expand != FALSE);
18595 self->priv->needs_y_expand = (y_expand != FALSE);
18600 * clutter_actor_needs_expand:
18601 * @self: a #ClutterActor
18602 * @orientation: the direction of expansion
18604 * Checks whether an actor, or any of its children, is set to expand
18605 * horizontally or vertically.
18607 * This function should only be called by layout managers that can
18608 * assign extra space to their children.
18610 * If you want to know whether the actor was explicitly set to expand,
18611 * use clutter_actor_get_x_expand() or clutter_actor_get_y_expand().
18613 * Return value: %TRUE if the actor should expand
18618 clutter_actor_needs_expand (ClutterActor *self,
18619 ClutterOrientation orientation)
18621 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18623 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18626 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18629 clutter_actor_compute_expand (self);
18631 switch (orientation)
18633 case CLUTTER_ORIENTATION_HORIZONTAL:
18634 return self->priv->needs_x_expand;
18636 case CLUTTER_ORIENTATION_VERTICAL:
18637 return self->priv->needs_y_expand;