4 * An OpenGL based 'interactive canvas' library.
6 * Authored By Matthew Allum <mallum@openedhand.com>
8 * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9 * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
26 * SECTION:clutter-actor
27 * @short_description: The basic element of the scene graph
29 * The ClutterActor class is the basic element of the scene graph in Clutter,
30 * and it encapsulates the position, size, and transformations of a node in
33 * <refsect2 id="ClutterActor-transformations">
34 * <title>Actor transformations</title>
35 * <para>Each actor can be transformed using methods like
36 * clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37 * in which the transformations are applied is decided by Clutter and it is
38 * the following:</para>
40 * <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41 * <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42 * <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43 * <listitem><para>rotation around the #ClutterActor:rotation-angle-x and #ClutterActor:rotation-center-x;</para></listitem>
44 * <listitem><para>rotation around the #ClutterActor:rotation-angle-y and #ClutterActor:rotation-center-y;</para></listitem>
45 * <listitem><para>rotation around the #ClutterActor:rotation-angle-z and #ClutterActor:rotation-center-z;</para></listitem>
46 * <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
50 * <refsect2 id="ClutterActor-geometry">
51 * <title>Modifying an actor's geometry</title>
52 * <para>Each actor has a bounding box, called #ClutterActor:allocation
53 * which is either set by its parent or explicitly through the
54 * clutter_actor_set_position() and clutter_actor_set_size() methods.
55 * Each actor also has an implicit preferred size.</para>
56 * <para>An actor’s preferred size can be defined by any subclass by
57 * overriding the #ClutterActorClass.get_preferred_width() and the
58 * #ClutterActorClass.get_preferred_height() virtual functions, or it can
59 * be explicitly set by using clutter_actor_set_width() and
60 * clutter_actor_set_height().</para>
61 * <para>An actor’s position can be set explicitly by using
62 * clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63 * relative to the origin of the actor’s parent.</para>
66 * <refsect2 id="ClutterActor-children">
67 * <title>Managing actor children</title>
68 * <para>Each actor can have multiple children, by calling
69 * clutter_actor_add_child() to add a new child actor, and
70 * clutter_actor_remove_child() to remove an existing child. #ClutterActor
71 * will hold a reference on each child actor, which will be released when
72 * the child is removed from its parent, or destroyed using
73 * clutter_actor_destroy().</para>
74 * <informalexample><programlisting>
75 * ClutterActor *actor = clutter_actor_new ();
77 * /* set the bounding box of the actor */
78 * clutter_actor_set_position (actor, 0, 0);
79 * clutter_actor_set_size (actor, 480, 640);
81 * /* set the background color of the actor */
82 * clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
84 * /* set the bounding box of the child, relative to the parent */
85 * ClutterActor *child = clutter_actor_new ();
86 * clutter_actor_set_position (child, 20, 20);
87 * clutter_actor_set_size (child, 80, 240);
89 * /* set the background color of the child */
90 * clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
92 * /* add the child to the actor */
93 * clutter_actor_add_child (actor, child);
94 * </programlisting></informalexample>
95 * <para>Children can be inserted at a given index, or above and below
96 * another child actor. The order of insertion determines the order of the
97 * children when iterating over them. Iterating over children is performed
98 * by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99 * clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100 * also possible to retrieve a list of children by using
101 * clutter_actor_get_children(), as well as retrieving a specific child at a
102 * given index by using clutter_actor_get_child_at_index().</para>
103 * <para>If you need to track additions of children to a #ClutterActor, use
104 * the #ClutterContainer::actor-added signal; similarly, to track removals
105 * of children from a ClutterActor, use the #ClutterContainer::actor-removed
107 * <informalexample><programlisting>
108 * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../examples/basic-actor.c">
109 * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
111 * </programlisting></informalexample>
112 * <figure id="actor-example-image">
113 * <title>Actors</title>
114 * <graphic fileref="actor-example.png" format="PNG"/>
118 * <refsect2 id="ClutterActor-painting">
119 * <title>Painting an actor</title>
120 * <para>There are three ways to paint an actor:</para>
122 * <listitem><para>set a delegate #ClutterContent as the value for the
123 * #ClutterActor:content property of the actor;</para></listitem>
124 * <listitem><para>subclass #ClutterActor and override the
125 * #ClutterActorClass.paint_node() virtual function;</para></listitem>
126 * <listitem><para>subclass #ClutterActor and override the
127 * #ClutterActorClass.paint() virtual function.</para></listitem>
130 * <title>Setting the Content property</title>
131 * <para>A #ClutterContent is a delegate object that takes over the
132 * painting operation of one, or more actors. The #ClutterContent
133 * painting will be performed on top of the #ClutterActor:background-color
134 * of the actor, and before calling the #ClutterActorClass.paint_node()
135 * virtual function.</para>
136 * <informalexample><programlisting>
137 * ClutterActor *actor = clutter_actor_new ();
139 * /* set the bounding box */
140 * clutter_actor_set_position (actor, 50, 50);
141 * clutter_actor_set_size (actor, 100, 100);
143 * /* set the content; the image_content variable is set elsewhere */
144 * clutter_actor_set_content (actor, image_content);
145 * </programlisting></informalexample>
148 * <title>Overriding the paint_node virtual function</title>
149 * <para>The #ClutterActorClass.paint_node() virtual function is invoked
150 * whenever an actor needs to be painted. The implementation of the
151 * virtual function must only paint the contents of the actor itself,
152 * and not the contents of its children, if the actor has any.</para>
153 * <para>The #ClutterPaintNode passed to the virtual function is the
154 * local root of the render tree; any node added to it will be
155 * rendered at the correct position, as defined by the actor's
156 * #ClutterActor:allocation.</para>
157 * <informalexample><programlisting>
159 * my_actor_paint_node (ClutterActor *actor,
160 * ClutterPaintNode *root)
162 * ClutterPaintNode *node;
163 * ClutterActorBox box;
165 * /* where the content of the actor should be painted */
166 * clutter_actor_get_allocation_box (actor, &box);
168 * /* the cogl_texture variable is set elsewhere */
169 * node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170 * CLUTTER_SCALING_FILTER_TRILINEAR,
171 * CLUTTER_SCALING_FILTER_LINEAR);
173 * /* paint the content of the node using the allocation */
174 * clutter_paint_node_add_rectangle (node, &box);
176 * /* add the node, and transfer ownership */
177 * clutter_paint_node_add_child (root, node);
178 * clutter_paint_node_unref (node);
180 * </programlisting></informalexample>
183 * <title>Overriding the paint virtual function</title>
184 * <para>The #ClutterActorClass.paint() virtual function is invoked
185 * when the #ClutterActor::paint signal is emitted, and after the other
186 * signal handlers have been invoked. Overriding the paint virtual
187 * function gives total control to the paint sequence of the actor
188 * itself, including the children of the actor, if any.</para>
189 * <warning><para>It is strongly discouraged to override the
190 * #ClutterActorClass.paint() virtual function, as well as connecting
191 * to the #ClutterActor::paint signal. These hooks into the paint
192 * sequence are considered legacy, and will be removed when the Clutter
193 * API changes.</para></warning>
197 * <refsect2 id="ClutterActor-events">
198 * <title>Handling events on an actor</title>
199 * <para>A #ClutterActor can receive and handle input device events, for
200 * instance pointer events and key events, as long as its
201 * #ClutterActor:reactive property is set to %TRUE.</para>
202 * <para>Once an actor has been determined to be the source of an event,
203 * Clutter will traverse the scene graph from the top-level actor towards the
204 * event source, emitting the #ClutterActor::captured-event signal on each
205 * ancestor until it reaches the source; this phase is also called
206 * <emphasis>the capture phase</emphasis>. If the event propagation was not
207 * stopped, the graph is walked backwards, from the source actor to the
208 * top-level, and the #ClutterActor::event signal, along with other event
209 * signals if needed, is emitted; this phase is also called <emphasis>the
210 * bubble phase</emphasis>. At any point of the signal emission, signal
211 * handlers can stop the propagation through the scene graph by returning
212 * %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213 * returning %CLUTTER_EVENT_PROPAGATE.</para>
216 * <refsect2 id="ClutterActor-animation">
217 * <title>Animation</title>
218 * <para>Animation is a core concept of modern user interfaces; Clutter
219 * provides a complete and powerful animation framework that automatically
220 * tweens the actor's state without requiring direct, frame by frame
221 * manipulation from your application code.</para>
223 * <title>Implicit animations</title>
224 * <para>The implicit animation model of Clutter assumes that all the
225 * changes in an actor state should be gradual and asynchronous; Clutter
226 * will automatically transition an actor's property change between the
227 * current state and the desired one without manual intervention.</para>
228 * <para>By default, in the 1.0 API series, the transition happens with
229 * a duration of zero milliseconds, and the implicit animation is an
230 * opt in feature to retain backwards compatibility. In order to enable
231 * implicit animations, it is necessary to change the easing state of
232 * an actor by using clutter_actor_save_easing_state():</para>
233 * <informalexample><programlisting>
234 * /* assume that the actor is currently positioned at (100, 100) */
235 * clutter_actor_save_easing_state (actor);
236 * clutter_actor_set_position (actor, 500, 500);
237 * clutter_actor_restore_easing_state (actor);
238 * </programlisting></informalexample>
239 * <para>The example above will trigger an implicit animation of the
240 * actor between its current position to a new position.</para>
241 * <para>It is possible to animate multiple properties of an actor
242 * at the same time, and you can animate multiple actors at the same
243 * time as well, for instance:</para>
244 * <informalexample><programlisting>
245 * /* animate the actor's opacity and depth */
246 * clutter_actor_save_easing_state (actor);
247 * clutter_actor_set_opacity (actor, 0);
248 * clutter_actor_set_depth (actor, -100);
249 * clutter_actor_restore_easing_state (actor);
251 * /* animate another actor's opacity */
252 * clutter_actor_save_easing_state (another_actor);
253 * clutter_actor_set_opacity (another_actor, 255);
254 * clutter_actor_set_depth (another_actor, 100);
255 * clutter_actor_restore_easing_state (another_actor);
256 * </programlisting></informalexample>
257 * <para>Implicit animations use a default duration of 250 milliseconds,
258 * and a default easing mode of %CLUTTER_EASE_OUT_CUBIC, unless you call
259 * clutter_actor_set_easing_mode() and clutter_actor_set_easing_duration()
260 * after changing the easing state of the actor.</para>
261 * <para>It is important to note that if you modify the state on an
262 * animatable property while a transition is in flight, the transition's
263 * final value will be updated, as well as its duration and progress
264 * mode by using the current easing state; for instance, in the following
266 * <informalexample><programlisting>
267 * clutter_actor_save_easing_state (actor);
268 * clutter_actor_set_x (actor, 200);
269 * clutter_actor_restore_easing_state (actor);
271 * clutter_actor_save_easing_state (actor);
272 * clutter_actor_set_x (actor, 100);
273 * clutter_actor_restore_easing_state (actor);
274 * </programlisting></informalexample>
275 * <para>the first call to clutter_actor_set_x() will begin a transition
276 * of the #ClutterActor:x property to the value of 200; the second call
277 * to clutter_actor_set_x() will change the transition's final value to
279 * <para>It is possible to retrieve the #ClutterTransition used by the
280 * animatable properties by using clutter_actor_get_transition() and using
281 * the property name as the transition name.</para>
284 * <title>Explicit animations</title>
285 * <para>The explicit animation model supported by Clutter requires that
286 * you create a #ClutterTransition object, and set the initial and
287 * final values. The transition will not start unless you add it to the
288 * #ClutterActor.</para>
289 * <informalexample><programlisting>
290 * ClutterTransition *transition;
292 * transition = clutter_property_transition_new ("opacity");
293 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000);
294 * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
295 * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
296 * clutter_transition_set_from (transition, G_TYPE_UINT, 255);
297 * clutter_transition_set_to (transition, G_TYPE_UINT, 0);
299 * clutter_actor_add_transition (actor, "animate-opacity", transition);
300 * </programlisting></informalexample>
301 * <para>The example above will animate the #ClutterActor:opacity property
302 * of an actor between fully opaque and fully transparent, and back, over
303 * a span of 3 seconds. The animation does not begin until it is added to
305 * <para>The explicit animation API should also be used when using custom
306 * animatable properties for #ClutterAction, #ClutterConstraint, and
307 * #ClutterEffect instances associated to an actor; see the section on
308 * <ulink linkend="ClutterActor-custom-animatable-properties">custom
309 * animatable properties below</ulink> for an example.</para>
310 * <para>Finally, explicit animations are useful for creating animations
311 * that run continuously, for instance:</para>
312 * <informalexample><programlisting>
313 * /* this animation will pulse the actor's opacity continuously */
314 * ClutterTransition *transition;
315 * ClutterInterval *interval;
317 * transition = clutter_property_transition_new ("opacity");
319 * /* we want to animate the opacity between 0 and 255 */
320 * clutter_transition_set_from (transition, G_TYPE_UINT, 0);
321 * clutter_transition_set_to (transition, G_TYPE_UINT, 255);
323 * /* over a one second duration, running an infinite amount of times */
324 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
325 * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
327 * /* we want to fade in and out, so we need to auto-reverse the transition */
328 * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
330 * /* and we want to use an easing function that eases both in and out */
331 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
332 * CLUTTER_EASE_IN_OUT_CUBIC);
334 * /* add the transition to the desired actor; this will
335 * * start the animation.
337 * clutter_actor_add_transition (actor, "opacityAnimation", transition);
338 * </programlisting></informalexample>
342 * <refsect2 id="ClutterActor-subclassing">
343 * <title>Implementing an actor</title>
344 * <para>Careful consideration should be given when deciding to implement
345 * a #ClutterActor sub-class. It is generally recommended to implement a
346 * sub-class of #ClutterActor only for actors that should be used as leaf
347 * nodes of a scene graph.</para>
348 * <para>If your actor should be painted in a custom way, you should
349 * override the #ClutterActor::paint signal class handler. You can either
350 * opt to chain up to the parent class implementation or decide to fully
351 * override the default paint implementation; Clutter will set up the
352 * transformations and clip regions prior to emitting the #ClutterActor::paint
354 * <para>By overriding the #ClutterActorClass.get_preferred_width() and
355 * #ClutterActorClass.get_preferred_height() virtual functions it is
356 * possible to change or provide the preferred size of an actor; similarly,
357 * by overriding the #ClutterActorClass.allocate() virtual function it is
358 * possible to control the layout of the children of an actor. Make sure to
359 * always chain up to the parent implementation of the
360 * #ClutterActorClass.allocate() virtual function.</para>
361 * <para>In general, it is strongly encouraged to use delegation and
362 * composition instead of direct subclassing.</para>
365 * <refsect2 id="ClutterActor-script">
366 * <title>ClutterActor custom properties for #ClutterScript</title>
367 * <para>#ClutterActor defines a custom "rotation" property which
368 * allows a short-hand description of the rotations to be applied
369 * to an actor.</para>
370 * <para>The syntax of the "rotation" property is the following:</para>
374 * { "<axis>" : [ <angle>, [ <center> ] ] }
378 * <para>where the <emphasis>axis</emphasis> is the name of an enumeration
379 * value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
380 * floating point value representing the rotation angle on the given axis,
382 * <para>The <emphasis>center</emphasis> array is optional, and if present
383 * it must contain the center of rotation as described by two coordinates:
384 * Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
386 * <para>#ClutterActor also defines a scriptable "margin" property which
387 * follows the CSS "margin" shorthand.
391 * "margin" : [ <top>, <right>, <bottom> <left> ]
393 * "margin" : [ <top>, <left/right>, <bottom> ]
395 * "margin" : [ <top/bottom>, <left/right> ]
397 * "margin" : [ <top/right/bottom/left> ]
401 * <para>#ClutterActor will also parse every positional and dimensional
402 * property defined as a string through clutter_units_from_string(); you
403 * should read the documentation for the #ClutterUnits parser format for
404 * the valid units and syntax.</para>
407 * <refsect2 id="ClutterActor-custom-animatable-properties">
408 * <title>Custom animatable properties</title>
409 * <para>#ClutterActor allows accessing properties of #ClutterAction,
410 * #ClutterEffect, and #ClutterConstraint instances associated to an actor
411 * instance for animation purposes.</para>
412 * <para>In order to access a specific #ClutterAction or a #ClutterConstraint
413 * property it is necessary to set the #ClutterActorMeta:name property on the
414 * given action or constraint.</para>
415 * <para>The property can be accessed using the following syntax:</para>
418 * @<section>.<meta-name>.<property-name>
421 * <para>The initial <emphasis>@</emphasis> is mandatory.</para>
422 * <para>The <emphasis>section</emphasis> fragment can be one between
423 * "actions", "constraints" and "effects".</para>
424 * <para>The <emphasis>meta-name</emphasis> fragment is the name of the
425 * action or constraint, as specified by the #ClutterActorMeta:name
427 * <para>The <emphasis>property-name</emphasis> fragment is the name of the
428 * action or constraint property to be animated.</para>
429 * <para>The example below animates a #ClutterBindConstraint applied to an
430 * actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
431 * a binding constraint for the <emphasis>origin</emphasis> actor, and in
432 * its initial state is overlapping the actor to which is bound to.</para>
433 * <informalexample><programlisting>
434 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
435 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
436 * clutter_actor_add_constraint (rect, constraint);
438 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
439 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
440 * clutter_actor_add_constraint (rect, constraint);
442 * clutter_actor_set_reactive (origin, TRUE);
444 * g_signal_connect (origin, "button-press-event",
445 * G_CALLBACK (on_button_press),
447 * </programlisting></informalexample>
448 * <para>On button press, the rectangle "slides" from behind the actor to
449 * which is bound to, using the #ClutterBindConstraint:offset property to
450 * achieve the effect:</para>
451 * <informalexample><programlisting>
453 * on_button_press (ClutterActor *origin,
454 * ClutterEvent *event,
455 * ClutterActor *rect)
457 * ClutterTransition *transition;
458 * ClutterInterval *interval;
460 * /* the offset that we want to apply; this will make the actor
461 * * slide in from behind the origin and rest at the right of
462 * * the origin, plus a padding value.
464 * float new_offset = clutter_actor_get_width (origin) + h_padding;
466 * /* the property we wish to animate; the "@constraints" section
467 * * tells Clutter to check inside the constraints associated
468 * * with the actor; the "bind-x" section is the name of the
469 * * constraint; and the "offset" is the name of the property
470 * * on the constraint.
472 * const char *prop = "@constraints.bind-x.offset";
474 * /* create a new transition for the given property */
475 * transition = clutter_property_transition_new (prop);
477 * /* set the easing mode and duration */
478 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
479 * CLUTTER_EASE_OUT_CUBIC);
480 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
482 * /* create the interval with the initial and final values */
483 * interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
484 * clutter_transition_set_interval (transition, interval);
486 * /* add the transition to the actor; this causes the animation
487 * * to start. the name "offsetAnimation" can be used to retrieve
488 * * the transition later.
490 * clutter_actor_add_transition (rect, "offsetAnimation", transition);
492 * /* we handled the event */
493 * return CLUTTER_EVENT_STOP;
495 * </programlisting></informalexample>
500 * CLUTTER_ACTOR_IS_MAPPED:
501 * @a: a #ClutterActor
503 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
505 * The mapped state is set when the actor is visible and all its parents up
506 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
508 * This check can be used to see if an actor is going to be painted, as only
509 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
511 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
512 * not be checked directly; instead, the recommended usage is to connect a
513 * handler on the #GObject::notify signal for the #ClutterActor:mapped
514 * property of #ClutterActor, and check the presence of
515 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
517 * It is also important to note that Clutter may delay the changes of
518 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
519 * limitations, or during the reparenting of an actor, to optimize
520 * unnecessary (and potentially expensive) state changes.
526 * CLUTTER_ACTOR_IS_REALIZED:
527 * @a: a #ClutterActor
529 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
531 * The realized state has an actor-dependant interpretation. If an
532 * actor wants to delay allocating resources until it is attached to a
533 * stage, it may use the realize state to do so. However it is
534 * perfectly acceptable for an actor to allocate Cogl resources before
535 * being realized because there is only one drawing context used by Clutter
536 * so any resources will work on any stage. If an actor is mapped it
537 * must also be realized, but an actor can be realized and unmapped
538 * (this is so hiding an actor temporarily doesn't do an expensive
539 * unrealize/realize).
541 * To be realized an actor must be inside a stage, and all its parents
548 * CLUTTER_ACTOR_IS_VISIBLE:
549 * @a: a #ClutterActor
551 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
552 * Equivalent to the ClutterActor::visible object property.
554 * Note that an actor is only painted onscreen if it's mapped, which
555 * means it's visible, and all its parents are visible, and one of the
556 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
562 * CLUTTER_ACTOR_IS_REACTIVE:
563 * @a: a #ClutterActor
565 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
567 * Only reactive actors will receive event-related signals.
578 #include <gobject/gvaluecollector.h>
580 #include <cogl/cogl.h>
582 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
583 #define CLUTTER_ENABLE_EXPERIMENTAL_API
585 #include "clutter-actor-private.h"
587 #include "clutter-action.h"
588 #include "clutter-actor-meta-private.h"
589 #include "clutter-animatable.h"
590 #include "clutter-color-static.h"
591 #include "clutter-color.h"
592 #include "clutter-constraint.h"
593 #include "clutter-container.h"
594 #include "clutter-content-private.h"
595 #include "clutter-debug.h"
596 #include "clutter-easing.h"
597 #include "clutter-effect-private.h"
598 #include "clutter-enum-types.h"
599 #include "clutter-fixed-layout.h"
600 #include "clutter-flatten-effect.h"
601 #include "clutter-interval.h"
602 #include "clutter-main.h"
603 #include "clutter-marshal.h"
604 #include "clutter-paint-nodes.h"
605 #include "clutter-paint-node-private.h"
606 #include "clutter-paint-volume-private.h"
607 #include "clutter-private.h"
608 #include "clutter-profile.h"
609 #include "clutter-property-transition.h"
610 #include "clutter-scriptable.h"
611 #include "clutter-script-private.h"
612 #include "clutter-stage-private.h"
613 #include "clutter-timeline.h"
614 #include "clutter-transition.h"
615 #include "clutter-units.h"
617 #include "deprecated/clutter-actor.h"
618 #include "deprecated/clutter-behaviour.h"
619 #include "deprecated/clutter-container.h"
621 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
622 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
624 /* Internal enum used to control mapped state update. This is a hint
625 * which indicates when to do something other than just enforce
629 MAP_STATE_CHECK, /* just enforce invariants. */
630 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
631 * used when about to unparent.
633 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
634 * used to set mapped on toplevels.
636 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
637 * used just before unmapping parent.
641 /* 3 entries should be a good compromise, few layout managers
642 * will ask for 3 different preferred size in each allocation cycle */
643 #define N_CACHED_SIZE_REQUESTS 3
645 struct _ClutterActorPrivate
648 ClutterRequestMode request_mode;
650 /* our cached size requests for different width / height */
651 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
652 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
654 /* An age of 0 means the entry is not set */
655 guint cached_height_age;
656 guint cached_width_age;
658 /* the bounding box of the actor, relative to the parent's
661 ClutterActorBox allocation;
662 ClutterAllocationFlags allocation_flags;
664 /* clip, in actor coordinates */
665 cairo_rectangle_t clip;
667 /* the cached transformation matrix; see apply_transform() */
668 CoglMatrix transform;
671 gint opacity_override;
673 ClutterOffscreenRedirect offscreen_redirect;
675 /* This is an internal effect used to implement the
676 offscreen-redirect property */
677 ClutterEffect *flatten_effect;
680 ClutterActor *parent;
681 ClutterActor *prev_sibling;
682 ClutterActor *next_sibling;
683 ClutterActor *first_child;
684 ClutterActor *last_child;
688 /* tracks whenever the children of an actor are changed; the
689 * age is incremented by 1 whenever an actor is added or
690 * removed. the age is not incremented when the first or the
691 * last child pointers are changed, or when grandchildren of
692 * an actor are changed.
696 gchar *name; /* a non-unique name, used for debugging */
697 guint32 id; /* unique id, used for backward compatibility */
699 gint32 pick_id; /* per-stage unique id, used for picking */
701 /* a back-pointer to the Pango context that we can use
702 * to create pre-configured PangoLayout
704 PangoContext *pango_context;
706 /* the text direction configured for this child - either by
707 * application code, or by the actor's parent
709 ClutterTextDirection text_direction;
711 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
715 ClutterMetaGroup *actions;
716 ClutterMetaGroup *constraints;
717 ClutterMetaGroup *effects;
719 /* delegate object used to allocate the children of this actor */
720 ClutterLayoutManager *layout_manager;
722 /* delegate object used to paint the contents of this actor */
723 ClutterContent *content;
725 ClutterActorBox content_box;
726 ClutterContentGravity content_gravity;
727 ClutterScalingFilter min_filter;
728 ClutterScalingFilter mag_filter;
729 ClutterContentRepeat content_repeat;
731 /* used when painting, to update the paint volume */
732 ClutterEffect *current_effect;
734 /* This is used to store an effect which needs to be redrawn. A
735 redraw can be queued to start from a particular effect. This is
736 used by parametrised effects that can cache an image of the
737 actor. If a parameter of the effect changes then it only needs to
738 redraw the cached image, not the actual actor. The pointer is
739 only valid if is_dirty == TRUE. If the pointer is NULL then the
740 whole actor is dirty. */
741 ClutterEffect *effect_to_redraw;
743 /* This is used when painting effects to implement the
744 clutter_actor_continue_paint() function. It points to the node in
745 the list of effects that is next in the chain */
746 const GList *next_effect_to_paint;
748 ClutterPaintVolume paint_volume;
750 /* NB: This volume isn't relative to this actor, it is in eye
751 * coordinates so that it can remain valid after the actor changes.
753 ClutterPaintVolume last_paint_volume;
755 ClutterStageQueueRedrawEntry *queue_redraw_entry;
757 ClutterColor bg_color;
759 #ifdef CLUTTER_ENABLE_DEBUG
760 /* a string used for debugging messages */
766 /* fixed position and sizes */
767 guint position_set : 1;
768 guint min_width_set : 1;
769 guint min_height_set : 1;
770 guint natural_width_set : 1;
771 guint natural_height_set : 1;
772 /* cached request is invalid (implies allocation is too) */
773 guint needs_width_request : 1;
774 /* cached request is invalid (implies allocation is too) */
775 guint needs_height_request : 1;
776 /* cached allocation is invalid (request has changed, probably) */
777 guint needs_allocation : 1;
778 guint show_on_set_parent : 1;
780 guint clip_to_allocation : 1;
781 guint enable_model_view_transform : 1;
782 guint enable_paint_unmapped : 1;
783 guint has_pointer : 1;
784 guint propagated_one_redraw : 1;
785 guint paint_volume_valid : 1;
786 guint last_paint_volume_valid : 1;
787 guint in_clone_paint : 1;
788 guint transform_valid : 1;
789 /* This is TRUE if anything has queued a redraw since we were last
790 painted. In this case effect_to_redraw will point to an effect
791 the redraw was queued from or it will be NULL if the redraw was
792 queued without an effect. */
794 guint bg_color_set : 1;
795 guint content_box_valid : 1;
796 guint x_expand_set : 1;
797 guint y_expand_set : 1;
798 guint needs_compute_expand : 1;
799 guint needs_x_expand : 1;
800 guint needs_y_expand : 1;
809 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
810 * when set they force a size request, when gotten they
811 * get the allocation if the allocation is valid, and the
822 /* Then the rest of these size-related properties are the "actual"
823 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
828 PROP_FIXED_POSITION_SET,
837 PROP_NATURAL_WIDTH_SET,
840 PROP_NATURAL_HEIGHT_SET,
844 /* Allocation properties are read-only */
851 PROP_CLIP_TO_ALLOCATION,
855 PROP_OFFSCREEN_REDIRECT,
868 PROP_ROTATION_ANGLE_X,
869 PROP_ROTATION_ANGLE_Y,
870 PROP_ROTATION_ANGLE_Z,
871 PROP_ROTATION_CENTER_X,
872 PROP_ROTATION_CENTER_Y,
873 PROP_ROTATION_CENTER_Z,
874 /* This property only makes sense for the z rotation because the
875 others would depend on the actor having a size along the
877 PROP_ROTATION_CENTER_Z_GRAVITY,
883 PROP_SHOW_ON_SET_PARENT,
903 PROP_BACKGROUND_COLOR,
904 PROP_BACKGROUND_COLOR_SET,
910 PROP_CONTENT_GRAVITY,
912 PROP_MINIFICATION_FILTER,
913 PROP_MAGNIFICATION_FILTER,
919 static GParamSpec *obj_props[PROP_LAST];
938 BUTTON_RELEASE_EVENT,
946 TRANSITIONS_COMPLETED,
951 static guint actor_signals[LAST_SIGNAL] = { 0, };
953 typedef struct _TransitionClosure
956 ClutterTransition *transition;
961 static void clutter_container_iface_init (ClutterContainerIface *iface);
962 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
963 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
964 static void atk_implementor_iface_init (AtkImplementorIface *iface);
966 /* These setters are all static for now, maybe they should be in the
967 * public API, but they are perhaps obscure enough to leave only as
970 static void clutter_actor_set_min_width (ClutterActor *self,
972 static void clutter_actor_set_min_height (ClutterActor *self,
974 static void clutter_actor_set_natural_width (ClutterActor *self,
975 gfloat natural_width);
976 static void clutter_actor_set_natural_height (ClutterActor *self,
977 gfloat natural_height);
978 static void clutter_actor_set_min_width_set (ClutterActor *self,
979 gboolean use_min_width);
980 static void clutter_actor_set_min_height_set (ClutterActor *self,
981 gboolean use_min_height);
982 static void clutter_actor_set_natural_width_set (ClutterActor *self,
983 gboolean use_natural_width);
984 static void clutter_actor_set_natural_height_set (ClutterActor *self,
985 gboolean use_natural_height);
986 static void clutter_actor_update_map_state (ClutterActor *self,
987 MapStateChange change);
988 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
990 /* Helper routines for managing anchor coords */
991 static void clutter_anchor_coord_get_units (ClutterActor *self,
992 const AnchorCoord *coord,
996 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
1001 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
1002 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
1003 ClutterGravity gravity);
1005 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
1007 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
1009 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
1010 ClutterActor *ancestor,
1011 CoglMatrix *matrix);
1013 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
1015 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
1017 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
1018 const ClutterColor *color);
1020 static void on_layout_manager_changed (ClutterLayoutManager *manager,
1021 ClutterActor *self);
1023 static inline void clutter_actor_queue_compute_expand (ClutterActor *self);
1025 /* Helper macro which translates by the anchor coord, applies the
1026 given transformation and then translates back */
1027 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
1028 gfloat _tx, _ty, _tz; \
1029 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
1030 cogl_matrix_translate ((m), _tx, _ty, _tz); \
1032 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
1034 static GQuark quark_shader_data = 0;
1035 static GQuark quark_actor_layout_info = 0;
1036 static GQuark quark_actor_transform_info = 0;
1037 static GQuark quark_actor_animation_info = 0;
1039 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1041 G_TYPE_INITIALLY_UNOWNED,
1042 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1043 clutter_container_iface_init)
1044 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1045 clutter_scriptable_iface_init)
1046 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1047 clutter_animatable_iface_init)
1048 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1049 atk_implementor_iface_init));
1052 * clutter_actor_get_debug_name:
1053 * @actor: a #ClutterActor
1055 * Retrieves a printable name of @actor for debugging messages
1057 * Return value: a string with a printable name
1060 _clutter_actor_get_debug_name (ClutterActor *actor)
1062 ClutterActorPrivate *priv = actor->priv;
1063 const gchar *retval;
1065 #ifdef CLUTTER_ENABLE_DEBUG
1066 if (G_UNLIKELY (priv->debug_name == NULL))
1068 priv->debug_name = g_strdup_printf ("<%s>[<%s>:%p]",
1069 priv->name != NULL ? priv->name
1071 G_OBJECT_TYPE_NAME (actor),
1075 retval = priv->debug_name;
1077 retval = priv->name != NULL
1079 : G_OBJECT_TYPE_NAME (actor);
1085 #ifdef CLUTTER_ENABLE_DEBUG
1086 /* XXX - this is for debugging only, remove once working (or leave
1087 * in only in some debug mode). Should leave it for a little while
1088 * until we're confident in the new map/realize/visible handling.
1091 clutter_actor_verify_map_state (ClutterActor *self)
1093 ClutterActorPrivate *priv = self->priv;
1095 if (CLUTTER_ACTOR_IS_REALIZED (self))
1097 /* all bets are off during reparent when we're potentially realized,
1098 * but should not be according to invariants
1100 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1102 if (priv->parent == NULL)
1104 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1108 g_warning ("Realized non-toplevel actor '%s' should "
1110 _clutter_actor_get_debug_name (self));
1112 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1114 g_warning ("Realized actor %s has an unrealized parent %s",
1115 _clutter_actor_get_debug_name (self),
1116 _clutter_actor_get_debug_name (priv->parent));
1121 if (CLUTTER_ACTOR_IS_MAPPED (self))
1123 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1124 g_warning ("Actor '%s' is mapped but not realized",
1125 _clutter_actor_get_debug_name (self));
1127 /* remaining bets are off during reparent when we're potentially
1128 * mapped, but should not be according to invariants
1130 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1132 if (priv->parent == NULL)
1134 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1136 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1137 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1139 g_warning ("Toplevel actor '%s' is mapped "
1141 _clutter_actor_get_debug_name (self));
1146 g_warning ("Mapped actor '%s' should have a parent",
1147 _clutter_actor_get_debug_name (self));
1152 ClutterActor *iter = self;
1154 /* check for the enable_paint_unmapped flag on the actor
1155 * and parents; if the flag is enabled at any point of this
1156 * branch of the scene graph then all the later checks
1159 while (iter != NULL)
1161 if (iter->priv->enable_paint_unmapped)
1164 iter = iter->priv->parent;
1167 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1169 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1171 _clutter_actor_get_debug_name (self),
1172 _clutter_actor_get_debug_name (priv->parent));
1175 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1177 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1179 _clutter_actor_get_debug_name (self),
1180 _clutter_actor_get_debug_name (priv->parent));
1183 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1185 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1186 g_warning ("Actor '%s' is mapped but its non-toplevel "
1187 "parent '%s' is not mapped",
1188 _clutter_actor_get_debug_name (self),
1189 _clutter_actor_get_debug_name (priv->parent));
1196 #endif /* CLUTTER_ENABLE_DEBUG */
1199 clutter_actor_set_mapped (ClutterActor *self,
1202 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1207 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1208 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1212 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1213 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1217 /* this function updates the mapped and realized states according to
1218 * invariants, in the appropriate order.
1221 clutter_actor_update_map_state (ClutterActor *self,
1222 MapStateChange change)
1224 gboolean was_mapped;
1226 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1228 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1230 /* the mapped flag on top-level actors must be set by the
1231 * per-backend implementation because it might be asynchronous.
1233 * That is, the MAPPED flag on toplevels currently tracks the X
1234 * server mapped-ness of the window, while the expected behavior
1235 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1236 * This creates some weird complexity by breaking the invariant
1237 * that if we're visible and all ancestors shown then we are
1238 * also mapped - instead, we are mapped if all ancestors
1239 * _possibly excepting_ the stage are mapped. The stage
1240 * will map/unmap for example when it is minimized or
1241 * moved to another workspace.
1243 * So, the only invariant on the stage is that if visible it
1244 * should be realized, and that it has to be visible to be
1247 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1248 clutter_actor_realize (self);
1252 case MAP_STATE_CHECK:
1255 case MAP_STATE_MAKE_MAPPED:
1256 g_assert (!was_mapped);
1257 clutter_actor_set_mapped (self, TRUE);
1260 case MAP_STATE_MAKE_UNMAPPED:
1261 g_assert (was_mapped);
1262 clutter_actor_set_mapped (self, FALSE);
1265 case MAP_STATE_MAKE_UNREALIZED:
1266 /* we only use MAKE_UNREALIZED in unparent,
1267 * and unparenting a stage isn't possible.
1268 * If someone wants to just unrealize a stage
1269 * then clutter_actor_unrealize() doesn't
1270 * go through this codepath.
1272 g_warning ("Trying to force unrealize stage is not allowed");
1276 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1277 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1278 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1280 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1281 "it is somehow still mapped",
1282 _clutter_actor_get_debug_name (self));
1287 ClutterActorPrivate *priv = self->priv;
1288 ClutterActor *parent = priv->parent;
1289 gboolean should_be_mapped;
1290 gboolean may_be_realized;
1291 gboolean must_be_realized;
1293 should_be_mapped = FALSE;
1294 may_be_realized = TRUE;
1295 must_be_realized = FALSE;
1297 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1299 may_be_realized = FALSE;
1303 /* Maintain invariant that if parent is mapped, and we are
1304 * visible, then we are mapped ... unless parent is a
1305 * stage, in which case we map regardless of parent's map
1306 * state but do require stage to be visible and realized.
1308 * If parent is realized, that does not force us to be
1309 * realized; but if parent is unrealized, that does force
1310 * us to be unrealized.
1312 * The reason we don't force children to realize with
1313 * parents is _clutter_actor_rerealize(); if we require that
1314 * a realized parent means children are realized, then to
1315 * unrealize an actor we would have to unrealize its
1316 * parents, which would end up meaning unrealizing and
1317 * hiding the entire stage. So we allow unrealizing a
1318 * child (as long as that child is not mapped) while that
1319 * child still has a realized parent.
1321 * Also, if we unrealize from leaf nodes to root, and
1322 * realize from root to leaf, the invariants are never
1323 * violated if we allow children to be unrealized
1324 * while parents are realized.
1326 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1327 * to force us to unmap, even though parent is still
1328 * mapped. This is because we're unmapping from leaf nodes
1331 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1332 change != MAP_STATE_MAKE_UNMAPPED)
1334 gboolean parent_is_visible_realized_toplevel;
1336 parent_is_visible_realized_toplevel =
1337 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1338 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1339 CLUTTER_ACTOR_IS_REALIZED (parent));
1341 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1342 parent_is_visible_realized_toplevel)
1344 must_be_realized = TRUE;
1345 should_be_mapped = TRUE;
1349 /* if the actor has been set to be painted even if unmapped
1350 * then we should map it and check for realization as well;
1351 * this is an override for the branch of the scene graph
1352 * which begins with this node
1354 if (priv->enable_paint_unmapped)
1356 if (priv->parent == NULL)
1357 g_warning ("Attempting to map an unparented actor '%s'",
1358 _clutter_actor_get_debug_name (self));
1360 should_be_mapped = TRUE;
1361 must_be_realized = TRUE;
1364 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1365 may_be_realized = FALSE;
1368 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1371 g_warning ("Attempting to map a child that does not "
1372 "meet the necessary invariants: the actor '%s' "
1374 _clutter_actor_get_debug_name (self));
1376 g_warning ("Attempting to map a child that does not "
1377 "meet the necessary invariants: the actor '%s' "
1378 "is parented to an unmapped actor '%s'",
1379 _clutter_actor_get_debug_name (self),
1380 _clutter_actor_get_debug_name (priv->parent));
1383 /* If in reparent, we temporarily suspend unmap and unrealize.
1385 * We want to go in the order "realize, map" and "unmap, unrealize"
1389 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1390 clutter_actor_set_mapped (self, FALSE);
1393 if (must_be_realized)
1394 clutter_actor_realize (self);
1396 /* if we must be realized then we may be, presumably */
1397 g_assert (!(must_be_realized && !may_be_realized));
1400 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1401 clutter_actor_unrealize_not_hiding (self);
1404 if (should_be_mapped)
1406 if (!must_be_realized)
1407 g_warning ("Somehow we think actor '%s' should be mapped but "
1408 "not realized, which isn't allowed",
1409 _clutter_actor_get_debug_name (self));
1411 /* realization is allowed to fail (though I don't know what
1412 * an app is supposed to do about that - shouldn't it just
1413 * be a g_error? anyway, we have to avoid mapping if this
1416 if (CLUTTER_ACTOR_IS_REALIZED (self))
1417 clutter_actor_set_mapped (self, TRUE);
1421 #ifdef CLUTTER_ENABLE_DEBUG
1422 /* check all invariants were kept */
1423 clutter_actor_verify_map_state (self);
1428 clutter_actor_real_map (ClutterActor *self)
1430 ClutterActorPrivate *priv = self->priv;
1431 ClutterActor *stage, *iter;
1433 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1435 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1436 _clutter_actor_get_debug_name (self));
1438 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1440 stage = _clutter_actor_get_stage_internal (self);
1441 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1443 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1445 _clutter_actor_get_debug_name (self));
1447 /* notify on parent mapped before potentially mapping
1448 * children, so apps see a top-down notification.
1450 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1452 for (iter = self->priv->first_child;
1454 iter = iter->priv->next_sibling)
1456 clutter_actor_map (iter);
1461 * clutter_actor_map:
1462 * @self: A #ClutterActor
1464 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1465 * and realizes its children if they are visible. Does nothing if the
1466 * actor is not visible.
1468 * Calling this function is strongly disencouraged: the default
1469 * implementation of #ClutterActorClass.map() will map all the children
1470 * of an actor when mapping its parent.
1472 * When overriding map, it is mandatory to chain up to the parent
1478 clutter_actor_map (ClutterActor *self)
1480 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1482 if (CLUTTER_ACTOR_IS_MAPPED (self))
1485 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1488 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1492 clutter_actor_real_unmap (ClutterActor *self)
1494 ClutterActorPrivate *priv = self->priv;
1497 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1499 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1500 _clutter_actor_get_debug_name (self));
1502 for (iter = self->priv->first_child;
1504 iter = iter->priv->next_sibling)
1506 clutter_actor_unmap (iter);
1509 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1511 /* clear the contents of the last paint volume, so that hiding + moving +
1512 * showing will not result in the wrong area being repainted
1514 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1515 priv->last_paint_volume_valid = TRUE;
1517 /* notify on parent mapped after potentially unmapping
1518 * children, so apps see a bottom-up notification.
1520 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1522 /* relinquish keyboard focus if we were unmapped while owning it */
1523 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1525 ClutterStage *stage;
1527 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1530 _clutter_stage_release_pick_id (stage, priv->pick_id);
1534 if (stage != NULL &&
1535 clutter_stage_get_key_focus (stage) == self)
1537 clutter_stage_set_key_focus (stage, NULL);
1543 * clutter_actor_unmap:
1544 * @self: A #ClutterActor
1546 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1547 * unmaps its children if they were mapped.
1549 * Calling this function is not encouraged: the default #ClutterActor
1550 * implementation of #ClutterActorClass.unmap() will also unmap any
1551 * eventual children by default when their parent is unmapped.
1553 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1554 * chain up to the parent implementation.
1556 * <note>It is important to note that the implementation of the
1557 * #ClutterActorClass.unmap() virtual function may be called after
1558 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1559 * implementation, but it is guaranteed to be called before the
1560 * #GObjectClass.finalize() implementation.</note>
1565 clutter_actor_unmap (ClutterActor *self)
1567 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1569 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1572 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1576 clutter_actor_real_show (ClutterActor *self)
1578 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1580 ClutterActorPrivate *priv = self->priv;
1582 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1584 /* we notify on the "visible" flag in the clutter_actor_show()
1585 * wrapper so the entire show signal emission completes first
1588 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1590 /* we queue a relayout unless the actor is inside a
1591 * container that explicitly told us not to
1593 if (priv->parent != NULL &&
1594 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1596 /* While an actor is hidden the parent may not have
1597 * allocated/requested so we need to start from scratch
1598 * and avoid the short-circuiting in
1599 * clutter_actor_queue_relayout().
1601 priv->needs_width_request = FALSE;
1602 priv->needs_height_request = FALSE;
1603 priv->needs_allocation = FALSE;
1604 clutter_actor_queue_relayout (self);
1610 set_show_on_set_parent (ClutterActor *self,
1613 ClutterActorPrivate *priv = self->priv;
1615 set_show = !!set_show;
1617 if (priv->show_on_set_parent == set_show)
1620 if (priv->parent == NULL)
1622 priv->show_on_set_parent = set_show;
1623 g_object_notify_by_pspec (G_OBJECT (self),
1624 obj_props[PROP_SHOW_ON_SET_PARENT]);
1629 * clutter_actor_show:
1630 * @self: A #ClutterActor
1632 * Flags an actor to be displayed. An actor that isn't shown will not
1633 * be rendered on the stage.
1635 * Actors are visible by default.
1637 * If this function is called on an actor without a parent, the
1638 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1642 clutter_actor_show (ClutterActor *self)
1644 ClutterActorPrivate *priv;
1646 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1648 /* simple optimization */
1649 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1651 /* we still need to set the :show-on-set-parent property, in
1652 * case show() is called on an unparented actor
1654 set_show_on_set_parent (self, TRUE);
1658 #ifdef CLUTTER_ENABLE_DEBUG
1659 clutter_actor_verify_map_state (self);
1664 g_object_freeze_notify (G_OBJECT (self));
1666 set_show_on_set_parent (self, TRUE);
1668 /* if we're showing a child that needs to expand, or may
1669 * expand, then we need to recompute the expand flags for
1670 * its parent as well
1672 if (priv->needs_compute_expand ||
1673 priv->needs_x_expand ||
1674 priv->needs_y_expand)
1676 clutter_actor_queue_compute_expand (self);
1679 g_signal_emit (self, actor_signals[SHOW], 0);
1680 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1682 if (priv->parent != NULL)
1683 clutter_actor_queue_redraw (priv->parent);
1685 g_object_thaw_notify (G_OBJECT (self));
1689 * clutter_actor_show_all:
1690 * @self: a #ClutterActor
1692 * Calls clutter_actor_show() on all children of an actor (if any).
1696 * Deprecated: 1.10: Actors are visible by default
1699 clutter_actor_show_all (ClutterActor *self)
1701 ClutterActorClass *klass;
1703 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1705 klass = CLUTTER_ACTOR_GET_CLASS (self);
1706 if (klass->show_all)
1707 klass->show_all (self);
1711 clutter_actor_real_hide (ClutterActor *self)
1713 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1715 ClutterActorPrivate *priv = self->priv;
1717 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1719 /* we notify on the "visible" flag in the clutter_actor_hide()
1720 * wrapper so the entire hide signal emission completes first
1723 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1725 /* we queue a relayout unless the actor is inside a
1726 * container that explicitly told us not to
1728 if (priv->parent != NULL &&
1729 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1730 clutter_actor_queue_relayout (priv->parent);
1735 * clutter_actor_hide:
1736 * @self: A #ClutterActor
1738 * Flags an actor to be hidden. A hidden actor will not be
1739 * rendered on the stage.
1741 * Actors are visible by default.
1743 * If this function is called on an actor without a parent, the
1744 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1748 clutter_actor_hide (ClutterActor *self)
1750 ClutterActorPrivate *priv;
1752 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1754 /* simple optimization */
1755 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1757 /* we still need to set the :show-on-set-parent property, in
1758 * case hide() is called on an unparented actor
1760 set_show_on_set_parent (self, FALSE);
1764 #ifdef CLUTTER_ENABLE_DEBUG
1765 clutter_actor_verify_map_state (self);
1770 g_object_freeze_notify (G_OBJECT (self));
1772 set_show_on_set_parent (self, FALSE);
1774 /* if we're hiding a child that needs to expand, or may
1775 * expand, then we need to recompute the expand flags for
1776 * its parent as well
1778 if (priv->needs_compute_expand ||
1779 priv->needs_x_expand ||
1780 priv->needs_y_expand)
1782 clutter_actor_queue_compute_expand (self);
1785 g_signal_emit (self, actor_signals[HIDE], 0);
1786 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1788 if (priv->parent != NULL)
1789 clutter_actor_queue_redraw (priv->parent);
1791 g_object_thaw_notify (G_OBJECT (self));
1795 * clutter_actor_hide_all:
1796 * @self: a #ClutterActor
1798 * Calls clutter_actor_hide() on all child actors (if any).
1802 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1803 * prevent its children from being painted as well.
1806 clutter_actor_hide_all (ClutterActor *self)
1808 ClutterActorClass *klass;
1810 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1812 klass = CLUTTER_ACTOR_GET_CLASS (self);
1813 if (klass->hide_all)
1814 klass->hide_all (self);
1818 * clutter_actor_realize:
1819 * @self: A #ClutterActor
1821 * Realization informs the actor that it is attached to a stage. It
1822 * can use this to allocate resources if it wanted to delay allocation
1823 * until it would be rendered. However it is perfectly acceptable for
1824 * an actor to create resources before being realized because Clutter
1825 * only ever has a single rendering context so that actor is free to
1826 * be moved from one stage to another.
1828 * This function does nothing if the actor is already realized.
1830 * Because a realized actor must have realized parent actors, calling
1831 * clutter_actor_realize() will also realize all parents of the actor.
1833 * This function does not realize child actors, except in the special
1834 * case that realizing the stage, when the stage is visible, will
1835 * suddenly map (and thus realize) the children of the stage.
1838 clutter_actor_realize (ClutterActor *self)
1840 ClutterActorPrivate *priv;
1842 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1846 #ifdef CLUTTER_ENABLE_DEBUG
1847 clutter_actor_verify_map_state (self);
1850 if (CLUTTER_ACTOR_IS_REALIZED (self))
1853 /* To be realized, our parent actors must be realized first.
1854 * This will only succeed if we're inside a toplevel.
1856 if (priv->parent != NULL)
1857 clutter_actor_realize (priv->parent);
1859 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1861 /* toplevels can be realized at any time */
1865 /* "Fail" the realization if parent is missing or unrealized;
1866 * this should really be a g_warning() not some kind of runtime
1867 * failure; how can an app possibly recover? Instead it's a bug
1868 * in the app and the app should get an explanatory warning so
1869 * someone can fix it. But for now it's too hard to fix this
1870 * because e.g. ClutterTexture needs reworking.
1872 if (priv->parent == NULL ||
1873 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1877 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1879 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1880 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1882 g_signal_emit (self, actor_signals[REALIZE], 0);
1884 /* Stage actor is allowed to unset the realized flag again in its
1885 * default signal handler, though that is a pathological situation.
1888 /* If realization "failed" we'll have to update child state. */
1889 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1893 clutter_actor_real_unrealize (ClutterActor *self)
1895 /* we must be unmapped (implying our children are also unmapped) */
1896 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1900 * clutter_actor_unrealize:
1901 * @self: A #ClutterActor
1903 * Unrealization informs the actor that it may be being destroyed or
1904 * moved to another stage. The actor may want to destroy any
1905 * underlying graphics resources at this point. However it is
1906 * perfectly acceptable for it to retain the resources until the actor
1907 * is destroyed because Clutter only ever uses a single rendering
1908 * context and all of the graphics resources are valid on any stage.
1910 * Because mapped actors must be realized, actors may not be
1911 * unrealized if they are mapped. This function hides the actor to be
1912 * sure it isn't mapped, an application-visible side effect that you
1913 * may not be expecting.
1915 * This function should not be called by application code.
1918 clutter_actor_unrealize (ClutterActor *self)
1920 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1921 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1923 /* This function should not really be in the public API, because
1924 * there isn't a good reason to call it. ClutterActor will already
1925 * unrealize things for you when it's important to do so.
1927 * If you were using clutter_actor_unrealize() in a dispose
1928 * implementation, then don't, just chain up to ClutterActor's
1931 * If you were using clutter_actor_unrealize() to implement
1932 * unrealizing children of your container, then don't, ClutterActor
1933 * will already take care of that.
1935 * If you were using clutter_actor_unrealize() to re-realize to
1936 * create your resources in a different way, then use
1937 * _clutter_actor_rerealize() (inside Clutter) or just call your
1938 * code that recreates your resources directly (outside Clutter).
1941 #ifdef CLUTTER_ENABLE_DEBUG
1942 clutter_actor_verify_map_state (self);
1945 clutter_actor_hide (self);
1947 clutter_actor_unrealize_not_hiding (self);
1950 static ClutterActorTraverseVisitFlags
1951 unrealize_actor_before_children_cb (ClutterActor *self,
1955 /* If an actor is already unrealized we know its children have also
1956 * already been unrealized... */
1957 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1958 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1960 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1962 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1965 static ClutterActorTraverseVisitFlags
1966 unrealize_actor_after_children_cb (ClutterActor *self,
1970 /* We want to unset the realized flag only _after_
1971 * child actors are unrealized, to maintain invariants.
1973 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1974 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1975 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1979 * clutter_actor_unrealize_not_hiding:
1980 * @self: A #ClutterActor
1982 * Unrealization informs the actor that it may be being destroyed or
1983 * moved to another stage. The actor may want to destroy any
1984 * underlying graphics resources at this point. However it is
1985 * perfectly acceptable for it to retain the resources until the actor
1986 * is destroyed because Clutter only ever uses a single rendering
1987 * context and all of the graphics resources are valid on any stage.
1989 * Because mapped actors must be realized, actors may not be
1990 * unrealized if they are mapped. You must hide the actor or one of
1991 * its parents before attempting to unrealize.
1993 * This function is separate from clutter_actor_unrealize() because it
1994 * does not automatically hide the actor.
1995 * Actors need not be hidden to be unrealized, they just need to
1996 * be unmapped. In fact we don't want to mess up the application's
1997 * setting of the "visible" flag, so hiding is very undesirable.
1999 * clutter_actor_unrealize() does a clutter_actor_hide() just for
2000 * backward compatibility.
2003 clutter_actor_unrealize_not_hiding (ClutterActor *self)
2005 _clutter_actor_traverse (self,
2006 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
2007 unrealize_actor_before_children_cb,
2008 unrealize_actor_after_children_cb,
2013 * _clutter_actor_rerealize:
2014 * @self: A #ClutterActor
2015 * @callback: Function to call while unrealized
2016 * @data: data for callback
2018 * If an actor is already unrealized, this just calls the callback.
2020 * If it is realized, it unrealizes temporarily, calls the callback,
2021 * and then re-realizes the actor.
2023 * As a side effect, leaves all children of the actor unrealized if
2024 * the actor was realized but not showing. This is because when we
2025 * unrealize the actor temporarily we must unrealize its children
2026 * (e.g. children of a stage can't be realized if stage window is
2027 * gone). And we aren't clever enough to save the realization state of
2028 * all children. In most cases this should not matter, because
2029 * the children will automatically realize when they next become mapped.
2032 _clutter_actor_rerealize (ClutterActor *self,
2033 ClutterCallback callback,
2036 gboolean was_mapped;
2037 gboolean was_showing;
2038 gboolean was_realized;
2040 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2042 #ifdef CLUTTER_ENABLE_DEBUG
2043 clutter_actor_verify_map_state (self);
2046 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
2047 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
2048 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
2050 /* Must be unmapped to unrealize. Note we only have to hide this
2051 * actor if it was mapped (if all parents were showing). If actor
2052 * is merely visible (but not mapped), then that's fine, we can
2056 clutter_actor_hide (self);
2058 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
2060 /* unrealize self and all children */
2061 clutter_actor_unrealize_not_hiding (self);
2063 if (callback != NULL)
2065 (* callback) (self, data);
2069 clutter_actor_show (self); /* will realize only if mapping implies it */
2070 else if (was_realized)
2071 clutter_actor_realize (self); /* realize self and all parents */
2075 clutter_actor_real_pick (ClutterActor *self,
2076 const ClutterColor *color)
2078 /* the default implementation is just to paint a rectangle
2079 * with the same size of the actor using the passed color
2081 if (clutter_actor_should_pick_paint (self))
2083 ClutterActorBox box = { 0, };
2084 float width, height;
2086 clutter_actor_get_allocation_box (self, &box);
2088 width = box.x2 - box.x1;
2089 height = box.y2 - box.y1;
2091 cogl_set_source_color4ub (color->red,
2096 cogl_rectangle (0, 0, width, height);
2099 /* XXX - this thoroughly sucks, but we need to maintain compatibility
2100 * with existing container classes that override the pick() virtual
2101 * and chain up to the default implementation - otherwise we'll end up
2102 * painting our children twice.
2104 * this has to go away for 2.0; hopefully along the pick() itself.
2106 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2110 for (iter = self->priv->first_child;
2112 iter = iter->priv->next_sibling)
2113 clutter_actor_paint (iter);
2118 * clutter_actor_should_pick_paint:
2119 * @self: A #ClutterActor
2121 * Should be called inside the implementation of the
2122 * #ClutterActor::pick virtual function in order to check whether
2123 * the actor should paint itself in pick mode or not.
2125 * This function should never be called directly by applications.
2127 * Return value: %TRUE if the actor should paint its silhouette,
2131 clutter_actor_should_pick_paint (ClutterActor *self)
2133 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2135 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2136 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2137 CLUTTER_ACTOR_IS_REACTIVE (self)))
2144 clutter_actor_real_get_preferred_width (ClutterActor *self,
2146 gfloat *min_width_p,
2147 gfloat *natural_width_p)
2149 ClutterActorPrivate *priv = self->priv;
2151 if (priv->n_children != 0 &&
2152 priv->layout_manager != NULL)
2154 ClutterContainer *container = CLUTTER_CONTAINER (self);
2156 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2157 "for the preferred width",
2158 G_OBJECT_TYPE_NAME (priv->layout_manager),
2159 priv->layout_manager);
2161 clutter_layout_manager_get_preferred_width (priv->layout_manager,
2170 /* Default implementation is always 0x0, usually an actor
2171 * using this default is relying on someone to set the
2174 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2179 if (natural_width_p)
2180 *natural_width_p = 0;
2184 clutter_actor_real_get_preferred_height (ClutterActor *self,
2186 gfloat *min_height_p,
2187 gfloat *natural_height_p)
2189 ClutterActorPrivate *priv = self->priv;
2191 if (priv->n_children != 0 &&
2192 priv->layout_manager != NULL)
2194 ClutterContainer *container = CLUTTER_CONTAINER (self);
2196 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2197 "for the preferred height",
2198 G_OBJECT_TYPE_NAME (priv->layout_manager),
2199 priv->layout_manager);
2201 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2209 /* Default implementation is always 0x0, usually an actor
2210 * using this default is relying on someone to set the
2213 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2218 if (natural_height_p)
2219 *natural_height_p = 0;
2223 clutter_actor_store_old_geometry (ClutterActor *self,
2224 ClutterActorBox *box)
2226 *box = self->priv->allocation;
2230 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2231 const ClutterActorBox *old)
2233 ClutterActorPrivate *priv = self->priv;
2234 GObject *obj = G_OBJECT (self);
2236 g_object_freeze_notify (obj);
2238 /* to avoid excessive requisition or allocation cycles we
2239 * use the cached values.
2241 * - if we don't have an allocation we assume that we need
2243 * - if we don't have a width or a height request we notify
2245 * - if we have a valid allocation then we check the old
2246 * bounding box with the current allocation and we notify
2249 if (priv->needs_allocation)
2251 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2252 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2253 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2254 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2255 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2256 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2258 else if (priv->needs_width_request || priv->needs_height_request)
2260 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2261 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2262 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2267 gfloat width, height;
2269 x = priv->allocation.x1;
2270 y = priv->allocation.y1;
2271 width = priv->allocation.x2 - priv->allocation.x1;
2272 height = priv->allocation.y2 - priv->allocation.y1;
2276 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2277 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2282 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2283 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2286 if (width != (old->x2 - old->x1))
2288 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2289 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2292 if (height != (old->y2 - old->y1))
2294 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2295 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2299 g_object_thaw_notify (obj);
2303 * clutter_actor_set_allocation_internal:
2304 * @self: a #ClutterActor
2305 * @box: a #ClutterActorBox
2306 * @flags: allocation flags
2308 * Stores the allocation of @self.
2310 * This function only performs basic storage and property notification.
2312 * This function should be called by clutter_actor_set_allocation()
2313 * and by the default implementation of #ClutterActorClass.allocate().
2315 * Return value: %TRUE if the allocation of the #ClutterActor has been
2316 * changed, and %FALSE otherwise
2318 static inline gboolean
2319 clutter_actor_set_allocation_internal (ClutterActor *self,
2320 const ClutterActorBox *box,
2321 ClutterAllocationFlags flags)
2323 ClutterActorPrivate *priv = self->priv;
2325 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2327 ClutterActorBox old_alloc = { 0, };
2329 obj = G_OBJECT (self);
2331 g_object_freeze_notify (obj);
2333 clutter_actor_store_old_geometry (self, &old_alloc);
2335 x1_changed = priv->allocation.x1 != box->x1;
2336 y1_changed = priv->allocation.y1 != box->y1;
2337 x2_changed = priv->allocation.x2 != box->x2;
2338 y2_changed = priv->allocation.y2 != box->y2;
2340 priv->allocation = *box;
2341 priv->allocation_flags = flags;
2343 /* allocation is authoritative */
2344 priv->needs_width_request = FALSE;
2345 priv->needs_height_request = FALSE;
2346 priv->needs_allocation = FALSE;
2353 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2354 _clutter_actor_get_debug_name (self));
2356 priv->transform_valid = FALSE;
2358 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2360 /* if the allocation changes, so does the content box */
2361 if (priv->content != NULL)
2363 priv->content_box_valid = FALSE;
2364 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2372 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2374 g_object_thaw_notify (obj);
2379 static void clutter_actor_real_allocate (ClutterActor *self,
2380 const ClutterActorBox *box,
2381 ClutterAllocationFlags flags);
2384 clutter_actor_maybe_layout_children (ClutterActor *self,
2385 const ClutterActorBox *allocation,
2386 ClutterAllocationFlags flags)
2388 ClutterActorPrivate *priv = self->priv;
2390 /* this is going to be a bit hard to follow, so let's put an explanation
2393 * we want ClutterActor to have a default layout manager if the actor was
2394 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2396 * we also want any subclass of ClutterActor that does not override the
2397 * ::allocate() virtual function to delegate to a layout manager.
2399 * finally, we want to allow people subclassing ClutterActor and overriding
2400 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2402 * on the other hand, we want existing actor subclasses overriding the
2403 * ::allocate() virtual function and chaining up to the parent's
2404 * implementation to continue working without allocating their children
2405 * twice, or without entering an allocation loop.
2407 * for the first two points, we check if the class of the actor is
2408 * overridding the ::allocate() virtual function; if it isn't, then we
2409 * follow through with checking whether we have children and a layout
2410 * manager, and eventually calling clutter_layout_manager_allocate().
2412 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2413 * allocation flags that we got passed, and if it is present, we continue
2414 * with the check above.
2416 * if neither of these two checks yields a positive result, we just
2417 * assume that the ::allocate() virtual function that resulted in this
2418 * function being called will also allocate the children of the actor.
2421 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2424 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2430 if (priv->n_children != 0 &&
2431 priv->layout_manager != NULL)
2433 ClutterContainer *container = CLUTTER_CONTAINER (self);
2434 ClutterAllocationFlags children_flags;
2435 ClutterActorBox children_box;
2437 /* normalize the box passed to the layout manager */
2438 children_box.x1 = children_box.y1 = 0.f;
2439 children_box.x2 = (allocation->x2 - allocation->x1);
2440 children_box.y2 = (allocation->y2 - allocation->y1);
2442 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2443 * the actor's children, since it refers only to the current
2444 * actor's allocation.
2446 children_flags = flags;
2447 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2449 CLUTTER_NOTE (LAYOUT,
2450 "Allocating %d children of %s "
2451 "at { %.2f, %.2f - %.2f x %.2f } "
2454 _clutter_actor_get_debug_name (self),
2457 (allocation->x2 - allocation->x1),
2458 (allocation->y2 - allocation->y1),
2459 G_OBJECT_TYPE_NAME (priv->layout_manager));
2461 clutter_layout_manager_allocate (priv->layout_manager,
2469 clutter_actor_real_allocate (ClutterActor *self,
2470 const ClutterActorBox *box,
2471 ClutterAllocationFlags flags)
2473 ClutterActorPrivate *priv = self->priv;
2476 g_object_freeze_notify (G_OBJECT (self));
2478 changed = clutter_actor_set_allocation_internal (self, box, flags);
2480 /* we allocate our children before we notify changes in our geometry,
2481 * so that people connecting to properties will be able to get valid
2482 * data out of the sub-tree of the scene graph that has this actor at
2485 clutter_actor_maybe_layout_children (self, box, flags);
2489 ClutterActorBox signal_box = priv->allocation;
2490 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2492 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2497 g_object_thaw_notify (G_OBJECT (self));
2501 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2502 ClutterActor *origin)
2504 /* no point in queuing a redraw on a destroyed actor */
2505 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2508 /* NB: We can't bail out early here if the actor is hidden in case
2509 * the actor bas been cloned. In this case the clone will need to
2510 * receive the signal so it can queue its own redraw.
2513 /* calls klass->queue_redraw in default handler */
2514 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2518 clutter_actor_real_queue_redraw (ClutterActor *self,
2519 ClutterActor *origin)
2521 ClutterActor *parent;
2523 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2524 _clutter_actor_get_debug_name (self),
2525 origin != NULL ? _clutter_actor_get_debug_name (origin)
2528 /* no point in queuing a redraw on a destroyed actor */
2529 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2532 /* If the queue redraw is coming from a child then the actor has
2533 become dirty and any queued effect is no longer valid */
2536 self->priv->is_dirty = TRUE;
2537 self->priv->effect_to_redraw = NULL;
2540 /* If the actor isn't visible, we still had to emit the signal
2541 * to allow for a ClutterClone, but the appearance of the parent
2542 * won't change so we don't have to propagate up the hierarchy.
2544 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2547 /* Although we could determine here that a full stage redraw
2548 * has already been queued and immediately bail out, we actually
2549 * guarantee that we will propagate a queue-redraw signal to our
2550 * parent at least once so that it's possible to implement a
2551 * container that tracks which of its children have queued a
2554 if (self->priv->propagated_one_redraw)
2556 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2557 if (stage != NULL &&
2558 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2562 self->priv->propagated_one_redraw = TRUE;
2564 /* notify parents, if they are all visible eventually we'll
2565 * queue redraw on the stage, which queues the redraw idle.
2567 parent = clutter_actor_get_parent (self);
2570 /* this will go up recursively */
2571 _clutter_actor_signal_queue_redraw (parent, origin);
2576 clutter_actor_real_queue_relayout (ClutterActor *self)
2578 ClutterActorPrivate *priv = self->priv;
2580 /* no point in queueing a redraw on a destroyed actor */
2581 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2584 priv->needs_width_request = TRUE;
2585 priv->needs_height_request = TRUE;
2586 priv->needs_allocation = TRUE;
2588 /* reset the cached size requests */
2589 memset (priv->width_requests, 0,
2590 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2591 memset (priv->height_requests, 0,
2592 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2594 /* We need to go all the way up the hierarchy */
2595 if (priv->parent != NULL)
2596 _clutter_actor_queue_only_relayout (priv->parent);
2600 * clutter_actor_apply_relative_transform_to_point:
2601 * @self: A #ClutterActor
2602 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2603 * default #ClutterStage
2604 * @point: A point as #ClutterVertex
2605 * @vertex: (out caller-allocates): The translated #ClutterVertex
2607 * Transforms @point in coordinates relative to the actor into
2608 * ancestor-relative coordinates using the relevant transform
2609 * stack (i.e. scale, rotation, etc).
2611 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2612 * this case, the coordinates returned will be the coordinates on
2613 * the stage before the projection is applied. This is different from
2614 * the behaviour of clutter_actor_apply_transform_to_point().
2619 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2620 ClutterActor *ancestor,
2621 const ClutterVertex *point,
2622 ClutterVertex *vertex)
2627 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2628 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2629 g_return_if_fail (point != NULL);
2630 g_return_if_fail (vertex != NULL);
2635 if (ancestor == NULL)
2636 ancestor = _clutter_actor_get_stage_internal (self);
2638 if (ancestor == NULL)
2644 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2645 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2649 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2650 const ClutterVertex *vertices_in,
2651 ClutterVertex *vertices_out,
2654 ClutterActor *stage;
2655 CoglMatrix modelview;
2656 CoglMatrix projection;
2659 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2661 stage = _clutter_actor_get_stage_internal (self);
2663 /* We really can't do anything meaningful in this case so don't try
2664 * to do any transform */
2668 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2669 * that gets us to stage coordinates, we want to go all the way to eye
2671 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2673 /* Fetch the projection and viewport */
2674 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2675 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2681 _clutter_util_fully_transform_vertices (&modelview,
2692 * clutter_actor_apply_transform_to_point:
2693 * @self: A #ClutterActor
2694 * @point: A point as #ClutterVertex
2695 * @vertex: (out caller-allocates): The translated #ClutterVertex
2697 * Transforms @point in coordinates relative to the actor
2698 * into screen-relative coordinates with the current actor
2699 * transformation (i.e. scale, rotation, etc)
2704 clutter_actor_apply_transform_to_point (ClutterActor *self,
2705 const ClutterVertex *point,
2706 ClutterVertex *vertex)
2708 g_return_if_fail (point != NULL);
2709 g_return_if_fail (vertex != NULL);
2710 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2714 * _clutter_actor_get_relative_transformation_matrix:
2715 * @self: The actor whose coordinate space you want to transform from.
2716 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2717 * or %NULL if you want to transform all the way to eye coordinates.
2718 * @matrix: A #CoglMatrix to store the transformation
2720 * This gets a transformation @matrix that will transform coordinates from the
2721 * coordinate space of @self into the coordinate space of @ancestor.
2723 * For example if you need a matrix that can transform the local actor
2724 * coordinates of @self into stage coordinates you would pass the actor's stage
2725 * pointer as the @ancestor.
2727 * If you pass %NULL then the transformation will take you all the way through
2728 * to eye coordinates. This can be useful if you want to extract the entire
2729 * modelview transform that Clutter applies before applying the projection
2730 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2731 * using cogl_set_modelview_matrix() for example then you would want a matrix
2732 * that transforms into eye coordinates.
2734 * <note><para>This function explicitly initializes the given @matrix. If you just
2735 * want clutter to multiply a relative transformation with an existing matrix
2736 * you can use clutter_actor_apply_relative_transformation_matrix()
2737 * instead.</para></note>
2740 /* XXX: We should consider caching the stage relative modelview along with
2741 * the actor itself */
2743 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2744 ClutterActor *ancestor,
2747 cogl_matrix_init_identity (matrix);
2749 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2752 /* Project the given @box into stage window coordinates, writing the
2753 * transformed vertices to @verts[]. */
2755 _clutter_actor_transform_and_project_box (ClutterActor *self,
2756 const ClutterActorBox *box,
2757 ClutterVertex verts[])
2759 ClutterVertex box_vertices[4];
2761 box_vertices[0].x = box->x1;
2762 box_vertices[0].y = box->y1;
2763 box_vertices[0].z = 0;
2764 box_vertices[1].x = box->x2;
2765 box_vertices[1].y = box->y1;
2766 box_vertices[1].z = 0;
2767 box_vertices[2].x = box->x1;
2768 box_vertices[2].y = box->y2;
2769 box_vertices[2].z = 0;
2770 box_vertices[3].x = box->x2;
2771 box_vertices[3].y = box->y2;
2772 box_vertices[3].z = 0;
2775 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2779 * clutter_actor_get_allocation_vertices:
2780 * @self: A #ClutterActor
2781 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2782 * against, or %NULL to use the #ClutterStage
2783 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2784 * location for an array of 4 #ClutterVertex in which to store the result
2786 * Calculates the transformed coordinates of the four corners of the
2787 * actor in the plane of @ancestor. The returned vertices relate to
2788 * the #ClutterActorBox coordinates as follows:
2790 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2791 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2792 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2793 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2796 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2797 * this case, the coordinates returned will be the coordinates on
2798 * the stage before the projection is applied. This is different from
2799 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2804 clutter_actor_get_allocation_vertices (ClutterActor *self,
2805 ClutterActor *ancestor,
2806 ClutterVertex verts[])
2808 ClutterActorPrivate *priv;
2809 ClutterActorBox box;
2810 ClutterVertex vertices[4];
2811 CoglMatrix modelview;
2813 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2814 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2816 if (ancestor == NULL)
2817 ancestor = _clutter_actor_get_stage_internal (self);
2819 /* Fallback to a NOP transform if the actor isn't parented under a
2821 if (ancestor == NULL)
2826 /* if the actor needs to be allocated we force a relayout, so that
2827 * we will have valid values to use in the transformations */
2828 if (priv->needs_allocation)
2830 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2832 _clutter_stage_maybe_relayout (stage);
2835 box.x1 = box.y1 = 0;
2836 /* The result isn't really meaningful in this case but at
2837 * least try to do something *vaguely* reasonable... */
2838 clutter_actor_get_size (self, &box.x2, &box.y2);
2842 clutter_actor_get_allocation_box (self, &box);
2844 vertices[0].x = box.x1;
2845 vertices[0].y = box.y1;
2847 vertices[1].x = box.x2;
2848 vertices[1].y = box.y1;
2850 vertices[2].x = box.x1;
2851 vertices[2].y = box.y2;
2853 vertices[3].x = box.x2;
2854 vertices[3].y = box.y2;
2857 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2860 cogl_matrix_transform_points (&modelview,
2862 sizeof (ClutterVertex),
2864 sizeof (ClutterVertex),
2870 * clutter_actor_get_abs_allocation_vertices:
2871 * @self: A #ClutterActor
2872 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2873 * of 4 #ClutterVertex where to store the result.
2875 * Calculates the transformed screen coordinates of the four corners of
2876 * the actor; the returned vertices relate to the #ClutterActorBox
2877 * coordinates as follows:
2879 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2880 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2881 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2882 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2888 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2889 ClutterVertex verts[])
2891 ClutterActorPrivate *priv;
2892 ClutterActorBox actor_space_allocation;
2894 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2898 /* if the actor needs to be allocated we force a relayout, so that
2899 * the actor allocation box will be valid for
2900 * _clutter_actor_transform_and_project_box()
2902 if (priv->needs_allocation)
2904 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2905 /* There's nothing meaningful we can do now */
2909 _clutter_stage_maybe_relayout (stage);
2912 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2913 * own coordinate space... */
2914 actor_space_allocation.x1 = 0;
2915 actor_space_allocation.y1 = 0;
2916 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2917 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2918 _clutter_actor_transform_and_project_box (self,
2919 &actor_space_allocation,
2924 clutter_actor_real_apply_transform (ClutterActor *self,
2927 ClutterActorPrivate *priv = self->priv;
2929 if (!priv->transform_valid)
2931 CoglMatrix *transform = &priv->transform;
2932 const ClutterTransformInfo *info;
2934 info = _clutter_actor_get_transform_info_or_defaults (self);
2936 cogl_matrix_init_identity (transform);
2938 cogl_matrix_translate (transform,
2939 priv->allocation.x1,
2940 priv->allocation.y1,
2944 cogl_matrix_translate (transform, 0, 0, info->depth);
2947 * because the rotation involves translations, we must scale
2948 * before applying the rotations (if we apply the scale after
2949 * the rotations, the translations included in the rotation are
2950 * not scaled and so the entire object will move on the screen
2951 * as a result of rotating it).
2953 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2955 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2956 &info->scale_center,
2957 cogl_matrix_scale (transform,
2964 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2966 cogl_matrix_rotate (transform,
2971 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2973 cogl_matrix_rotate (transform,
2978 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2980 cogl_matrix_rotate (transform,
2984 if (!clutter_anchor_coord_is_zero (&info->anchor))
2988 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2989 cogl_matrix_translate (transform, -x, -y, -z);
2992 priv->transform_valid = TRUE;
2995 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2998 /* Applies the transforms associated with this actor to the given
3001 _clutter_actor_apply_modelview_transform (ClutterActor *self,
3004 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
3008 * clutter_actor_apply_relative_transformation_matrix:
3009 * @self: The actor whose coordinate space you want to transform from.
3010 * @ancestor: The ancestor actor whose coordinate space you want to transform too
3011 * or %NULL if you want to transform all the way to eye coordinates.
3012 * @matrix: A #CoglMatrix to apply the transformation too.
3014 * This multiplies a transform with @matrix that will transform coordinates
3015 * from the coordinate space of @self into the coordinate space of @ancestor.
3017 * For example if you need a matrix that can transform the local actor
3018 * coordinates of @self into stage coordinates you would pass the actor's stage
3019 * pointer as the @ancestor.
3021 * If you pass %NULL then the transformation will take you all the way through
3022 * to eye coordinates. This can be useful if you want to extract the entire
3023 * modelview transform that Clutter applies before applying the projection
3024 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
3025 * using cogl_set_modelview_matrix() for example then you would want a matrix
3026 * that transforms into eye coordinates.
3028 * <note>This function doesn't initialize the given @matrix, it simply
3029 * multiplies the requested transformation matrix with the existing contents of
3030 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
3031 * before calling this function, or you can use
3032 * clutter_actor_get_relative_transformation_matrix() instead.</note>
3035 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
3036 ClutterActor *ancestor,
3039 ClutterActor *parent;
3041 /* Note we terminate before ever calling stage->apply_transform()
3042 * since that would conceptually be relative to the underlying
3043 * window OpenGL coordinates so we'd need a special @ancestor
3044 * value to represent the fake parent of the stage. */
3045 if (self == ancestor)
3048 parent = clutter_actor_get_parent (self);
3051 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
3054 _clutter_actor_apply_modelview_transform (self, matrix);
3058 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
3059 ClutterPaintVolume *pv,
3061 const CoglColor *color)
3063 static CoglPipeline *outline = NULL;
3064 CoglPrimitive *prim;
3065 ClutterVertex line_ends[12 * 2];
3068 clutter_backend_get_cogl_context (clutter_get_default_backend ());
3069 /* XXX: at some point we'll query this from the stage but we can't
3070 * do that until the osx backend uses Cogl natively. */
3071 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
3073 if (outline == NULL)
3074 outline = cogl_pipeline_new (ctx);
3076 _clutter_paint_volume_complete (pv);
3078 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3081 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3082 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3083 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3084 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3089 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3090 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3091 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3092 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3094 /* Lines connecting front face to back face */
3095 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3096 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3097 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3098 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3101 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3103 (CoglVertexP3 *)line_ends);
3105 cogl_pipeline_set_color (outline, color);
3106 cogl_framebuffer_draw_primitive (fb, outline, prim);
3107 cogl_object_unref (prim);
3111 PangoLayout *layout;
3112 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3113 pango_layout_set_text (layout, label, -1);
3114 cogl_pango_render_layout (layout,
3119 g_object_unref (layout);
3124 _clutter_actor_draw_paint_volume (ClutterActor *self)
3126 ClutterPaintVolume *pv;
3129 pv = _clutter_actor_get_paint_volume_mutable (self);
3132 gfloat width, height;
3133 ClutterPaintVolume fake_pv;
3135 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3136 _clutter_paint_volume_init_static (&fake_pv, stage);
3138 clutter_actor_get_size (self, &width, &height);
3139 clutter_paint_volume_set_width (&fake_pv, width);
3140 clutter_paint_volume_set_height (&fake_pv, height);
3142 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3143 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3144 _clutter_actor_get_debug_name (self),
3147 clutter_paint_volume_free (&fake_pv);
3151 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3152 _clutter_actor_draw_paint_volume_full (self, pv,
3153 _clutter_actor_get_debug_name (self),
3159 _clutter_actor_paint_cull_result (ClutterActor *self,
3161 ClutterCullResult result)
3163 ClutterPaintVolume *pv;
3168 if (result == CLUTTER_CULL_RESULT_IN)
3169 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3170 else if (result == CLUTTER_CULL_RESULT_OUT)
3171 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3173 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3176 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3178 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3179 _clutter_actor_draw_paint_volume_full (self, pv,
3180 _clutter_actor_get_debug_name (self),
3184 PangoLayout *layout;
3186 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3187 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3188 cogl_set_source_color (&color);
3190 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3191 pango_layout_set_text (layout, label, -1);
3192 cogl_pango_render_layout (layout,
3198 g_object_unref (layout);
3202 static int clone_paint_level = 0;
3205 _clutter_actor_push_clone_paint (void)
3207 clone_paint_level++;
3211 _clutter_actor_pop_clone_paint (void)
3213 clone_paint_level--;
3217 in_clone_paint (void)
3219 return clone_paint_level > 0;
3222 /* Returns TRUE if the actor can be ignored */
3223 /* FIXME: we should return a ClutterCullResult, and
3224 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3225 * means there's no point in trying to cull descendants of the current
3228 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3230 ClutterActorPrivate *priv = self->priv;
3231 ClutterActor *stage;
3232 const ClutterPlane *stage_clip;
3234 if (!priv->last_paint_volume_valid)
3236 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3237 "->last_paint_volume_valid == FALSE",
3238 _clutter_actor_get_debug_name (self));
3242 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3245 stage = _clutter_actor_get_stage_internal (self);
3246 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3247 if (G_UNLIKELY (!stage_clip))
3249 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3250 "No stage clip set",
3251 _clutter_actor_get_debug_name (self));
3255 if (cogl_get_draw_framebuffer () !=
3256 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3258 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3259 "Current framebuffer doesn't correspond to stage",
3260 _clutter_actor_get_debug_name (self));
3265 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3270 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3272 ClutterActorPrivate *priv = self->priv;
3273 const ClutterPaintVolume *pv;
3275 if (priv->last_paint_volume_valid)
3277 clutter_paint_volume_free (&priv->last_paint_volume);
3278 priv->last_paint_volume_valid = FALSE;
3281 pv = clutter_actor_get_paint_volume (self);
3284 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3285 "Actor failed to report a paint volume",
3286 _clutter_actor_get_debug_name (self));
3290 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3292 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3293 NULL); /* eye coordinates */
3295 priv->last_paint_volume_valid = TRUE;
3298 static inline gboolean
3299 actor_has_shader_data (ClutterActor *self)
3301 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3305 _clutter_actor_get_pick_id (ClutterActor *self)
3307 if (self->priv->pick_id < 0)
3310 return self->priv->pick_id;
3313 /* This is the same as clutter_actor_add_effect except that it doesn't
3314 queue a redraw and it doesn't notify on the effect property */
3316 _clutter_actor_add_effect_internal (ClutterActor *self,
3317 ClutterEffect *effect)
3319 ClutterActorPrivate *priv = self->priv;
3321 if (priv->effects == NULL)
3323 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3324 priv->effects->actor = self;
3327 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3330 /* This is the same as clutter_actor_remove_effect except that it doesn't
3331 queue a redraw and it doesn't notify on the effect property */
3333 _clutter_actor_remove_effect_internal (ClutterActor *self,
3334 ClutterEffect *effect)
3336 ClutterActorPrivate *priv = self->priv;
3338 if (priv->effects == NULL)
3341 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3343 if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3344 g_clear_object (&priv->effects);
3348 needs_flatten_effect (ClutterActor *self)
3350 ClutterActorPrivate *priv = self->priv;
3352 if (G_UNLIKELY (clutter_paint_debug_flags &
3353 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3356 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3358 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3360 if (clutter_actor_get_paint_opacity (self) < 255 &&
3361 clutter_actor_has_overlaps (self))
3369 add_or_remove_flatten_effect (ClutterActor *self)
3371 ClutterActorPrivate *priv = self->priv;
3373 /* Add or remove the flatten effect depending on the
3374 offscreen-redirect property. */
3375 if (needs_flatten_effect (self))
3377 if (priv->flatten_effect == NULL)
3379 ClutterActorMeta *actor_meta;
3382 priv->flatten_effect = _clutter_flatten_effect_new ();
3383 /* Keep a reference to the effect so that we can queue
3385 g_object_ref_sink (priv->flatten_effect);
3387 /* Set the priority of the effect to high so that it will
3388 always be applied to the actor first. It uses an internal
3389 priority so that it won't be visible to applications */
3390 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3391 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3392 _clutter_actor_meta_set_priority (actor_meta, priority);
3394 /* This will add the effect without queueing a redraw */
3395 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3400 if (priv->flatten_effect != NULL)
3402 /* Destroy the effect so that it will lose its fbo cache of
3404 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3405 g_clear_object (&priv->flatten_effect);
3411 clutter_actor_real_paint (ClutterActor *actor)
3413 ClutterActorPrivate *priv = actor->priv;
3416 for (iter = priv->first_child;
3418 iter = iter->priv->next_sibling)
3420 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3421 _clutter_actor_get_debug_name (iter),
3422 _clutter_actor_get_debug_name (actor),
3423 iter->priv->allocation.x1,
3424 iter->priv->allocation.y1,
3425 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3426 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3428 clutter_actor_paint (iter);
3433 clutter_actor_paint_node (ClutterActor *actor,
3434 ClutterPaintNode *root)
3436 ClutterActorPrivate *priv = actor->priv;
3441 if (priv->bg_color_set &&
3442 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3444 ClutterPaintNode *node;
3445 ClutterColor bg_color;
3446 ClutterActorBox box;
3450 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3451 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3453 bg_color = priv->bg_color;
3454 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3455 * priv->bg_color.alpha
3458 node = clutter_color_node_new (&bg_color);
3459 clutter_paint_node_set_name (node, "backgroundColor");
3460 clutter_paint_node_add_rectangle (node, &box);
3461 clutter_paint_node_add_child (root, node);
3462 clutter_paint_node_unref (node);
3465 if (priv->content != NULL)
3466 _clutter_content_paint_content (priv->content, actor, root);
3468 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3469 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3471 if (clutter_paint_node_get_n_children (root) == 0)
3474 #ifdef CLUTTER_ENABLE_DEBUG
3475 if (CLUTTER_HAS_DEBUG (PAINT))
3477 /* dump the tree only if we have one */
3478 _clutter_paint_node_dump_tree (root);
3480 #endif /* CLUTTER_ENABLE_DEBUG */
3482 _clutter_paint_node_paint (root);
3485 /* XXX: Uncomment this when we disable emitting the paint signal */
3486 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3493 * clutter_actor_paint:
3494 * @self: A #ClutterActor
3496 * Renders the actor to display.
3498 * This function should not be called directly by applications.
3499 * Call clutter_actor_queue_redraw() to queue paints, instead.
3501 * This function is context-aware, and will either cause a
3502 * regular paint or a pick paint.
3504 * This function will emit the #ClutterActor::paint signal or
3505 * the #ClutterActor::pick signal, depending on the context.
3507 * This function does not paint the actor if the actor is set to 0,
3508 * unless it is performing a pick paint.
3511 clutter_actor_paint (ClutterActor *self)
3513 ClutterActorPrivate *priv;
3514 ClutterPickMode pick_mode;
3515 gboolean clip_set = FALSE;
3516 gboolean shader_applied = FALSE;
3518 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3519 "Actor real-paint counter",
3520 "Increments each time any actor is painted",
3521 0 /* no application private data */);
3522 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3523 "Actor pick-paint counter",
3524 "Increments each time any actor is painted "
3526 0 /* no application private data */);
3528 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3530 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3535 pick_mode = _clutter_context_get_pick_mode ();
3537 if (pick_mode == CLUTTER_PICK_NONE)
3538 priv->propagated_one_redraw = FALSE;
3540 /* It's an important optimization that we consider painting of
3541 * actors with 0 opacity to be a NOP... */
3542 if (pick_mode == CLUTTER_PICK_NONE &&
3543 /* ignore top-levels, since they might be transparent */
3544 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3545 /* Use the override opacity if its been set */
3546 ((priv->opacity_override >= 0) ?
3547 priv->opacity_override : priv->opacity) == 0)
3550 /* if we aren't paintable (not in a toplevel with all
3551 * parents paintable) then do nothing.
3553 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3556 /* mark that we are in the paint process */
3557 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3561 if (priv->enable_model_view_transform)
3565 /* XXX: It could be better to cache the modelview with the actor
3566 * instead of progressively building up the transformations on
3567 * the matrix stack every time we paint. */
3568 cogl_get_modelview_matrix (&matrix);
3569 _clutter_actor_apply_modelview_transform (self, &matrix);
3571 #ifdef CLUTTER_ENABLE_DEBUG
3572 /* Catch when out-of-band transforms have been made by actors not as part
3573 * of an apply_transform vfunc... */
3574 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3576 CoglMatrix expected_matrix;
3578 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3581 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3583 GString *buf = g_string_sized_new (1024);
3584 ClutterActor *parent;
3587 while (parent != NULL)
3589 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3591 if (parent->priv->parent != NULL)
3592 g_string_append (buf, "->");
3594 parent = parent->priv->parent;
3597 g_warning ("Unexpected transform found when painting actor "
3598 "\"%s\". This will be caused by one of the actor's "
3599 "ancestors (%s) using the Cogl API directly to transform "
3600 "children instead of using ::apply_transform().",
3601 _clutter_actor_get_debug_name (self),
3604 g_string_free (buf, TRUE);
3607 #endif /* CLUTTER_ENABLE_DEBUG */
3609 cogl_set_modelview_matrix (&matrix);
3614 cogl_clip_push_rectangle (priv->clip.x,
3616 priv->clip.x + priv->clip.width,
3617 priv->clip.y + priv->clip.height);
3620 else if (priv->clip_to_allocation)
3622 gfloat width, height;
3624 width = priv->allocation.x2 - priv->allocation.x1;
3625 height = priv->allocation.y2 - priv->allocation.y1;
3627 cogl_clip_push_rectangle (0, 0, width, height);
3631 if (pick_mode == CLUTTER_PICK_NONE)
3633 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3635 /* We check whether we need to add the flatten effect before
3636 each paint so that we can avoid having a mechanism for
3637 applications to notify when the value of the
3638 has_overlaps virtual changes. */
3639 add_or_remove_flatten_effect (self);
3642 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3644 /* We save the current paint volume so that the next time the
3645 * actor queues a redraw we can constrain the redraw to just
3646 * cover the union of the new bounding box and the old.
3648 * We also fetch the current paint volume to perform culling so
3649 * we can avoid painting actors outside the current clip region.
3651 * If we are painting inside a clone, we should neither update
3652 * the paint volume or use it to cull painting, since the paint
3653 * box represents the location of the source actor on the
3656 * XXX: We are starting to do a lot of vertex transforms on
3657 * the CPU in a typical paint, so at some point we should
3658 * audit these and consider caching some things.
3660 * NB: We don't perform culling while picking at this point because
3661 * clutter-stage.c doesn't setup the clipping planes appropriately.
3663 * NB: We don't want to update the last-paint-volume during picking
3664 * because the last-paint-volume is used to determine the old screen
3665 * space location of an actor that has moved so we can know the
3666 * minimal region to redraw to clear an old view of the actor. If we
3667 * update this during picking then by the time we come around to
3668 * paint then the last-paint-volume would likely represent the new
3669 * actor position not the old.
3671 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3674 /* annoyingly gcc warns if uninitialized even though
3675 * the initialization is redundant :-( */
3676 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3678 if (G_LIKELY ((clutter_paint_debug_flags &
3679 (CLUTTER_DEBUG_DISABLE_CULLING |
3680 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3681 (CLUTTER_DEBUG_DISABLE_CULLING |
3682 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3683 _clutter_actor_update_last_paint_volume (self);
3685 success = cull_actor (self, &result);
3687 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3688 _clutter_actor_paint_cull_result (self, success, result);
3689 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3693 if (priv->effects == NULL)
3695 if (pick_mode == CLUTTER_PICK_NONE &&
3696 actor_has_shader_data (self))
3698 _clutter_actor_shader_pre_paint (self, FALSE);
3699 shader_applied = TRUE;
3702 priv->next_effect_to_paint = NULL;
3705 priv->next_effect_to_paint =
3706 _clutter_meta_group_peek_metas (priv->effects);
3708 clutter_actor_continue_paint (self);
3711 _clutter_actor_shader_post_paint (self);
3713 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3714 pick_mode == CLUTTER_PICK_NONE))
3715 _clutter_actor_draw_paint_volume (self);
3718 /* If we make it here then the actor has run through a complete
3719 paint run including all the effects so it's no longer dirty */
3720 if (pick_mode == CLUTTER_PICK_NONE)
3721 priv->is_dirty = FALSE;
3728 /* paint sequence complete */
3729 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3733 * clutter_actor_continue_paint:
3734 * @self: A #ClutterActor
3736 * Run the next stage of the paint sequence. This function should only
3737 * be called within the implementation of the ‘run’ virtual of a
3738 * #ClutterEffect. It will cause the run method of the next effect to
3739 * be applied, or it will paint the actual actor if the current effect
3740 * is the last effect in the chain.
3745 clutter_actor_continue_paint (ClutterActor *self)
3747 ClutterActorPrivate *priv;
3749 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3750 /* This should only be called from with in the ‘run’ implementation
3751 of a ClutterEffect */
3752 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3756 /* Skip any effects that are disabled */
3757 while (priv->next_effect_to_paint &&
3758 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3759 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3761 /* If this has come from the last effect then we'll just paint the
3763 if (priv->next_effect_to_paint == NULL)
3765 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3767 ClutterPaintNode *dummy;
3769 /* XXX - this will go away in 2.0, when we can get rid of this
3770 * stuff and switch to a pure retained render tree of PaintNodes
3771 * for the entire frame, starting from the Stage; the paint()
3772 * virtual function can then be called directly.
3774 dummy = _clutter_dummy_node_new (self);
3775 clutter_paint_node_set_name (dummy, "Root");
3777 /* XXX - for 1.12, we use the return value of paint_node() to
3778 * decide whether we should emit the ::paint signal.
3780 clutter_actor_paint_node (self, dummy);
3781 clutter_paint_node_unref (dummy);
3783 g_signal_emit (self, actor_signals[PAINT], 0);
3787 ClutterColor col = { 0, };
3789 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3791 /* Actor will then paint silhouette of itself in supplied
3792 * color. See clutter_stage_get_actor_at_pos() for where
3793 * picking is enabled.
3795 g_signal_emit (self, actor_signals[PICK], 0, &col);
3800 ClutterEffect *old_current_effect;
3801 ClutterEffectPaintFlags run_flags = 0;
3803 /* Cache the current effect so that we can put it back before
3805 old_current_effect = priv->current_effect;
3807 priv->current_effect = priv->next_effect_to_paint->data;
3808 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3810 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3814 /* If there's an effect queued with this redraw then all
3815 effects up to that one will be considered dirty. It
3816 is expected the queued effect will paint the cached
3817 image and not call clutter_actor_continue_paint again
3818 (although it should work ok if it does) */
3819 if (priv->effect_to_redraw == NULL ||
3820 priv->current_effect != priv->effect_to_redraw)
3821 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3824 _clutter_effect_paint (priv->current_effect, run_flags);
3828 /* We can't determine when an actor has been modified since
3829 its last pick so lets just assume it has always been
3831 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3833 _clutter_effect_pick (priv->current_effect, run_flags);
3836 priv->current_effect = old_current_effect;
3841 _clutter_actor_stop_transitions (ClutterActor *self)
3843 const ClutterAnimationInfo *info;
3844 GHashTableIter iter;
3847 info = _clutter_actor_get_animation_info_or_defaults (self);
3848 if (info->transitions == NULL)
3851 g_hash_table_iter_init (&iter, info->transitions);
3852 while (g_hash_table_iter_next (&iter, NULL, &value))
3854 TransitionClosure *closure = value;
3855 clutter_timeline_stop (CLUTTER_TIMELINE (closure->transition));
3859 static ClutterActorTraverseVisitFlags
3860 invalidate_queue_redraw_entry (ClutterActor *self,
3864 ClutterActorPrivate *priv = self->priv;
3866 if (priv->queue_redraw_entry != NULL)
3868 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3869 priv->queue_redraw_entry = NULL;
3872 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3876 remove_child (ClutterActor *self,
3877 ClutterActor *child)
3879 ClutterActor *prev_sibling, *next_sibling;
3881 prev_sibling = child->priv->prev_sibling;
3882 next_sibling = child->priv->next_sibling;
3884 if (prev_sibling != NULL)
3885 prev_sibling->priv->next_sibling = next_sibling;
3887 if (next_sibling != NULL)
3888 next_sibling->priv->prev_sibling = prev_sibling;
3890 if (self->priv->first_child == child)
3891 self->priv->first_child = next_sibling;
3893 if (self->priv->last_child == child)
3894 self->priv->last_child = prev_sibling;
3896 child->priv->parent = NULL;
3897 child->priv->prev_sibling = NULL;
3898 child->priv->next_sibling = NULL;
3902 REMOVE_CHILD_DESTROY_META = 1 << 0,
3903 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3904 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3905 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3906 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3907 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3908 REMOVE_CHILD_STOP_TRANSITIONS = 1 << 6,
3910 /* default flags for public API */
3911 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_STOP_TRANSITIONS |
3912 REMOVE_CHILD_DESTROY_META |
3913 REMOVE_CHILD_EMIT_PARENT_SET |
3914 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3915 REMOVE_CHILD_CHECK_STATE |
3916 REMOVE_CHILD_FLUSH_QUEUE |
3917 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3919 /* flags for legacy/deprecated API */
3920 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_STOP_TRANSITIONS |
3921 REMOVE_CHILD_CHECK_STATE |
3922 REMOVE_CHILD_FLUSH_QUEUE |
3923 REMOVE_CHILD_EMIT_PARENT_SET |
3924 REMOVE_CHILD_NOTIFY_FIRST_LAST
3925 } ClutterActorRemoveChildFlags;
3928 * clutter_actor_remove_child_internal:
3929 * @self: a #ClutterActor
3930 * @child: the child of @self that has to be removed
3931 * @flags: control the removal operations
3933 * Removes @child from the list of children of @self.
3936 clutter_actor_remove_child_internal (ClutterActor *self,
3937 ClutterActor *child,
3938 ClutterActorRemoveChildFlags flags)
3940 ClutterActor *old_first, *old_last;
3941 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3942 gboolean flush_queue;
3943 gboolean notify_first_last;
3944 gboolean was_mapped;
3945 gboolean stop_transitions;
3947 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3948 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3949 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3950 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3951 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3952 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3953 stop_transitions = (flags & REMOVE_CHILD_STOP_TRANSITIONS) != 0;
3955 g_object_freeze_notify (G_OBJECT (self));
3957 if (stop_transitions)
3958 _clutter_actor_stop_transitions (child);
3961 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3965 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3967 /* we need to unrealize *before* we set parent_actor to NULL,
3968 * because in an unrealize method actors are dissociating from the
3969 * stage, which means they need to be able to
3970 * clutter_actor_get_stage().
3972 * yhis should unmap and unrealize, unless we're reparenting.
3974 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3981 /* We take this opportunity to invalidate any queue redraw entry
3982 * associated with the actor and descendants since we won't be able to
3983 * determine the appropriate stage after this.
3985 * we do this after we updated the mapped state because actors might
3986 * end up queueing redraws inside their mapped/unmapped virtual
3987 * functions, and if we invalidate the redraw entry we could end up
3988 * with an inconsistent state and weird memory corruption. see
3991 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3992 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3994 _clutter_actor_traverse (child,
3996 invalidate_queue_redraw_entry,
4001 old_first = self->priv->first_child;
4002 old_last = self->priv->last_child;
4004 remove_child (self, child);
4006 self->priv->n_children -= 1;
4008 self->priv->age += 1;
4010 /* if the child that got removed was visible and set to
4011 * expand then we want to reset the parent's state in
4012 * case the child was the only thing that was making it
4015 if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
4016 (child->priv->needs_compute_expand ||
4017 child->priv->needs_x_expand ||
4018 child->priv->needs_y_expand))
4020 clutter_actor_queue_compute_expand (self);
4023 /* clutter_actor_reparent() will emit ::parent-set for us */
4024 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
4025 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
4027 /* if the child was mapped then we need to relayout ourselves to account
4028 * for the removed child
4031 clutter_actor_queue_relayout (self);
4033 /* we need to emit the signal before dropping the reference */
4034 if (emit_actor_removed)
4035 g_signal_emit_by_name (self, "actor-removed", child);
4037 if (notify_first_last)
4039 if (old_first != self->priv->first_child)
4040 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
4042 if (old_last != self->priv->last_child)
4043 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
4046 g_object_thaw_notify (G_OBJECT (self));
4048 /* remove the reference we acquired in clutter_actor_add_child() */
4049 g_object_unref (child);
4052 static const ClutterTransformInfo default_transform_info = {
4053 0.0, { 0, }, /* rotation-x */
4054 0.0, { 0, }, /* rotation-y */
4055 0.0, { 0, }, /* rotation-z */
4057 1.0, 1.0, { 0, }, /* scale */
4059 { 0, }, /* anchor */
4065 * _clutter_actor_get_transform_info_or_defaults:
4066 * @self: a #ClutterActor
4068 * Retrieves the ClutterTransformInfo structure associated to an actor.
4070 * If the actor does not have a ClutterTransformInfo structure associated
4071 * to it, then the default structure will be returned.
4073 * This function should only be used for getters.
4075 * Return value: a const pointer to the ClutterTransformInfo structure
4077 const ClutterTransformInfo *
4078 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
4080 ClutterTransformInfo *info;
4082 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4086 return &default_transform_info;
4090 clutter_transform_info_free (gpointer data)
4093 g_slice_free (ClutterTransformInfo, data);
4097 * _clutter_actor_get_transform_info:
4098 * @self: a #ClutterActor
4100 * Retrieves a pointer to the ClutterTransformInfo structure.
4102 * If the actor does not have a ClutterTransformInfo associated to it, one
4103 * will be created and initialized to the default values.
4105 * This function should be used for setters.
4107 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
4110 * Return value: (transfer none): a pointer to the ClutterTransformInfo
4113 ClutterTransformInfo *
4114 _clutter_actor_get_transform_info (ClutterActor *self)
4116 ClutterTransformInfo *info;
4118 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4121 info = g_slice_new (ClutterTransformInfo);
4123 *info = default_transform_info;
4125 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4127 clutter_transform_info_free);
4134 * clutter_actor_set_rotation_angle_internal:
4135 * @self: a #ClutterActor
4136 * @axis: the axis of the angle to change
4137 * @angle: the angle of rotation
4139 * Sets the rotation angle on the given axis without affecting the
4140 * rotation center point.
4143 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
4144 ClutterRotateAxis axis,
4147 GObject *obj = G_OBJECT (self);
4148 ClutterTransformInfo *info;
4150 info = _clutter_actor_get_transform_info (self);
4152 g_object_freeze_notify (obj);
4156 case CLUTTER_X_AXIS:
4157 info->rx_angle = angle;
4158 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4161 case CLUTTER_Y_AXIS:
4162 info->ry_angle = angle;
4163 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4166 case CLUTTER_Z_AXIS:
4167 info->rz_angle = angle;
4168 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4172 self->priv->transform_valid = FALSE;
4174 g_object_thaw_notify (obj);
4176 clutter_actor_queue_redraw (self);
4180 clutter_actor_set_rotation_angle (ClutterActor *self,
4181 ClutterRotateAxis axis,
4184 const ClutterTransformInfo *info;
4185 const double *cur_angle_p = NULL;
4186 GParamSpec *pspec = NULL;
4188 info = _clutter_actor_get_transform_info_or_defaults (self);
4192 case CLUTTER_X_AXIS:
4193 cur_angle_p = &info->rx_angle;
4194 pspec = obj_props[PROP_ROTATION_ANGLE_X];
4197 case CLUTTER_Y_AXIS:
4198 cur_angle_p = &info->ry_angle;
4199 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4202 case CLUTTER_Z_AXIS:
4203 cur_angle_p = &info->rz_angle;
4204 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4208 g_assert (pspec != NULL);
4209 g_assert (cur_angle_p != NULL);
4211 if (_clutter_actor_get_transition (self, pspec) == NULL)
4212 _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4214 _clutter_actor_update_transition (self, pspec, angle);
4216 clutter_actor_queue_redraw (self);
4220 * clutter_actor_set_rotation_center_internal:
4221 * @self: a #ClutterActor
4222 * @axis: the axis of the center to change
4223 * @center: the coordinates of the rotation center
4225 * Sets the rotation center on the given axis without affecting the
4229 clutter_actor_set_rotation_center_internal (ClutterActor *self,
4230 ClutterRotateAxis axis,
4231 const ClutterVertex *center)
4233 GObject *obj = G_OBJECT (self);
4234 ClutterTransformInfo *info;
4235 ClutterVertex v = { 0, 0, 0 };
4237 info = _clutter_actor_get_transform_info (self);
4242 g_object_freeze_notify (obj);
4246 case CLUTTER_X_AXIS:
4247 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4248 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4251 case CLUTTER_Y_AXIS:
4252 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4253 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4256 case CLUTTER_Z_AXIS:
4257 /* if the previously set rotation center was fractional, then
4258 * setting explicit coordinates will have to notify the
4259 * :rotation-center-z-gravity property as well
4261 if (info->rz_center.is_fractional)
4262 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4264 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4265 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4269 self->priv->transform_valid = FALSE;
4271 g_object_thaw_notify (obj);
4273 clutter_actor_queue_redraw (self);
4277 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4281 GObject *obj = G_OBJECT (self);
4282 ClutterTransformInfo *info;
4284 info = _clutter_actor_get_transform_info (self);
4286 if (pspec == obj_props[PROP_SCALE_X])
4287 info->scale_x = factor;
4289 info->scale_y = factor;
4291 self->priv->transform_valid = FALSE;
4292 clutter_actor_queue_redraw (self);
4293 g_object_notify_by_pspec (obj, pspec);
4297 clutter_actor_set_scale_factor (ClutterActor *self,
4298 ClutterRotateAxis axis,
4301 const ClutterTransformInfo *info;
4302 const double *scale_p = NULL;
4303 GParamSpec *pspec = NULL;
4305 info = _clutter_actor_get_transform_info_or_defaults (self);
4309 case CLUTTER_X_AXIS:
4310 pspec = obj_props[PROP_SCALE_X];
4311 scale_p = &info->scale_x;
4314 case CLUTTER_Y_AXIS:
4315 pspec = obj_props[PROP_SCALE_Y];
4316 scale_p = &info->scale_y;
4319 case CLUTTER_Z_AXIS:
4323 g_assert (pspec != NULL);
4324 g_assert (scale_p != NULL);
4326 if (_clutter_actor_get_transition (self, pspec) == NULL)
4327 _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4329 _clutter_actor_update_transition (self, pspec, factor);
4331 clutter_actor_queue_redraw (self);
4335 clutter_actor_set_scale_center (ClutterActor *self,
4336 ClutterRotateAxis axis,
4339 GObject *obj = G_OBJECT (self);
4340 ClutterTransformInfo *info;
4341 gfloat center_x, center_y;
4343 info = _clutter_actor_get_transform_info (self);
4345 g_object_freeze_notify (obj);
4347 /* get the current scale center coordinates */
4348 clutter_anchor_coord_get_units (self, &info->scale_center,
4353 /* we need to notify this too, because setting explicit coordinates will
4354 * change the gravity as a side effect
4356 if (info->scale_center.is_fractional)
4357 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4361 case CLUTTER_X_AXIS:
4362 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4363 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4366 case CLUTTER_Y_AXIS:
4367 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4368 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4372 g_assert_not_reached ();
4375 self->priv->transform_valid = FALSE;
4377 clutter_actor_queue_redraw (self);
4379 g_object_thaw_notify (obj);
4383 clutter_actor_set_scale_gravity (ClutterActor *self,
4384 ClutterGravity gravity)
4386 ClutterTransformInfo *info;
4389 info = _clutter_actor_get_transform_info (self);
4390 obj = G_OBJECT (self);
4392 if (gravity == CLUTTER_GRAVITY_NONE)
4393 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4395 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4397 self->priv->transform_valid = FALSE;
4399 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4400 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4401 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4403 clutter_actor_queue_redraw (self);
4407 clutter_actor_set_anchor_coord (ClutterActor *self,
4408 ClutterRotateAxis axis,
4411 GObject *obj = G_OBJECT (self);
4412 ClutterTransformInfo *info;
4413 gfloat anchor_x, anchor_y;
4415 info = _clutter_actor_get_transform_info (self);
4417 g_object_freeze_notify (obj);
4419 clutter_anchor_coord_get_units (self, &info->anchor,
4424 if (info->anchor.is_fractional)
4425 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4429 case CLUTTER_X_AXIS:
4430 clutter_anchor_coord_set_units (&info->anchor,
4434 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4437 case CLUTTER_Y_AXIS:
4438 clutter_anchor_coord_set_units (&info->anchor,
4442 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4446 g_assert_not_reached ();
4449 self->priv->transform_valid = FALSE;
4451 clutter_actor_queue_redraw (self);
4453 g_object_thaw_notify (obj);
4457 clutter_actor_set_property (GObject *object,
4459 const GValue *value,
4462 ClutterActor *actor = CLUTTER_ACTOR (object);
4463 ClutterActorPrivate *priv = actor->priv;
4468 clutter_actor_set_x (actor, g_value_get_float (value));
4472 clutter_actor_set_y (actor, g_value_get_float (value));
4477 const ClutterPoint *pos = g_value_get_boxed (value);
4480 clutter_actor_set_position (actor, pos->x, pos->y);
4482 clutter_actor_set_fixed_position_set (actor, FALSE);
4487 clutter_actor_set_width (actor, g_value_get_float (value));
4491 clutter_actor_set_height (actor, g_value_get_float (value));
4496 const ClutterSize *size = g_value_get_boxed (value);
4499 clutter_actor_set_size (actor, size->width, size->height);
4501 clutter_actor_set_size (actor, -1, -1);
4506 clutter_actor_set_x (actor, g_value_get_float (value));
4510 clutter_actor_set_y (actor, g_value_get_float (value));
4513 case PROP_FIXED_POSITION_SET:
4514 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4517 case PROP_MIN_WIDTH:
4518 clutter_actor_set_min_width (actor, g_value_get_float (value));
4521 case PROP_MIN_HEIGHT:
4522 clutter_actor_set_min_height (actor, g_value_get_float (value));
4525 case PROP_NATURAL_WIDTH:
4526 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4529 case PROP_NATURAL_HEIGHT:
4530 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4533 case PROP_MIN_WIDTH_SET:
4534 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4537 case PROP_MIN_HEIGHT_SET:
4538 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4541 case PROP_NATURAL_WIDTH_SET:
4542 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4545 case PROP_NATURAL_HEIGHT_SET:
4546 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4549 case PROP_REQUEST_MODE:
4550 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4554 clutter_actor_set_depth (actor, g_value_get_float (value));
4558 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4561 case PROP_OFFSCREEN_REDIRECT:
4562 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4566 clutter_actor_set_name (actor, g_value_get_string (value));
4570 if (g_value_get_boolean (value) == TRUE)
4571 clutter_actor_show (actor);
4573 clutter_actor_hide (actor);
4577 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4578 g_value_get_double (value));
4582 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4583 g_value_get_double (value));
4586 case PROP_SCALE_CENTER_X:
4587 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4588 g_value_get_float (value));
4591 case PROP_SCALE_CENTER_Y:
4592 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4593 g_value_get_float (value));
4596 case PROP_SCALE_GRAVITY:
4597 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4602 const ClutterGeometry *geom = g_value_get_boxed (value);
4604 clutter_actor_set_clip (actor,
4606 geom->width, geom->height);
4610 case PROP_CLIP_TO_ALLOCATION:
4611 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4615 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4618 case PROP_ROTATION_ANGLE_X:
4619 clutter_actor_set_rotation_angle (actor,
4621 g_value_get_double (value));
4624 case PROP_ROTATION_ANGLE_Y:
4625 clutter_actor_set_rotation_angle (actor,
4627 g_value_get_double (value));
4630 case PROP_ROTATION_ANGLE_Z:
4631 clutter_actor_set_rotation_angle (actor,
4633 g_value_get_double (value));
4636 case PROP_ROTATION_CENTER_X:
4637 clutter_actor_set_rotation_center_internal (actor,
4639 g_value_get_boxed (value));
4642 case PROP_ROTATION_CENTER_Y:
4643 clutter_actor_set_rotation_center_internal (actor,
4645 g_value_get_boxed (value));
4648 case PROP_ROTATION_CENTER_Z:
4649 clutter_actor_set_rotation_center_internal (actor,
4651 g_value_get_boxed (value));
4654 case PROP_ROTATION_CENTER_Z_GRAVITY:
4656 const ClutterTransformInfo *info;
4658 info = _clutter_actor_get_transform_info_or_defaults (actor);
4659 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4660 g_value_get_enum (value));
4665 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4666 g_value_get_float (value));
4670 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4671 g_value_get_float (value));
4674 case PROP_ANCHOR_GRAVITY:
4675 clutter_actor_set_anchor_point_from_gravity (actor,
4676 g_value_get_enum (value));
4679 case PROP_SHOW_ON_SET_PARENT:
4680 priv->show_on_set_parent = g_value_get_boolean (value);
4683 case PROP_TEXT_DIRECTION:
4684 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4688 clutter_actor_add_action (actor, g_value_get_object (value));
4691 case PROP_CONSTRAINTS:
4692 clutter_actor_add_constraint (actor, g_value_get_object (value));
4696 clutter_actor_add_effect (actor, g_value_get_object (value));
4699 case PROP_LAYOUT_MANAGER:
4700 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4704 clutter_actor_set_x_expand (actor, g_value_get_boolean (value));
4708 clutter_actor_set_y_expand (actor, g_value_get_boolean (value));
4712 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4716 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4719 case PROP_MARGIN_TOP:
4720 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4723 case PROP_MARGIN_BOTTOM:
4724 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4727 case PROP_MARGIN_LEFT:
4728 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4731 case PROP_MARGIN_RIGHT:
4732 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4735 case PROP_BACKGROUND_COLOR:
4736 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4740 clutter_actor_set_content (actor, g_value_get_object (value));
4743 case PROP_CONTENT_GRAVITY:
4744 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4747 case PROP_MINIFICATION_FILTER:
4748 clutter_actor_set_content_scaling_filters (actor,
4749 g_value_get_enum (value),
4750 actor->priv->mag_filter);
4753 case PROP_MAGNIFICATION_FILTER:
4754 clutter_actor_set_content_scaling_filters (actor,
4755 actor->priv->min_filter,
4756 g_value_get_enum (value));
4759 case PROP_CONTENT_REPEAT:
4760 clutter_actor_set_content_repeat (actor, g_value_get_flags (value));
4764 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4770 clutter_actor_get_property (GObject *object,
4775 ClutterActor *actor = CLUTTER_ACTOR (object);
4776 ClutterActorPrivate *priv = actor->priv;
4781 g_value_set_float (value, clutter_actor_get_x (actor));
4785 g_value_set_float (value, clutter_actor_get_y (actor));
4790 ClutterPoint position;
4792 clutter_point_init (&position,
4793 clutter_actor_get_x (actor),
4794 clutter_actor_get_y (actor));
4795 g_value_set_boxed (value, &position);
4800 g_value_set_float (value, clutter_actor_get_width (actor));
4804 g_value_set_float (value, clutter_actor_get_height (actor));
4811 clutter_size_init (&size,
4812 clutter_actor_get_width (actor),
4813 clutter_actor_get_height (actor));
4814 g_value_set_boxed (value, &size);
4820 const ClutterLayoutInfo *info;
4822 info = _clutter_actor_get_layout_info_or_defaults (actor);
4823 g_value_set_float (value, info->fixed_pos.x);
4829 const ClutterLayoutInfo *info;
4831 info = _clutter_actor_get_layout_info_or_defaults (actor);
4832 g_value_set_float (value, info->fixed_pos.y);
4836 case PROP_FIXED_POSITION_SET:
4837 g_value_set_boolean (value, priv->position_set);
4840 case PROP_MIN_WIDTH:
4842 const ClutterLayoutInfo *info;
4844 info = _clutter_actor_get_layout_info_or_defaults (actor);
4845 g_value_set_float (value, info->minimum.width);
4849 case PROP_MIN_HEIGHT:
4851 const ClutterLayoutInfo *info;
4853 info = _clutter_actor_get_layout_info_or_defaults (actor);
4854 g_value_set_float (value, info->minimum.height);
4858 case PROP_NATURAL_WIDTH:
4860 const ClutterLayoutInfo *info;
4862 info = _clutter_actor_get_layout_info_or_defaults (actor);
4863 g_value_set_float (value, info->natural.width);
4867 case PROP_NATURAL_HEIGHT:
4869 const ClutterLayoutInfo *info;
4871 info = _clutter_actor_get_layout_info_or_defaults (actor);
4872 g_value_set_float (value, info->natural.height);
4876 case PROP_MIN_WIDTH_SET:
4877 g_value_set_boolean (value, priv->min_width_set);
4880 case PROP_MIN_HEIGHT_SET:
4881 g_value_set_boolean (value, priv->min_height_set);
4884 case PROP_NATURAL_WIDTH_SET:
4885 g_value_set_boolean (value, priv->natural_width_set);
4888 case PROP_NATURAL_HEIGHT_SET:
4889 g_value_set_boolean (value, priv->natural_height_set);
4892 case PROP_REQUEST_MODE:
4893 g_value_set_enum (value, priv->request_mode);
4896 case PROP_ALLOCATION:
4897 g_value_set_boxed (value, &priv->allocation);
4901 g_value_set_float (value, clutter_actor_get_depth (actor));
4905 g_value_set_uint (value, priv->opacity);
4908 case PROP_OFFSCREEN_REDIRECT:
4909 g_value_set_enum (value, priv->offscreen_redirect);
4913 g_value_set_string (value, priv->name);
4917 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4921 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4925 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4929 g_value_set_boolean (value, priv->has_clip);
4934 ClutterGeometry clip;
4936 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4937 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4938 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4939 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4941 g_value_set_boxed (value, &clip);
4945 case PROP_CLIP_TO_ALLOCATION:
4946 g_value_set_boolean (value, priv->clip_to_allocation);
4951 const ClutterTransformInfo *info;
4953 info = _clutter_actor_get_transform_info_or_defaults (actor);
4954 g_value_set_double (value, info->scale_x);
4960 const ClutterTransformInfo *info;
4962 info = _clutter_actor_get_transform_info_or_defaults (actor);
4963 g_value_set_double (value, info->scale_y);
4967 case PROP_SCALE_CENTER_X:
4971 clutter_actor_get_scale_center (actor, ¢er, NULL);
4973 g_value_set_float (value, center);
4977 case PROP_SCALE_CENTER_Y:
4981 clutter_actor_get_scale_center (actor, NULL, ¢er);
4983 g_value_set_float (value, center);
4987 case PROP_SCALE_GRAVITY:
4988 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4992 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4995 case PROP_ROTATION_ANGLE_X:
4997 const ClutterTransformInfo *info;
4999 info = _clutter_actor_get_transform_info_or_defaults (actor);
5000 g_value_set_double (value, info->rx_angle);
5004 case PROP_ROTATION_ANGLE_Y:
5006 const ClutterTransformInfo *info;
5008 info = _clutter_actor_get_transform_info_or_defaults (actor);
5009 g_value_set_double (value, info->ry_angle);
5013 case PROP_ROTATION_ANGLE_Z:
5015 const ClutterTransformInfo *info;
5017 info = _clutter_actor_get_transform_info_or_defaults (actor);
5018 g_value_set_double (value, info->rz_angle);
5022 case PROP_ROTATION_CENTER_X:
5024 ClutterVertex center;
5026 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
5031 g_value_set_boxed (value, ¢er);
5035 case PROP_ROTATION_CENTER_Y:
5037 ClutterVertex center;
5039 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
5044 g_value_set_boxed (value, ¢er);
5048 case PROP_ROTATION_CENTER_Z:
5050 ClutterVertex center;
5052 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
5057 g_value_set_boxed (value, ¢er);
5061 case PROP_ROTATION_CENTER_Z_GRAVITY:
5062 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
5067 const ClutterTransformInfo *info;
5070 info = _clutter_actor_get_transform_info_or_defaults (actor);
5071 clutter_anchor_coord_get_units (actor, &info->anchor,
5075 g_value_set_float (value, anchor_x);
5081 const ClutterTransformInfo *info;
5084 info = _clutter_actor_get_transform_info_or_defaults (actor);
5085 clutter_anchor_coord_get_units (actor, &info->anchor,
5089 g_value_set_float (value, anchor_y);
5093 case PROP_ANCHOR_GRAVITY:
5094 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
5097 case PROP_SHOW_ON_SET_PARENT:
5098 g_value_set_boolean (value, priv->show_on_set_parent);
5101 case PROP_TEXT_DIRECTION:
5102 g_value_set_enum (value, priv->text_direction);
5105 case PROP_HAS_POINTER:
5106 g_value_set_boolean (value, priv->has_pointer);
5109 case PROP_LAYOUT_MANAGER:
5110 g_value_set_object (value, priv->layout_manager);
5115 const ClutterLayoutInfo *info;
5117 info = _clutter_actor_get_layout_info_or_defaults (actor);
5118 g_value_set_boolean (value, info->x_expand);
5124 const ClutterLayoutInfo *info;
5126 info = _clutter_actor_get_layout_info_or_defaults (actor);
5127 g_value_set_boolean (value, info->y_expand);
5133 const ClutterLayoutInfo *info;
5135 info = _clutter_actor_get_layout_info_or_defaults (actor);
5136 g_value_set_enum (value, info->x_align);
5142 const ClutterLayoutInfo *info;
5144 info = _clutter_actor_get_layout_info_or_defaults (actor);
5145 g_value_set_enum (value, info->y_align);
5149 case PROP_MARGIN_TOP:
5151 const ClutterLayoutInfo *info;
5153 info = _clutter_actor_get_layout_info_or_defaults (actor);
5154 g_value_set_float (value, info->margin.top);
5158 case PROP_MARGIN_BOTTOM:
5160 const ClutterLayoutInfo *info;
5162 info = _clutter_actor_get_layout_info_or_defaults (actor);
5163 g_value_set_float (value, info->margin.bottom);
5167 case PROP_MARGIN_LEFT:
5169 const ClutterLayoutInfo *info;
5171 info = _clutter_actor_get_layout_info_or_defaults (actor);
5172 g_value_set_float (value, info->margin.left);
5176 case PROP_MARGIN_RIGHT:
5178 const ClutterLayoutInfo *info;
5180 info = _clutter_actor_get_layout_info_or_defaults (actor);
5181 g_value_set_float (value, info->margin.right);
5185 case PROP_BACKGROUND_COLOR_SET:
5186 g_value_set_boolean (value, priv->bg_color_set);
5189 case PROP_BACKGROUND_COLOR:
5190 g_value_set_boxed (value, &priv->bg_color);
5193 case PROP_FIRST_CHILD:
5194 g_value_set_object (value, priv->first_child);
5197 case PROP_LAST_CHILD:
5198 g_value_set_object (value, priv->last_child);
5202 g_value_set_object (value, priv->content);
5205 case PROP_CONTENT_GRAVITY:
5206 g_value_set_enum (value, priv->content_gravity);
5209 case PROP_CONTENT_BOX:
5211 ClutterActorBox box = { 0, };
5213 clutter_actor_get_content_box (actor, &box);
5214 g_value_set_boxed (value, &box);
5218 case PROP_MINIFICATION_FILTER:
5219 g_value_set_enum (value, priv->min_filter);
5222 case PROP_MAGNIFICATION_FILTER:
5223 g_value_set_enum (value, priv->mag_filter);
5226 case PROP_CONTENT_REPEAT:
5227 g_value_set_flags (value, priv->content_repeat);
5231 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5237 clutter_actor_dispose (GObject *object)
5239 ClutterActor *self = CLUTTER_ACTOR (object);
5240 ClutterActorPrivate *priv = self->priv;
5242 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5244 g_type_name (G_OBJECT_TYPE (self)),
5247 g_signal_emit (self, actor_signals[DESTROY], 0);
5249 /* avoid recursing when called from clutter_actor_destroy() */
5250 if (priv->parent != NULL)
5252 ClutterActor *parent = priv->parent;
5254 /* go through the Container implementation unless this
5255 * is an internal child and has been marked as such.
5257 * removing the actor from its parent will reset the
5258 * realized and mapped states.
5260 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5261 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5263 clutter_actor_remove_child_internal (parent, self,
5264 REMOVE_CHILD_LEGACY_FLAGS);
5267 /* parent must be gone at this point */
5268 g_assert (priv->parent == NULL);
5270 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5272 /* can't be mapped or realized with no parent */
5273 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5274 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5277 g_clear_object (&priv->pango_context);
5278 g_clear_object (&priv->actions);
5279 g_clear_object (&priv->constraints);
5280 g_clear_object (&priv->effects);
5281 g_clear_object (&priv->flatten_effect);
5283 if (priv->layout_manager != NULL)
5285 clutter_layout_manager_set_container (priv->layout_manager, NULL);
5286 g_clear_object (&priv->layout_manager);
5289 if (priv->content != NULL)
5291 _clutter_content_detached (priv->content, self);
5292 g_clear_object (&priv->content);
5295 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5299 clutter_actor_finalize (GObject *object)
5301 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5303 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5304 priv->name != NULL ? priv->name : "<none>",
5306 g_type_name (G_OBJECT_TYPE (object)));
5308 _clutter_context_release_id (priv->id);
5310 g_free (priv->name);
5312 #ifdef CLUTTER_ENABLE_DEBUG
5313 g_free (priv->debug_name);
5316 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5321 * clutter_actor_get_accessible:
5322 * @self: a #ClutterActor
5324 * Returns the accessible object that describes the actor to an
5325 * assistive technology.
5327 * If no class-specific #AtkObject implementation is available for the
5328 * actor instance in question, it will inherit an #AtkObject
5329 * implementation from the first ancestor class for which such an
5330 * implementation is defined.
5332 * The documentation of the <ulink
5333 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5334 * library contains more information about accessible objects and
5337 * Returns: (transfer none): the #AtkObject associated with @actor
5340 clutter_actor_get_accessible (ClutterActor *self)
5342 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5344 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5348 clutter_actor_real_get_accessible (ClutterActor *actor)
5350 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5354 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5356 AtkObject *accessible;
5358 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5359 if (accessible != NULL)
5360 g_object_ref (accessible);
5366 atk_implementor_iface_init (AtkImplementorIface *iface)
5368 iface->ref_accessible = _clutter_actor_ref_accessible;
5372 clutter_actor_update_default_paint_volume (ClutterActor *self,
5373 ClutterPaintVolume *volume)
5375 ClutterActorPrivate *priv = self->priv;
5376 gboolean res = TRUE;
5378 /* we start from the allocation */
5379 clutter_paint_volume_set_width (volume,
5380 priv->allocation.x2 - priv->allocation.x1);
5381 clutter_paint_volume_set_height (volume,
5382 priv->allocation.y2 - priv->allocation.y1);
5384 /* if the actor has a clip set then we have a pretty definite
5385 * size for the paint volume: the actor cannot possibly paint
5386 * outside the clip region.
5388 if (priv->clip_to_allocation)
5390 /* the allocation has already been set, so we just flip the
5397 ClutterActor *child;
5399 if (priv->has_clip &&
5400 priv->clip.width >= 0 &&
5401 priv->clip.height >= 0)
5403 ClutterVertex origin;
5405 origin.x = priv->clip.x;
5406 origin.y = priv->clip.y;
5409 clutter_paint_volume_set_origin (volume, &origin);
5410 clutter_paint_volume_set_width (volume, priv->clip.width);
5411 clutter_paint_volume_set_height (volume, priv->clip.height);
5416 /* if we don't have children we just bail out here... */
5417 if (priv->n_children == 0)
5420 /* ...but if we have children then we ask for their paint volume in
5421 * our coordinates. if any of our children replies that it doesn't
5422 * have a paint volume, we bail out
5424 for (child = priv->first_child;
5426 child = child->priv->next_sibling)
5428 const ClutterPaintVolume *child_volume;
5430 if (!CLUTTER_ACTOR_IS_MAPPED (child))
5433 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5434 if (child_volume == NULL)
5440 clutter_paint_volume_union (volume, child_volume);
5450 clutter_actor_real_get_paint_volume (ClutterActor *self,
5451 ClutterPaintVolume *volume)
5453 ClutterActorClass *klass;
5456 klass = CLUTTER_ACTOR_GET_CLASS (self);
5458 /* XXX - this thoroughly sucks, but we don't want to penalize users
5459 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5460 * redraw. This should go away in 2.0.
5462 if (klass->paint == clutter_actor_real_paint &&
5463 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5469 /* this is the default return value: we cannot know if a class
5470 * is going to paint outside its allocation, so we take the
5471 * conservative approach.
5476 /* update_default_paint_volume() should only fail if one of the children
5477 * reported an invalid, or no, paint volume
5479 if (!clutter_actor_update_default_paint_volume (self, volume))
5486 * clutter_actor_get_default_paint_volume:
5487 * @self: a #ClutterActor
5489 * Retrieves the default paint volume for @self.
5491 * This function provides the same #ClutterPaintVolume that would be
5492 * computed by the default implementation inside #ClutterActor of the
5493 * #ClutterActorClass.get_paint_volume() virtual function.
5495 * This function should only be used by #ClutterActor subclasses that
5496 * cannot chain up to the parent implementation when computing their
5499 * Return value: (transfer none): a pointer to the default
5500 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5501 * the actor could not compute a valid paint volume. The returned value
5502 * is not guaranteed to be stable across multiple frames, so if you
5503 * want to retain it, you will need to copy it using
5504 * clutter_paint_volume_copy().
5508 const ClutterPaintVolume *
5509 clutter_actor_get_default_paint_volume (ClutterActor *self)
5511 ClutterPaintVolume volume;
5512 ClutterPaintVolume *res;
5514 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5517 _clutter_paint_volume_init_static (&volume, self);
5518 if (clutter_actor_update_default_paint_volume (self, &volume))
5520 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5524 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5525 _clutter_paint_volume_copy_static (&volume, res);
5529 clutter_paint_volume_free (&volume);
5535 clutter_actor_real_has_overlaps (ClutterActor *self)
5537 /* By default we'll assume that all actors need an offscreen redirect to get
5538 * the correct opacity. Actors such as ClutterTexture that would never need
5539 * an offscreen redirect can override this to return FALSE. */
5544 clutter_actor_real_destroy (ClutterActor *actor)
5546 ClutterActorIter iter;
5548 g_object_freeze_notify (G_OBJECT (actor));
5550 clutter_actor_iter_init (&iter, actor);
5551 while (clutter_actor_iter_next (&iter, NULL))
5552 clutter_actor_iter_destroy (&iter);
5554 g_object_thaw_notify (G_OBJECT (actor));
5558 clutter_actor_constructor (GType gtype,
5560 GObjectConstructParam *props)
5562 GObjectClass *gobject_class;
5566 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5567 retval = gobject_class->constructor (gtype, n_props, props);
5568 self = CLUTTER_ACTOR (retval);
5570 if (self->priv->layout_manager == NULL)
5572 ClutterLayoutManager *default_layout;
5574 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5576 default_layout = clutter_fixed_layout_new ();
5577 clutter_actor_set_layout_manager (self, default_layout);
5584 clutter_actor_class_init (ClutterActorClass *klass)
5586 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5588 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5589 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5590 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5591 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5593 object_class->constructor = clutter_actor_constructor;
5594 object_class->set_property = clutter_actor_set_property;
5595 object_class->get_property = clutter_actor_get_property;
5596 object_class->dispose = clutter_actor_dispose;
5597 object_class->finalize = clutter_actor_finalize;
5599 klass->show = clutter_actor_real_show;
5600 klass->show_all = clutter_actor_show;
5601 klass->hide = clutter_actor_real_hide;
5602 klass->hide_all = clutter_actor_hide;
5603 klass->map = clutter_actor_real_map;
5604 klass->unmap = clutter_actor_real_unmap;
5605 klass->unrealize = clutter_actor_real_unrealize;
5606 klass->pick = clutter_actor_real_pick;
5607 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5608 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5609 klass->allocate = clutter_actor_real_allocate;
5610 klass->queue_redraw = clutter_actor_real_queue_redraw;
5611 klass->queue_relayout = clutter_actor_real_queue_relayout;
5612 klass->apply_transform = clutter_actor_real_apply_transform;
5613 klass->get_accessible = clutter_actor_real_get_accessible;
5614 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5615 klass->has_overlaps = clutter_actor_real_has_overlaps;
5616 klass->paint = clutter_actor_real_paint;
5617 klass->destroy = clutter_actor_real_destroy;
5619 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5624 * X coordinate of the actor in pixels. If written, forces a fixed
5625 * position for the actor. If read, returns the fixed position if any,
5626 * otherwise the allocation if available, otherwise 0.
5628 * The #ClutterActor:x property is animatable.
5631 g_param_spec_float ("x",
5633 P_("X coordinate of the actor"),
5634 -G_MAXFLOAT, G_MAXFLOAT,
5637 G_PARAM_STATIC_STRINGS |
5638 CLUTTER_PARAM_ANIMATABLE);
5643 * Y coordinate of the actor in pixels. If written, forces a fixed
5644 * position for the actor. If read, returns the fixed position if
5645 * any, otherwise the allocation if available, otherwise 0.
5647 * The #ClutterActor:y property is animatable.
5650 g_param_spec_float ("y",
5652 P_("Y coordinate of the actor"),
5653 -G_MAXFLOAT, G_MAXFLOAT,
5656 G_PARAM_STATIC_STRINGS |
5657 CLUTTER_PARAM_ANIMATABLE);
5660 * ClutterActor:position:
5662 * The position of the origin of the actor.
5664 * This property is a shorthand for setting and getting the
5665 * #ClutterActor:x and #ClutterActor:y properties at the same
5668 * The #ClutterActor:position property is animatable.
5672 obj_props[PROP_POSITION] =
5673 g_param_spec_boxed ("position",
5675 P_("The position of the origin of the actor"),
5678 G_PARAM_STATIC_STRINGS |
5679 CLUTTER_PARAM_ANIMATABLE);
5682 * ClutterActor:width:
5684 * Width of the actor (in pixels). If written, forces the minimum and
5685 * natural size request of the actor to the given width. If read, returns
5686 * the allocated width if available, otherwise the width request.
5688 * The #ClutterActor:width property is animatable.
5690 obj_props[PROP_WIDTH] =
5691 g_param_spec_float ("width",
5693 P_("Width of the actor"),
5697 G_PARAM_STATIC_STRINGS |
5698 CLUTTER_PARAM_ANIMATABLE);
5701 * ClutterActor:height:
5703 * Height of the actor (in pixels). If written, forces the minimum and
5704 * natural size request of the actor to the given height. If read, returns
5705 * the allocated height if available, otherwise the height request.
5707 * The #ClutterActor:height property is animatable.
5709 obj_props[PROP_HEIGHT] =
5710 g_param_spec_float ("height",
5712 P_("Height of the actor"),
5716 G_PARAM_STATIC_STRINGS |
5717 CLUTTER_PARAM_ANIMATABLE);
5720 * ClutterActor:size:
5722 * The size of the actor.
5724 * This property is a shorthand for setting and getting the
5725 * #ClutterActor:width and #ClutterActor:height at the same time.
5727 * The #ClutterActor:size property is animatable.
5731 obj_props[PROP_SIZE] =
5732 g_param_spec_boxed ("size",
5734 P_("The size of the actor"),
5737 G_PARAM_STATIC_STRINGS |
5738 CLUTTER_PARAM_ANIMATABLE);
5741 * ClutterActor:fixed-x:
5743 * The fixed X position of the actor in pixels.
5745 * Writing this property sets #ClutterActor:fixed-position-set
5746 * property as well, as a side effect
5750 obj_props[PROP_FIXED_X] =
5751 g_param_spec_float ("fixed-x",
5753 P_("Forced X position of the actor"),
5754 -G_MAXFLOAT, G_MAXFLOAT,
5756 CLUTTER_PARAM_READWRITE);
5759 * ClutterActor:fixed-y:
5761 * The fixed Y position of the actor in pixels.
5763 * Writing this property sets the #ClutterActor:fixed-position-set
5764 * property as well, as a side effect
5768 obj_props[PROP_FIXED_Y] =
5769 g_param_spec_float ("fixed-y",
5771 P_("Forced Y position of the actor"),
5772 -G_MAXFLOAT, G_MAXFLOAT,
5774 CLUTTER_PARAM_READWRITE);
5777 * ClutterActor:fixed-position-set:
5779 * This flag controls whether the #ClutterActor:fixed-x and
5780 * #ClutterActor:fixed-y properties are used
5784 obj_props[PROP_FIXED_POSITION_SET] =
5785 g_param_spec_boolean ("fixed-position-set",
5786 P_("Fixed position set"),
5787 P_("Whether to use fixed positioning for the actor"),
5789 CLUTTER_PARAM_READWRITE);
5792 * ClutterActor:min-width:
5794 * A forced minimum width request for the actor, in pixels
5796 * Writing this property sets the #ClutterActor:min-width-set property
5797 * as well, as a side effect.
5799 *This property overrides the usual width request of the actor.
5803 obj_props[PROP_MIN_WIDTH] =
5804 g_param_spec_float ("min-width",
5806 P_("Forced minimum width request for the actor"),
5809 CLUTTER_PARAM_READWRITE);
5812 * ClutterActor:min-height:
5814 * A forced minimum height request for the actor, in pixels
5816 * Writing this property sets the #ClutterActor:min-height-set property
5817 * as well, as a side effect. This property overrides the usual height
5818 * request of the actor.
5822 obj_props[PROP_MIN_HEIGHT] =
5823 g_param_spec_float ("min-height",
5825 P_("Forced minimum height request for the actor"),
5828 CLUTTER_PARAM_READWRITE);
5831 * ClutterActor:natural-width:
5833 * A forced natural width request for the actor, in pixels
5835 * Writing this property sets the #ClutterActor:natural-width-set
5836 * property as well, as a side effect. This property overrides the
5837 * usual width request of the actor
5841 obj_props[PROP_NATURAL_WIDTH] =
5842 g_param_spec_float ("natural-width",
5843 P_("Natural Width"),
5844 P_("Forced natural width request for the actor"),
5847 CLUTTER_PARAM_READWRITE);
5850 * ClutterActor:natural-height:
5852 * A forced natural height request for the actor, in pixels
5854 * Writing this property sets the #ClutterActor:natural-height-set
5855 * property as well, as a side effect. This property overrides the
5856 * usual height request of the actor
5860 obj_props[PROP_NATURAL_HEIGHT] =
5861 g_param_spec_float ("natural-height",
5862 P_("Natural Height"),
5863 P_("Forced natural height request for the actor"),
5866 CLUTTER_PARAM_READWRITE);
5869 * ClutterActor:min-width-set:
5871 * This flag controls whether the #ClutterActor:min-width property
5876 obj_props[PROP_MIN_WIDTH_SET] =
5877 g_param_spec_boolean ("min-width-set",
5878 P_("Minimum width set"),
5879 P_("Whether to use the min-width property"),
5881 CLUTTER_PARAM_READWRITE);
5884 * ClutterActor:min-height-set:
5886 * This flag controls whether the #ClutterActor:min-height property
5891 obj_props[PROP_MIN_HEIGHT_SET] =
5892 g_param_spec_boolean ("min-height-set",
5893 P_("Minimum height set"),
5894 P_("Whether to use the min-height property"),
5896 CLUTTER_PARAM_READWRITE);
5899 * ClutterActor:natural-width-set:
5901 * This flag controls whether the #ClutterActor:natural-width property
5906 obj_props[PROP_NATURAL_WIDTH_SET] =
5907 g_param_spec_boolean ("natural-width-set",
5908 P_("Natural width set"),
5909 P_("Whether to use the natural-width property"),
5911 CLUTTER_PARAM_READWRITE);
5914 * ClutterActor:natural-height-set:
5916 * This flag controls whether the #ClutterActor:natural-height property
5921 obj_props[PROP_NATURAL_HEIGHT_SET] =
5922 g_param_spec_boolean ("natural-height-set",
5923 P_("Natural height set"),
5924 P_("Whether to use the natural-height property"),
5926 CLUTTER_PARAM_READWRITE);
5929 * ClutterActor:allocation:
5931 * The allocation for the actor, in pixels
5933 * This is property is read-only, but you might monitor it to know when an
5934 * actor moves or resizes
5938 obj_props[PROP_ALLOCATION] =
5939 g_param_spec_boxed ("allocation",
5941 P_("The actor's allocation"),
5942 CLUTTER_TYPE_ACTOR_BOX,
5944 G_PARAM_STATIC_STRINGS |
5945 CLUTTER_PARAM_ANIMATABLE);
5948 * ClutterActor:request-mode:
5950 * Request mode for the #ClutterActor. The request mode determines the
5951 * type of geometry management used by the actor, either height for width
5952 * (the default) or width for height.
5954 * For actors implementing height for width, the parent container should get
5955 * the preferred width first, and then the preferred height for that width.
5957 * For actors implementing width for height, the parent container should get
5958 * the preferred height first, and then the preferred width for that height.
5963 * ClutterRequestMode mode;
5964 * gfloat natural_width, min_width;
5965 * gfloat natural_height, min_height;
5967 * mode = clutter_actor_get_request_mode (child);
5968 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5970 * clutter_actor_get_preferred_width (child, -1,
5972 * &natural_width);
5973 * clutter_actor_get_preferred_height (child, natural_width,
5975 * &natural_height);
5979 * clutter_actor_get_preferred_height (child, -1,
5981 * &natural_height);
5982 * clutter_actor_get_preferred_width (child, natural_height,
5984 * &natural_width);
5988 * will retrieve the minimum and natural width and height depending on the
5989 * preferred request mode of the #ClutterActor "child".
5991 * The clutter_actor_get_preferred_size() function will implement this
5996 obj_props[PROP_REQUEST_MODE] =
5997 g_param_spec_enum ("request-mode",
5999 P_("The actor's request mode"),
6000 CLUTTER_TYPE_REQUEST_MODE,
6001 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
6002 CLUTTER_PARAM_READWRITE);
6005 * ClutterActor:depth:
6007 * The position of the actor on the Z axis.
6009 * The #ClutterActor:depth property is relative to the parent's
6012 * The #ClutterActor:depth property is animatable.
6016 obj_props[PROP_DEPTH] =
6017 g_param_spec_float ("depth",
6019 P_("Position on the Z axis"),
6020 -G_MAXFLOAT, G_MAXFLOAT,
6023 G_PARAM_STATIC_STRINGS |
6024 CLUTTER_PARAM_ANIMATABLE);
6027 * ClutterActor:opacity:
6029 * Opacity of an actor, between 0 (fully transparent) and
6030 * 255 (fully opaque)
6032 * The #ClutterActor:opacity property is animatable.
6034 obj_props[PROP_OPACITY] =
6035 g_param_spec_uint ("opacity",
6037 P_("Opacity of an actor"),
6041 G_PARAM_STATIC_STRINGS |
6042 CLUTTER_PARAM_ANIMATABLE);
6045 * ClutterActor:offscreen-redirect:
6047 * Determines the conditions in which the actor will be redirected
6048 * to an offscreen framebuffer while being painted. For example this
6049 * can be used to cache an actor in a framebuffer or for improved
6050 * handling of transparent actors. See
6051 * clutter_actor_set_offscreen_redirect() for details.
6055 obj_props[PROP_OFFSCREEN_REDIRECT] =
6056 g_param_spec_flags ("offscreen-redirect",
6057 P_("Offscreen redirect"),
6058 P_("Flags controlling when to flatten the actor into a single image"),
6059 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
6061 CLUTTER_PARAM_READWRITE);
6064 * ClutterActor:visible:
6066 * Whether the actor is set to be visible or not
6068 * See also #ClutterActor:mapped
6070 obj_props[PROP_VISIBLE] =
6071 g_param_spec_boolean ("visible",
6073 P_("Whether the actor is visible or not"),
6075 CLUTTER_PARAM_READWRITE);
6078 * ClutterActor:mapped:
6080 * Whether the actor is mapped (will be painted when the stage
6081 * to which it belongs is mapped)
6085 obj_props[PROP_MAPPED] =
6086 g_param_spec_boolean ("mapped",
6088 P_("Whether the actor will be painted"),
6090 CLUTTER_PARAM_READABLE);
6093 * ClutterActor:realized:
6095 * Whether the actor has been realized
6099 obj_props[PROP_REALIZED] =
6100 g_param_spec_boolean ("realized",
6102 P_("Whether the actor has been realized"),
6104 CLUTTER_PARAM_READABLE);
6107 * ClutterActor:reactive:
6109 * Whether the actor is reactive to events or not
6111 * Only reactive actors will emit event-related signals
6115 obj_props[PROP_REACTIVE] =
6116 g_param_spec_boolean ("reactive",
6118 P_("Whether the actor is reactive to events"),
6120 CLUTTER_PARAM_READWRITE);
6123 * ClutterActor:has-clip:
6125 * Whether the actor has the #ClutterActor:clip property set or not
6127 obj_props[PROP_HAS_CLIP] =
6128 g_param_spec_boolean ("has-clip",
6130 P_("Whether the actor has a clip set"),
6132 CLUTTER_PARAM_READABLE);
6135 * ClutterActor:clip:
6137 * The clip region for the actor, in actor-relative coordinates
6139 * Every part of the actor outside the clip region will not be
6142 obj_props[PROP_CLIP] =
6143 g_param_spec_boxed ("clip",
6145 P_("The clip region for the actor"),
6146 CLUTTER_TYPE_GEOMETRY,
6147 CLUTTER_PARAM_READWRITE);
6150 * ClutterActor:name:
6152 * The name of the actor
6156 obj_props[PROP_NAME] =
6157 g_param_spec_string ("name",
6159 P_("Name of the actor"),
6161 CLUTTER_PARAM_READWRITE);
6164 * ClutterActor:scale-x:
6166 * The horizontal scale of the actor.
6168 * The #ClutterActor:scale-x property is animatable.
6172 obj_props[PROP_SCALE_X] =
6173 g_param_spec_double ("scale-x",
6175 P_("Scale factor on the X axis"),
6179 G_PARAM_STATIC_STRINGS |
6180 CLUTTER_PARAM_ANIMATABLE);
6183 * ClutterActor:scale-y:
6185 * The vertical scale of the actor.
6187 * The #ClutterActor:scale-y property is animatable.
6191 obj_props[PROP_SCALE_Y] =
6192 g_param_spec_double ("scale-y",
6194 P_("Scale factor on the Y axis"),
6198 G_PARAM_STATIC_STRINGS |
6199 CLUTTER_PARAM_ANIMATABLE);
6202 * ClutterActor:scale-center-x:
6204 * The horizontal center point for scaling
6208 obj_props[PROP_SCALE_CENTER_X] =
6209 g_param_spec_float ("scale-center-x",
6210 P_("Scale Center X"),
6211 P_("Horizontal scale center"),
6212 -G_MAXFLOAT, G_MAXFLOAT,
6214 CLUTTER_PARAM_READWRITE);
6217 * ClutterActor:scale-center-y:
6219 * The vertical center point for scaling
6223 obj_props[PROP_SCALE_CENTER_Y] =
6224 g_param_spec_float ("scale-center-y",
6225 P_("Scale Center Y"),
6226 P_("Vertical scale center"),
6227 -G_MAXFLOAT, G_MAXFLOAT,
6229 CLUTTER_PARAM_READWRITE);
6232 * ClutterActor:scale-gravity:
6234 * The center point for scaling expressed as a #ClutterGravity
6238 obj_props[PROP_SCALE_GRAVITY] =
6239 g_param_spec_enum ("scale-gravity",
6240 P_("Scale Gravity"),
6241 P_("The center of scaling"),
6242 CLUTTER_TYPE_GRAVITY,
6243 CLUTTER_GRAVITY_NONE,
6244 CLUTTER_PARAM_READWRITE);
6247 * ClutterActor:rotation-angle-x:
6249 * The rotation angle on the X axis.
6251 * The #ClutterActor:rotation-angle-x property is animatable.
6255 obj_props[PROP_ROTATION_ANGLE_X] =
6256 g_param_spec_double ("rotation-angle-x",
6257 P_("Rotation Angle X"),
6258 P_("The rotation angle on the X axis"),
6259 -G_MAXDOUBLE, G_MAXDOUBLE,
6262 G_PARAM_STATIC_STRINGS |
6263 CLUTTER_PARAM_ANIMATABLE);
6266 * ClutterActor:rotation-angle-y:
6268 * The rotation angle on the Y axis
6270 * The #ClutterActor:rotation-angle-y property is animatable.
6274 obj_props[PROP_ROTATION_ANGLE_Y] =
6275 g_param_spec_double ("rotation-angle-y",
6276 P_("Rotation Angle Y"),
6277 P_("The rotation angle on the Y axis"),
6278 -G_MAXDOUBLE, G_MAXDOUBLE,
6281 G_PARAM_STATIC_STRINGS |
6282 CLUTTER_PARAM_ANIMATABLE);
6285 * ClutterActor:rotation-angle-z:
6287 * The rotation angle on the Z axis
6289 * The #ClutterActor:rotation-angle-z property is animatable.
6293 obj_props[PROP_ROTATION_ANGLE_Z] =
6294 g_param_spec_double ("rotation-angle-z",
6295 P_("Rotation Angle Z"),
6296 P_("The rotation angle on the Z axis"),
6297 -G_MAXDOUBLE, G_MAXDOUBLE,
6300 G_PARAM_STATIC_STRINGS |
6301 CLUTTER_PARAM_ANIMATABLE);
6304 * ClutterActor:rotation-center-x:
6306 * The rotation center on the X axis.
6310 obj_props[PROP_ROTATION_CENTER_X] =
6311 g_param_spec_boxed ("rotation-center-x",
6312 P_("Rotation Center X"),
6313 P_("The rotation center on the X axis"),
6314 CLUTTER_TYPE_VERTEX,
6315 CLUTTER_PARAM_READWRITE);
6318 * ClutterActor:rotation-center-y:
6320 * The rotation center on the Y axis.
6324 obj_props[PROP_ROTATION_CENTER_Y] =
6325 g_param_spec_boxed ("rotation-center-y",
6326 P_("Rotation Center Y"),
6327 P_("The rotation center on the Y axis"),
6328 CLUTTER_TYPE_VERTEX,
6329 CLUTTER_PARAM_READWRITE);
6332 * ClutterActor:rotation-center-z:
6334 * The rotation center on the Z axis.
6338 obj_props[PROP_ROTATION_CENTER_Z] =
6339 g_param_spec_boxed ("rotation-center-z",
6340 P_("Rotation Center Z"),
6341 P_("The rotation center on the Z axis"),
6342 CLUTTER_TYPE_VERTEX,
6343 CLUTTER_PARAM_READWRITE);
6346 * ClutterActor:rotation-center-z-gravity:
6348 * The rotation center on the Z axis expressed as a #ClutterGravity.
6352 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6353 g_param_spec_enum ("rotation-center-z-gravity",
6354 P_("Rotation Center Z Gravity"),
6355 P_("Center point for rotation around the Z axis"),
6356 CLUTTER_TYPE_GRAVITY,
6357 CLUTTER_GRAVITY_NONE,
6358 CLUTTER_PARAM_READWRITE);
6361 * ClutterActor:anchor-x:
6363 * The X coordinate of an actor's anchor point, relative to
6364 * the actor coordinate space, in pixels
6368 obj_props[PROP_ANCHOR_X] =
6369 g_param_spec_float ("anchor-x",
6371 P_("X coordinate of the anchor point"),
6372 -G_MAXFLOAT, G_MAXFLOAT,
6374 CLUTTER_PARAM_READWRITE);
6377 * ClutterActor:anchor-y:
6379 * The Y coordinate of an actor's anchor point, relative to
6380 * the actor coordinate space, in pixels
6384 obj_props[PROP_ANCHOR_Y] =
6385 g_param_spec_float ("anchor-y",
6387 P_("Y coordinate of the anchor point"),
6388 -G_MAXFLOAT, G_MAXFLOAT,
6390 CLUTTER_PARAM_READWRITE);
6393 * ClutterActor:anchor-gravity:
6395 * The anchor point expressed as a #ClutterGravity
6399 obj_props[PROP_ANCHOR_GRAVITY] =
6400 g_param_spec_enum ("anchor-gravity",
6401 P_("Anchor Gravity"),
6402 P_("The anchor point as a ClutterGravity"),
6403 CLUTTER_TYPE_GRAVITY,
6404 CLUTTER_GRAVITY_NONE,
6405 CLUTTER_PARAM_READWRITE);
6408 * ClutterActor:show-on-set-parent:
6410 * If %TRUE, the actor is automatically shown when parented.
6412 * Calling clutter_actor_hide() on an actor which has not been
6413 * parented will set this property to %FALSE as a side effect.
6417 obj_props[PROP_SHOW_ON_SET_PARENT] =
6418 g_param_spec_boolean ("show-on-set-parent",
6419 P_("Show on set parent"),
6420 P_("Whether the actor is shown when parented"),
6422 CLUTTER_PARAM_READWRITE);
6425 * ClutterActor:clip-to-allocation:
6427 * Whether the clip region should track the allocated area
6430 * This property is ignored if a clip area has been explicitly
6431 * set using clutter_actor_set_clip().
6435 obj_props[PROP_CLIP_TO_ALLOCATION] =
6436 g_param_spec_boolean ("clip-to-allocation",
6437 P_("Clip to Allocation"),
6438 P_("Sets the clip region to track the actor's allocation"),
6440 CLUTTER_PARAM_READWRITE);
6443 * ClutterActor:text-direction:
6445 * The direction of the text inside a #ClutterActor.
6449 obj_props[PROP_TEXT_DIRECTION] =
6450 g_param_spec_enum ("text-direction",
6451 P_("Text Direction"),
6452 P_("Direction of the text"),
6453 CLUTTER_TYPE_TEXT_DIRECTION,
6454 CLUTTER_TEXT_DIRECTION_LTR,
6455 CLUTTER_PARAM_READWRITE);
6458 * ClutterActor:has-pointer:
6460 * Whether the actor contains the pointer of a #ClutterInputDevice
6465 obj_props[PROP_HAS_POINTER] =
6466 g_param_spec_boolean ("has-pointer",
6468 P_("Whether the actor contains the pointer of an input device"),
6470 CLUTTER_PARAM_READABLE);
6473 * ClutterActor:actions:
6475 * Adds a #ClutterAction to the actor
6479 obj_props[PROP_ACTIONS] =
6480 g_param_spec_object ("actions",
6482 P_("Adds an action to the actor"),
6483 CLUTTER_TYPE_ACTION,
6484 CLUTTER_PARAM_WRITABLE);
6487 * ClutterActor:constraints:
6489 * Adds a #ClutterConstraint to the actor
6493 obj_props[PROP_CONSTRAINTS] =
6494 g_param_spec_object ("constraints",
6496 P_("Adds a constraint to the actor"),
6497 CLUTTER_TYPE_CONSTRAINT,
6498 CLUTTER_PARAM_WRITABLE);
6501 * ClutterActor:effect:
6503 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6507 obj_props[PROP_EFFECT] =
6508 g_param_spec_object ("effect",
6510 P_("Add an effect to be applied on the actor"),
6511 CLUTTER_TYPE_EFFECT,
6512 CLUTTER_PARAM_WRITABLE);
6515 * ClutterActor:layout-manager:
6517 * A delegate object for controlling the layout of the children of
6522 obj_props[PROP_LAYOUT_MANAGER] =
6523 g_param_spec_object ("layout-manager",
6524 P_("Layout Manager"),
6525 P_("The object controlling the layout of an actor's children"),
6526 CLUTTER_TYPE_LAYOUT_MANAGER,
6527 CLUTTER_PARAM_READWRITE);
6530 * ClutterActor:x-expand:
6532 * Whether a layout manager should assign more space to the actor on
6537 obj_props[PROP_X_EXPAND] =
6538 g_param_spec_boolean ("x-expand",
6540 P_("Whether extra horizontal space should be assigned to the actor"),
6543 G_PARAM_STATIC_STRINGS);
6546 * ClutterActor:y-expand:
6548 * Whether a layout manager should assign more space to the actor on
6553 obj_props[PROP_Y_EXPAND] =
6554 g_param_spec_boolean ("y-expand",
6556 P_("Whether extra vertical space should be assigned to the actor"),
6559 G_PARAM_STATIC_STRINGS);
6562 * ClutterActor:x-align:
6564 * The alignment of an actor on the X axis, if the actor has been given
6565 * extra space for its allocation. See also the #ClutterActor:x-expand
6570 obj_props[PROP_X_ALIGN] =
6571 g_param_spec_enum ("x-align",
6573 P_("The alignment of the actor on the X axis within its allocation"),
6574 CLUTTER_TYPE_ACTOR_ALIGN,
6575 CLUTTER_ACTOR_ALIGN_FILL,
6576 CLUTTER_PARAM_READWRITE);
6579 * ClutterActor:y-align:
6581 * The alignment of an actor on the Y axis, if the actor has been given
6582 * extra space for its allocation.
6586 obj_props[PROP_Y_ALIGN] =
6587 g_param_spec_enum ("y-align",
6589 P_("The alignment of the actor on the Y axis within its allocation"),
6590 CLUTTER_TYPE_ACTOR_ALIGN,
6591 CLUTTER_ACTOR_ALIGN_FILL,
6592 CLUTTER_PARAM_READWRITE);
6595 * ClutterActor:margin-top:
6597 * The margin (in pixels) from the top of the actor.
6599 * This property adds a margin to the actor's preferred size; the margin
6600 * will be automatically taken into account when allocating the actor.
6604 obj_props[PROP_MARGIN_TOP] =
6605 g_param_spec_float ("margin-top",
6607 P_("Extra space at the top"),
6610 CLUTTER_PARAM_READWRITE);
6613 * ClutterActor:margin-bottom:
6615 * The margin (in pixels) from the bottom of the actor.
6617 * This property adds a margin to the actor's preferred size; the margin
6618 * will be automatically taken into account when allocating the actor.
6622 obj_props[PROP_MARGIN_BOTTOM] =
6623 g_param_spec_float ("margin-bottom",
6624 P_("Margin Bottom"),
6625 P_("Extra space at the bottom"),
6628 CLUTTER_PARAM_READWRITE);
6631 * ClutterActor:margin-left:
6633 * The margin (in pixels) from the left of the actor.
6635 * This property adds a margin to the actor's preferred size; the margin
6636 * will be automatically taken into account when allocating the actor.
6640 obj_props[PROP_MARGIN_LEFT] =
6641 g_param_spec_float ("margin-left",
6643 P_("Extra space at the left"),
6646 CLUTTER_PARAM_READWRITE);
6649 * ClutterActor:margin-right:
6651 * The margin (in pixels) from the right of the actor.
6653 * This property adds a margin to the actor's preferred size; the margin
6654 * will be automatically taken into account when allocating the actor.
6658 obj_props[PROP_MARGIN_RIGHT] =
6659 g_param_spec_float ("margin-right",
6661 P_("Extra space at the right"),
6664 CLUTTER_PARAM_READWRITE);
6667 * ClutterActor:background-color-set:
6669 * Whether the #ClutterActor:background-color property has been set.
6673 obj_props[PROP_BACKGROUND_COLOR_SET] =
6674 g_param_spec_boolean ("background-color-set",
6675 P_("Background Color Set"),
6676 P_("Whether the background color is set"),
6678 CLUTTER_PARAM_READABLE);
6681 * ClutterActor:background-color:
6683 * Paints a solid fill of the actor's allocation using the specified
6686 * The #ClutterActor:background-color property is animatable.
6690 obj_props[PROP_BACKGROUND_COLOR] =
6691 clutter_param_spec_color ("background-color",
6692 P_("Background color"),
6693 P_("The actor's background color"),
6694 CLUTTER_COLOR_Transparent,
6696 G_PARAM_STATIC_STRINGS |
6697 CLUTTER_PARAM_ANIMATABLE);
6700 * ClutterActor:first-child:
6702 * The actor's first child.
6706 obj_props[PROP_FIRST_CHILD] =
6707 g_param_spec_object ("first-child",
6709 P_("The actor's first child"),
6711 CLUTTER_PARAM_READABLE);
6714 * ClutterActor:last-child:
6716 * The actor's last child.
6720 obj_props[PROP_LAST_CHILD] =
6721 g_param_spec_object ("last-child",
6723 P_("The actor's last child"),
6725 CLUTTER_PARAM_READABLE);
6728 * ClutterActor:content:
6730 * The #ClutterContent implementation that controls the content
6735 obj_props[PROP_CONTENT] =
6736 g_param_spec_object ("content",
6738 P_("Delegate object for painting the actor's content"),
6739 CLUTTER_TYPE_CONTENT,
6740 CLUTTER_PARAM_READWRITE);
6743 * ClutterActor:content-gravity:
6745 * The alignment that should be honoured by the #ClutterContent
6746 * set with the #ClutterActor:content property.
6748 * Changing the value of this property will change the bounding box of
6749 * the content; you can use the #ClutterActor:content-box property to
6750 * get the position and size of the content within the actor's
6753 * This property is meaningful only for #ClutterContent implementations
6754 * that have a preferred size, and if the preferred size is smaller than
6755 * the actor's allocation.
6757 * The #ClutterActor:content-gravity property is animatable.
6761 obj_props[PROP_CONTENT_GRAVITY] =
6762 g_param_spec_enum ("content-gravity",
6763 P_("Content Gravity"),
6764 P_("Alignment of the actor's content"),
6765 CLUTTER_TYPE_CONTENT_GRAVITY,
6766 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6767 CLUTTER_PARAM_READWRITE);
6770 * ClutterActor:content-box:
6772 * The bounding box for the #ClutterContent used by the actor.
6774 * The value of this property is controlled by the #ClutterActor:allocation
6775 * and #ClutterActor:content-gravity properties of #ClutterActor.
6777 * The bounding box for the content is guaranteed to never exceed the
6778 * allocation's of the actor.
6782 obj_props[PROP_CONTENT_BOX] =
6783 g_param_spec_boxed ("content-box",
6785 P_("The bounding box of the actor's content"),
6786 CLUTTER_TYPE_ACTOR_BOX,
6788 G_PARAM_STATIC_STRINGS |
6789 CLUTTER_PARAM_ANIMATABLE);
6791 obj_props[PROP_MINIFICATION_FILTER] =
6792 g_param_spec_enum ("minification-filter",
6793 P_("Minification Filter"),
6794 P_("The filter used when reducing the size of the content"),
6795 CLUTTER_TYPE_SCALING_FILTER,
6796 CLUTTER_SCALING_FILTER_LINEAR,
6797 CLUTTER_PARAM_READWRITE);
6799 obj_props[PROP_MAGNIFICATION_FILTER] =
6800 g_param_spec_enum ("magnification-filter",
6801 P_("Magnification Filter"),
6802 P_("The filter used when increasing the size of the content"),
6803 CLUTTER_TYPE_SCALING_FILTER,
6804 CLUTTER_SCALING_FILTER_LINEAR,
6805 CLUTTER_PARAM_READWRITE);
6808 * ClutterActor:content-repeat:
6810 * The repeat policy for the actor's #ClutterActor:content.
6814 obj_props[PROP_CONTENT_REPEAT] =
6815 g_param_spec_flags ("content-repeat",
6816 P_("Content Repeat"),
6817 P_("The repeat policy for the actor's content"),
6818 CLUTTER_TYPE_CONTENT_REPEAT,
6819 CLUTTER_REPEAT_NONE,
6821 G_PARAM_STATIC_STRINGS);
6823 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6826 * ClutterActor::destroy:
6827 * @actor: the #ClutterActor which emitted the signal
6829 * The ::destroy signal notifies that all references held on the
6830 * actor which emitted it should be released.
6832 * The ::destroy signal should be used by all holders of a reference
6835 * This signal might result in the finalization of the #ClutterActor
6836 * if all references are released.
6838 * Composite actors and actors implementing the #ClutterContainer
6839 * interface should override the default implementation of the
6840 * class handler of this signal and call clutter_actor_destroy() on
6841 * their children. When overriding the default class handler, it is
6842 * required to chain up to the parent's implementation.
6846 actor_signals[DESTROY] =
6847 g_signal_new (I_("destroy"),
6848 G_TYPE_FROM_CLASS (object_class),
6849 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6850 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6852 _clutter_marshal_VOID__VOID,
6855 * ClutterActor::show:
6856 * @actor: the object which received the signal
6858 * The ::show signal is emitted when an actor is visible and
6859 * rendered on the stage.
6863 actor_signals[SHOW] =
6864 g_signal_new (I_("show"),
6865 G_TYPE_FROM_CLASS (object_class),
6867 G_STRUCT_OFFSET (ClutterActorClass, show),
6869 _clutter_marshal_VOID__VOID,
6872 * ClutterActor::hide:
6873 * @actor: the object which received the signal
6875 * The ::hide signal is emitted when an actor is no longer rendered
6880 actor_signals[HIDE] =
6881 g_signal_new (I_("hide"),
6882 G_TYPE_FROM_CLASS (object_class),
6884 G_STRUCT_OFFSET (ClutterActorClass, hide),
6886 _clutter_marshal_VOID__VOID,
6889 * ClutterActor::parent-set:
6890 * @actor: the object which received the signal
6891 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6893 * This signal is emitted when the parent of the actor changes.
6897 actor_signals[PARENT_SET] =
6898 g_signal_new (I_("parent-set"),
6899 G_TYPE_FROM_CLASS (object_class),
6901 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6903 _clutter_marshal_VOID__OBJECT,
6905 CLUTTER_TYPE_ACTOR);
6908 * ClutterActor::queue-redraw:
6909 * @actor: the actor we're bubbling the redraw request through
6910 * @origin: the actor which initiated the redraw request
6912 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6913 * is called on @origin.
6915 * The default implementation for #ClutterActor chains up to the
6916 * parent actor and queues a redraw on the parent, thus "bubbling"
6917 * the redraw queue up through the actor graph. The default
6918 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6919 * in a main loop idle handler.
6921 * Note that the @origin actor may be the stage, or a container; it
6922 * does not have to be a leaf node in the actor graph.
6924 * Toolkits embedding a #ClutterStage which require a redraw and
6925 * relayout cycle can stop the emission of this signal using the
6926 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6931 * on_redraw_complete (gpointer data)
6933 * ClutterStage *stage = data;
6935 * /* execute the Clutter drawing pipeline */
6936 * clutter_stage_ensure_redraw (stage);
6940 * on_stage_queue_redraw (ClutterStage *stage)
6942 * /* this prevents the default handler to run */
6943 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6945 * /* queue a redraw with the host toolkit and call
6946 * * a function when the redraw has been completed
6948 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6952 * <note><para>This signal is emitted before the Clutter paint
6953 * pipeline is executed. If you want to know when the pipeline has
6954 * been completed you should connect to the ::paint signal on the
6955 * Stage with g_signal_connect_after().</para></note>
6959 actor_signals[QUEUE_REDRAW] =
6960 g_signal_new (I_("queue-redraw"),
6961 G_TYPE_FROM_CLASS (object_class),
6964 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6966 _clutter_marshal_VOID__OBJECT,
6968 CLUTTER_TYPE_ACTOR);
6971 * ClutterActor::queue-relayout:
6972 * @actor: the actor being queued for relayout
6974 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6975 * is called on an actor.
6977 * The default implementation for #ClutterActor chains up to the
6978 * parent actor and queues a relayout on the parent, thus "bubbling"
6979 * the relayout queue up through the actor graph.
6981 * The main purpose of this signal is to allow relayout to be propagated
6982 * properly in the procense of #ClutterClone actors. Applications will
6983 * not normally need to connect to this signal.
6987 actor_signals[QUEUE_RELAYOUT] =
6988 g_signal_new (I_("queue-relayout"),
6989 G_TYPE_FROM_CLASS (object_class),
6992 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6994 _clutter_marshal_VOID__VOID,
6998 * ClutterActor::event:
6999 * @actor: the actor which received the event
7000 * @event: a #ClutterEvent
7002 * The ::event signal is emitted each time an event is received
7003 * by the @actor. This signal will be emitted on every actor,
7004 * following the hierarchy chain, until it reaches the top-level
7005 * container (the #ClutterStage).
7007 * Return value: %TRUE if the event has been handled by the actor,
7008 * or %FALSE to continue the emission.
7012 actor_signals[EVENT] =
7013 g_signal_new (I_("event"),
7014 G_TYPE_FROM_CLASS (object_class),
7016 G_STRUCT_OFFSET (ClutterActorClass, event),
7017 _clutter_boolean_handled_accumulator, NULL,
7018 _clutter_marshal_BOOLEAN__BOXED,
7020 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7022 * ClutterActor::button-press-event:
7023 * @actor: the actor which received the event
7024 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
7026 * The ::button-press-event signal is emitted each time a mouse button
7027 * is pressed on @actor.
7029 * Return value: %TRUE if the event has been handled by the actor,
7030 * or %FALSE to continue the emission.
7034 actor_signals[BUTTON_PRESS_EVENT] =
7035 g_signal_new (I_("button-press-event"),
7036 G_TYPE_FROM_CLASS (object_class),
7038 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
7039 _clutter_boolean_handled_accumulator, NULL,
7040 _clutter_marshal_BOOLEAN__BOXED,
7042 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7044 * ClutterActor::button-release-event:
7045 * @actor: the actor which received the event
7046 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
7048 * The ::button-release-event signal is emitted each time a mouse button
7049 * is released on @actor.
7051 * Return value: %TRUE if the event has been handled by the actor,
7052 * or %FALSE to continue the emission.
7056 actor_signals[BUTTON_RELEASE_EVENT] =
7057 g_signal_new (I_("button-release-event"),
7058 G_TYPE_FROM_CLASS (object_class),
7060 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
7061 _clutter_boolean_handled_accumulator, NULL,
7062 _clutter_marshal_BOOLEAN__BOXED,
7064 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7066 * ClutterActor::scroll-event:
7067 * @actor: the actor which received the event
7068 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
7070 * The ::scroll-event signal is emitted each time the mouse is
7071 * scrolled on @actor
7073 * Return value: %TRUE if the event has been handled by the actor,
7074 * or %FALSE to continue the emission.
7078 actor_signals[SCROLL_EVENT] =
7079 g_signal_new (I_("scroll-event"),
7080 G_TYPE_FROM_CLASS (object_class),
7082 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
7083 _clutter_boolean_handled_accumulator, NULL,
7084 _clutter_marshal_BOOLEAN__BOXED,
7086 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7088 * ClutterActor::key-press-event:
7089 * @actor: the actor which received the event
7090 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7092 * The ::key-press-event signal is emitted each time a keyboard button
7093 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
7095 * Return value: %TRUE if the event has been handled by the actor,
7096 * or %FALSE to continue the emission.
7100 actor_signals[KEY_PRESS_EVENT] =
7101 g_signal_new (I_("key-press-event"),
7102 G_TYPE_FROM_CLASS (object_class),
7104 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
7105 _clutter_boolean_handled_accumulator, NULL,
7106 _clutter_marshal_BOOLEAN__BOXED,
7108 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7110 * ClutterActor::key-release-event:
7111 * @actor: the actor which received the event
7112 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7114 * The ::key-release-event signal is emitted each time a keyboard button
7115 * is released while @actor has key focus (see
7116 * clutter_stage_set_key_focus()).
7118 * Return value: %TRUE if the event has been handled by the actor,
7119 * or %FALSE to continue the emission.
7123 actor_signals[KEY_RELEASE_EVENT] =
7124 g_signal_new (I_("key-release-event"),
7125 G_TYPE_FROM_CLASS (object_class),
7127 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
7128 _clutter_boolean_handled_accumulator, NULL,
7129 _clutter_marshal_BOOLEAN__BOXED,
7131 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7133 * ClutterActor::motion-event:
7134 * @actor: the actor which received the event
7135 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
7137 * The ::motion-event signal is emitted each time the mouse pointer is
7138 * moved over @actor.
7140 * Return value: %TRUE if the event has been handled by the actor,
7141 * or %FALSE to continue the emission.
7145 actor_signals[MOTION_EVENT] =
7146 g_signal_new (I_("motion-event"),
7147 G_TYPE_FROM_CLASS (object_class),
7149 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
7150 _clutter_boolean_handled_accumulator, NULL,
7151 _clutter_marshal_BOOLEAN__BOXED,
7153 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7156 * ClutterActor::key-focus-in:
7157 * @actor: the actor which now has key focus
7159 * The ::key-focus-in signal is emitted when @actor receives key focus.
7163 actor_signals[KEY_FOCUS_IN] =
7164 g_signal_new (I_("key-focus-in"),
7165 G_TYPE_FROM_CLASS (object_class),
7167 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
7169 _clutter_marshal_VOID__VOID,
7173 * ClutterActor::key-focus-out:
7174 * @actor: the actor which now has key focus
7176 * The ::key-focus-out signal is emitted when @actor loses key focus.
7180 actor_signals[KEY_FOCUS_OUT] =
7181 g_signal_new (I_("key-focus-out"),
7182 G_TYPE_FROM_CLASS (object_class),
7184 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
7186 _clutter_marshal_VOID__VOID,
7190 * ClutterActor::enter-event:
7191 * @actor: the actor which the pointer has entered.
7192 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7194 * The ::enter-event signal is emitted when the pointer enters the @actor
7196 * Return value: %TRUE if the event has been handled by the actor,
7197 * or %FALSE to continue the emission.
7201 actor_signals[ENTER_EVENT] =
7202 g_signal_new (I_("enter-event"),
7203 G_TYPE_FROM_CLASS (object_class),
7205 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
7206 _clutter_boolean_handled_accumulator, NULL,
7207 _clutter_marshal_BOOLEAN__BOXED,
7209 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7212 * ClutterActor::leave-event:
7213 * @actor: the actor which the pointer has left
7214 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7216 * The ::leave-event signal is emitted when the pointer leaves the @actor.
7218 * Return value: %TRUE if the event has been handled by the actor,
7219 * or %FALSE to continue the emission.
7223 actor_signals[LEAVE_EVENT] =
7224 g_signal_new (I_("leave-event"),
7225 G_TYPE_FROM_CLASS (object_class),
7227 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7228 _clutter_boolean_handled_accumulator, NULL,
7229 _clutter_marshal_BOOLEAN__BOXED,
7231 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7234 * ClutterActor::captured-event:
7235 * @actor: the actor which received the signal
7236 * @event: a #ClutterEvent
7238 * The ::captured-event signal is emitted when an event is captured
7239 * by Clutter. This signal will be emitted starting from the top-level
7240 * container (the #ClutterStage) to the actor which received the event
7241 * going down the hierarchy. This signal can be used to intercept every
7242 * event before the specialized events (like
7243 * ClutterActor::button-press-event or ::key-released-event) are
7246 * Return value: %TRUE if the event has been handled by the actor,
7247 * or %FALSE to continue the emission.
7251 actor_signals[CAPTURED_EVENT] =
7252 g_signal_new (I_("captured-event"),
7253 G_TYPE_FROM_CLASS (object_class),
7255 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7256 _clutter_boolean_handled_accumulator, NULL,
7257 _clutter_marshal_BOOLEAN__BOXED,
7259 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7262 * ClutterActor::paint:
7263 * @actor: the #ClutterActor that received the signal
7265 * The ::paint signal is emitted each time an actor is being painted.
7267 * Subclasses of #ClutterActor should override the class signal handler
7268 * and paint themselves in that function.
7270 * It is possible to connect a handler to the ::paint signal in order
7271 * to set up some custom aspect of a paint.
7275 actor_signals[PAINT] =
7276 g_signal_new (I_("paint"),
7277 G_TYPE_FROM_CLASS (object_class),
7280 G_STRUCT_OFFSET (ClutterActorClass, paint),
7282 _clutter_marshal_VOID__VOID,
7285 * ClutterActor::realize:
7286 * @actor: the #ClutterActor that received the signal
7288 * The ::realize signal is emitted each time an actor is being
7293 actor_signals[REALIZE] =
7294 g_signal_new (I_("realize"),
7295 G_TYPE_FROM_CLASS (object_class),
7297 G_STRUCT_OFFSET (ClutterActorClass, realize),
7299 _clutter_marshal_VOID__VOID,
7302 * ClutterActor::unrealize:
7303 * @actor: the #ClutterActor that received the signal
7305 * The ::unrealize signal is emitted each time an actor is being
7310 actor_signals[UNREALIZE] =
7311 g_signal_new (I_("unrealize"),
7312 G_TYPE_FROM_CLASS (object_class),
7314 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7316 _clutter_marshal_VOID__VOID,
7320 * ClutterActor::pick:
7321 * @actor: the #ClutterActor that received the signal
7322 * @color: the #ClutterColor to be used when picking
7324 * The ::pick signal is emitted each time an actor is being painted
7325 * in "pick mode". The pick mode is used to identify the actor during
7326 * the event handling phase, or by clutter_stage_get_actor_at_pos().
7327 * The actor should paint its shape using the passed @pick_color.
7329 * Subclasses of #ClutterActor should override the class signal handler
7330 * and paint themselves in that function.
7332 * It is possible to connect a handler to the ::pick signal in order
7333 * to set up some custom aspect of a paint in pick mode.
7337 actor_signals[PICK] =
7338 g_signal_new (I_("pick"),
7339 G_TYPE_FROM_CLASS (object_class),
7341 G_STRUCT_OFFSET (ClutterActorClass, pick),
7343 _clutter_marshal_VOID__BOXED,
7345 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7348 * ClutterActor::allocation-changed:
7349 * @actor: the #ClutterActor that emitted the signal
7350 * @box: a #ClutterActorBox with the new allocation
7351 * @flags: #ClutterAllocationFlags for the allocation
7353 * The ::allocation-changed signal is emitted when the
7354 * #ClutterActor:allocation property changes. Usually, application
7355 * code should just use the notifications for the :allocation property
7356 * but if you want to track the allocation flags as well, for instance
7357 * to know whether the absolute origin of @actor changed, then you might
7358 * want use this signal instead.
7362 actor_signals[ALLOCATION_CHANGED] =
7363 g_signal_new (I_("allocation-changed"),
7364 G_TYPE_FROM_CLASS (object_class),
7368 _clutter_marshal_VOID__BOXED_FLAGS,
7370 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7371 CLUTTER_TYPE_ALLOCATION_FLAGS);
7374 * ClutterActor::transitions-completed:
7375 * @actor: a #ClutterActor
7377 * The ::transitions-completed signal is emitted once all transitions
7378 * involving @actor are complete.
7382 actor_signals[TRANSITIONS_COMPLETED] =
7383 g_signal_new (I_("transitions-completed"),
7384 G_TYPE_FROM_CLASS (object_class),
7388 _clutter_marshal_VOID__VOID,
7393 clutter_actor_init (ClutterActor *self)
7395 ClutterActorPrivate *priv;
7397 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7399 priv->id = _clutter_context_acquire_id (self);
7402 priv->opacity = 0xff;
7403 priv->show_on_set_parent = TRUE;
7405 priv->needs_width_request = TRUE;
7406 priv->needs_height_request = TRUE;
7407 priv->needs_allocation = TRUE;
7409 priv->cached_width_age = 1;
7410 priv->cached_height_age = 1;
7412 priv->opacity_override = -1;
7413 priv->enable_model_view_transform = TRUE;
7415 /* Initialize an empty paint volume to start with */
7416 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7417 priv->last_paint_volume_valid = TRUE;
7419 priv->transform_valid = FALSE;
7421 /* the default is to stretch the content, to match the
7422 * current behaviour of basically all actors. also, it's
7423 * the easiest thing to compute.
7425 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7426 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7427 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7429 /* this flag will be set to TRUE if the actor gets a child
7430 * or if the [xy]-expand flags are explicitly set; until
7431 * then, the actor does not need to expand.
7433 * this also allows us to avoid computing the expand flag
7434 * when building up a scene.
7436 priv->needs_compute_expand = FALSE;
7440 * clutter_actor_new:
7442 * Creates a new #ClutterActor.
7444 * A newly created actor has a floating reference, which will be sunk
7445 * when it is added to another actor.
7447 * Return value: (transfer full): the newly created #ClutterActor
7452 clutter_actor_new (void)
7454 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7458 * clutter_actor_destroy:
7459 * @self: a #ClutterActor
7461 * Destroys an actor. When an actor is destroyed, it will break any
7462 * references it holds to other objects. If the actor is inside a
7463 * container, the actor will be removed.
7465 * When you destroy a container, its children will be destroyed as well.
7467 * Note: you cannot destroy the #ClutterStage returned by
7468 * clutter_stage_get_default().
7471 clutter_actor_destroy (ClutterActor *self)
7473 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7475 g_object_ref (self);
7477 /* avoid recursion while destroying */
7478 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7480 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7482 g_object_run_dispose (G_OBJECT (self));
7484 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7487 g_object_unref (self);
7491 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7492 ClutterPaintVolume *clip)
7494 ClutterActorPrivate *priv = self->priv;
7495 ClutterPaintVolume *pv;
7498 /* Remove queue entry early in the process, otherwise a new
7499 queue_redraw() during signal handling could put back this
7500 object in the stage redraw list (but the entry is freed as
7501 soon as we return from this function, causing a segfault
7504 priv->queue_redraw_entry = NULL;
7506 /* If we've been explicitly passed a clip volume then there's
7507 * nothing more to calculate, but otherwise the only thing we know
7508 * is that the change is constrained to the given actor.
7510 * The idea is that if we know the paint volume for where the actor
7511 * was last drawn (in eye coordinates) and we also have the paint
7512 * volume for where it will be drawn next (in actor coordinates)
7513 * then if we queue a redraw for both these volumes that will cover
7514 * everything that needs to be redrawn to clear the old view and
7515 * show the latest view of the actor.
7517 * Don't clip this redraw if we don't know what position we had for
7518 * the previous redraw since we don't know where to set the clip so
7519 * it will clear the actor as it is currently.
7523 _clutter_actor_set_queue_redraw_clip (self, clip);
7526 else if (G_LIKELY (priv->last_paint_volume_valid))
7528 pv = _clutter_actor_get_paint_volume_mutable (self);
7531 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7533 /* make sure we redraw the actors old position... */
7534 _clutter_actor_set_queue_redraw_clip (stage,
7535 &priv->last_paint_volume);
7536 _clutter_actor_signal_queue_redraw (stage, stage);
7537 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7539 /* XXX: Ideally the redraw signal would take a clip volume
7540 * argument, but that would be an ABI break. Until we can
7541 * break the ABI we pass the argument out-of-band
7544 /* setup the clip for the actors new position... */
7545 _clutter_actor_set_queue_redraw_clip (self, pv);
7554 _clutter_actor_signal_queue_redraw (self, self);
7556 /* Just in case anyone is manually firing redraw signals without
7557 * using the public queue_redraw() API we are careful to ensure that
7558 * our out-of-band clip member is cleared before returning...
7560 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7562 if (G_LIKELY (clipped))
7563 _clutter_actor_set_queue_redraw_clip (self, NULL);
7567 _clutter_actor_get_allocation_clip (ClutterActor *self,
7568 ClutterActorBox *clip)
7570 ClutterActorBox allocation;
7572 /* XXX: we don't care if we get an out of date allocation here
7573 * because clutter_actor_queue_redraw_with_clip knows to ignore
7574 * the clip if the actor's allocation is invalid.
7576 * This is noted because clutter_actor_get_allocation_box does some
7577 * unnecessary work to support buggy code with a comment suggesting
7578 * that it could be changed later which would be good for this use
7581 clutter_actor_get_allocation_box (self, &allocation);
7583 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7584 * actor's own coordinate space but the allocation is in parent
7588 clip->x2 = allocation.x2 - allocation.x1;
7589 clip->y2 = allocation.y2 - allocation.y1;
7593 _clutter_actor_queue_redraw_full (ClutterActor *self,
7594 ClutterRedrawFlags flags,
7595 ClutterPaintVolume *volume,
7596 ClutterEffect *effect)
7598 ClutterActorPrivate *priv = self->priv;
7599 ClutterPaintVolume allocation_pv;
7600 ClutterPaintVolume *pv;
7601 gboolean should_free_pv;
7602 ClutterActor *stage;
7604 /* Here's an outline of the actor queue redraw mechanism:
7606 * The process starts in one of the following two functions which
7607 * are wrappers for this function:
7608 * clutter_actor_queue_redraw
7609 * _clutter_actor_queue_redraw_with_clip
7611 * additionally, an effect can queue a redraw by wrapping this
7612 * function in clutter_effect_queue_rerun
7614 * This functions queues an entry in a list associated with the
7615 * stage which is a list of actors that queued a redraw while
7616 * updating the timelines, performing layouting and processing other
7617 * mainloop sources before the next paint starts.
7619 * We aim to minimize the processing done at this point because
7620 * there is a good chance other events will happen while updating
7621 * the scenegraph that would invalidate any expensive work we might
7622 * otherwise try to do here. For example we don't try and resolve
7623 * the screen space bounding box of an actor at this stage so as to
7624 * minimize how much of the screen redraw because it's possible
7625 * something else will happen which will force a full redraw anyway.
7627 * When all updates are complete and we come to paint the stage then
7628 * we iterate this list and actually emit the "queue-redraw" signals
7629 * for each of the listed actors which will bubble up to the stage
7630 * for each actor and at that point we will transform the actors
7631 * paint volume into screen coordinates to determine the clip region
7632 * for what needs to be redrawn in the next paint.
7634 * Besides minimizing redundant work another reason for this
7635 * deferred design is that it's more likely we will be able to
7636 * determine the paint volume of an actor once we've finished
7637 * updating the scenegraph because its allocation should be up to
7638 * date. NB: If we can't determine an actors paint volume then we
7639 * can't automatically queue a clipped redraw which can make a big
7640 * difference to performance.
7642 * So the control flow goes like this:
7643 * One of clutter_actor_queue_redraw,
7644 * _clutter_actor_queue_redraw_with_clip
7645 * or clutter_effect_queue_rerun
7647 * then control moves to:
7648 * _clutter_stage_queue_actor_redraw
7650 * later during _clutter_stage_do_update, once relayouting is done
7651 * and the scenegraph has been updated we will call:
7652 * _clutter_stage_finish_queue_redraws
7654 * _clutter_stage_finish_queue_redraws will call
7655 * _clutter_actor_finish_queue_redraw for each listed actor.
7656 * Note: actors *are* allowed to queue further redraws during this
7657 * process (considering clone actors or texture_new_from_actor which
7658 * respond to their source queueing a redraw by queuing a redraw
7659 * themselves). We repeat the process until the list is empty.
7661 * This will result in the "queue-redraw" signal being fired for
7662 * each actor which will pass control to the default signal handler:
7663 * clutter_actor_real_queue_redraw
7665 * This will bubble up to the stages handler:
7666 * clutter_stage_real_queue_redraw
7668 * clutter_stage_real_queue_redraw will transform the actors paint
7669 * volume into screen space and add it as a clip region for the next
7673 /* ignore queueing a redraw for actors being destroyed */
7674 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7677 stage = _clutter_actor_get_stage_internal (self);
7679 /* Ignore queueing a redraw for actors not descended from a stage */
7683 /* ignore queueing a redraw on stages that are being destroyed */
7684 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7687 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7689 ClutterActorBox allocation_clip;
7690 ClutterVertex origin;
7692 /* If the actor doesn't have a valid allocation then we will
7693 * queue a full stage redraw. */
7694 if (priv->needs_allocation)
7696 /* NB: NULL denotes an undefined clip which will result in a
7698 _clutter_actor_set_queue_redraw_clip (self, NULL);
7699 _clutter_actor_signal_queue_redraw (self, self);
7703 _clutter_paint_volume_init_static (&allocation_pv, self);
7704 pv = &allocation_pv;
7706 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7708 origin.x = allocation_clip.x1;
7709 origin.y = allocation_clip.y1;
7711 clutter_paint_volume_set_origin (pv, &origin);
7712 clutter_paint_volume_set_width (pv,
7713 allocation_clip.x2 - allocation_clip.x1);
7714 clutter_paint_volume_set_height (pv,
7715 allocation_clip.y2 -
7716 allocation_clip.y1);
7717 should_free_pv = TRUE;
7722 should_free_pv = FALSE;
7725 self->priv->queue_redraw_entry =
7726 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7727 priv->queue_redraw_entry,
7732 clutter_paint_volume_free (pv);
7734 /* If this is the first redraw queued then we can directly use the
7736 if (!priv->is_dirty)
7737 priv->effect_to_redraw = effect;
7738 /* Otherwise we need to merge it with the existing effect parameter */
7739 else if (effect != NULL)
7741 /* If there's already an effect then we need to use whichever is
7742 later in the chain of actors. Otherwise a full redraw has
7743 already been queued on the actor so we need to ignore the
7745 if (priv->effect_to_redraw != NULL)
7747 if (priv->effects == NULL)
7748 g_warning ("Redraw queued with an effect that is "
7749 "not applied to the actor");
7754 for (l = _clutter_meta_group_peek_metas (priv->effects);
7758 if (l->data == priv->effect_to_redraw ||
7760 priv->effect_to_redraw = l->data;
7767 /* If no effect is specified then we need to redraw the whole
7769 priv->effect_to_redraw = NULL;
7772 priv->is_dirty = TRUE;
7776 * clutter_actor_queue_redraw:
7777 * @self: A #ClutterActor
7779 * Queues up a redraw of an actor and any children. The redraw occurs
7780 * once the main loop becomes idle (after the current batch of events
7781 * has been processed, roughly).
7783 * Applications rarely need to call this, as redraws are handled
7784 * automatically by modification functions.
7786 * This function will not do anything if @self is not visible, or
7787 * if the actor is inside an invisible part of the scenegraph.
7789 * Also be aware that painting is a NOP for actors with an opacity of
7792 * When you are implementing a custom actor you must queue a redraw
7793 * whenever some private state changes that will affect painting or
7794 * picking of your actor.
7797 clutter_actor_queue_redraw (ClutterActor *self)
7799 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7801 _clutter_actor_queue_redraw_full (self,
7803 NULL, /* clip volume */
7808 * _clutter_actor_queue_redraw_with_clip:
7809 * @self: A #ClutterActor
7810 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7811 * this queue redraw.
7812 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7813 * redrawn or %NULL if you are just using a @flag to state your
7816 * Queues up a clipped redraw of an actor and any children. The redraw
7817 * occurs once the main loop becomes idle (after the current batch of
7818 * events has been processed, roughly).
7820 * If no flags are given the clip volume is defined by @volume
7821 * specified in actor coordinates and tells Clutter that only content
7822 * within this volume has been changed so Clutter can optionally
7823 * optimize the redraw.
7825 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7826 * should be %NULL and this tells Clutter to use the actor's current
7827 * allocation as a clip box. This flag can only be used for 2D actors,
7828 * because any actor with depth may be projected outside its
7831 * Applications rarely need to call this, as redraws are handled
7832 * automatically by modification functions.
7834 * This function will not do anything if @self is not visible, or if
7835 * the actor is inside an invisible part of the scenegraph.
7837 * Also be aware that painting is a NOP for actors with an opacity of
7840 * When you are implementing a custom actor you must queue a redraw
7841 * whenever some private state changes that will affect painting or
7842 * picking of your actor.
7845 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7846 ClutterRedrawFlags flags,
7847 ClutterPaintVolume *volume)
7849 _clutter_actor_queue_redraw_full (self,
7851 volume, /* clip volume */
7856 _clutter_actor_queue_only_relayout (ClutterActor *self)
7858 ClutterActorPrivate *priv = self->priv;
7860 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7863 if (priv->needs_width_request &&
7864 priv->needs_height_request &&
7865 priv->needs_allocation)
7866 return; /* save some cpu cycles */
7868 #if CLUTTER_ENABLE_DEBUG
7869 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7871 g_warning ("The actor '%s' is currently inside an allocation "
7872 "cycle; calling clutter_actor_queue_relayout() is "
7874 _clutter_actor_get_debug_name (self));
7876 #endif /* CLUTTER_ENABLE_DEBUG */
7878 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7882 * clutter_actor_queue_redraw_with_clip:
7883 * @self: a #ClutterActor
7884 * @clip: (allow-none): a rectangular clip region, or %NULL
7886 * Queues a redraw on @self limited to a specific, actor-relative
7889 * If @clip is %NULL this function is equivalent to
7890 * clutter_actor_queue_redraw().
7895 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7896 const cairo_rectangle_int_t *clip)
7898 ClutterPaintVolume volume;
7899 ClutterVertex origin;
7901 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7905 clutter_actor_queue_redraw (self);
7909 _clutter_paint_volume_init_static (&volume, self);
7915 clutter_paint_volume_set_origin (&volume, &origin);
7916 clutter_paint_volume_set_width (&volume, clip->width);
7917 clutter_paint_volume_set_height (&volume, clip->height);
7919 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7921 clutter_paint_volume_free (&volume);
7925 * clutter_actor_queue_relayout:
7926 * @self: A #ClutterActor
7928 * Indicates that the actor's size request or other layout-affecting
7929 * properties may have changed. This function is used inside #ClutterActor
7930 * subclass implementations, not by applications directly.
7932 * Queueing a new layout automatically queues a redraw as well.
7937 clutter_actor_queue_relayout (ClutterActor *self)
7939 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7941 _clutter_actor_queue_only_relayout (self);
7942 clutter_actor_queue_redraw (self);
7946 * clutter_actor_get_preferred_size:
7947 * @self: a #ClutterActor
7948 * @min_width_p: (out) (allow-none): return location for the minimum
7950 * @min_height_p: (out) (allow-none): return location for the minimum
7952 * @natural_width_p: (out) (allow-none): return location for the natural
7954 * @natural_height_p: (out) (allow-none): return location for the natural
7957 * Computes the preferred minimum and natural size of an actor, taking into
7958 * account the actor's geometry management (either height-for-width
7959 * or width-for-height).
7961 * The width and height used to compute the preferred height and preferred
7962 * width are the actor's natural ones.
7964 * If you need to control the height for the preferred width, or the width for
7965 * the preferred height, you should use clutter_actor_get_preferred_width()
7966 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7967 * geometry management using the #ClutterActor:request-mode property.
7972 clutter_actor_get_preferred_size (ClutterActor *self,
7973 gfloat *min_width_p,
7974 gfloat *min_height_p,
7975 gfloat *natural_width_p,
7976 gfloat *natural_height_p)
7978 ClutterActorPrivate *priv;
7979 gfloat min_width, min_height;
7980 gfloat natural_width, natural_height;
7982 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7986 min_width = min_height = 0;
7987 natural_width = natural_height = 0;
7989 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7991 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7992 clutter_actor_get_preferred_width (self, -1,
7995 clutter_actor_get_preferred_height (self, natural_width,
8001 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
8002 clutter_actor_get_preferred_height (self, -1,
8005 clutter_actor_get_preferred_width (self, natural_height,
8011 *min_width_p = min_width;
8014 *min_height_p = min_height;
8016 if (natural_width_p)
8017 *natural_width_p = natural_width;
8019 if (natural_height_p)
8020 *natural_height_p = natural_height;
8025 * @align: a #ClutterActorAlign
8026 * @direction: a #ClutterTextDirection
8028 * Retrieves the correct alignment depending on the text direction
8030 * Return value: the effective alignment
8032 static ClutterActorAlign
8033 effective_align (ClutterActorAlign align,
8034 ClutterTextDirection direction)
8036 ClutterActorAlign res;
8040 case CLUTTER_ACTOR_ALIGN_START:
8041 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
8042 ? CLUTTER_ACTOR_ALIGN_END
8043 : CLUTTER_ACTOR_ALIGN_START;
8046 case CLUTTER_ACTOR_ALIGN_END:
8047 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
8048 ? CLUTTER_ACTOR_ALIGN_START
8049 : CLUTTER_ACTOR_ALIGN_END;
8061 * _clutter_actor_get_effective_x_align:
8062 * @self: a #ClutterActor
8064 * Retrieves the effective horizontal alignment, taking into
8065 * consideration the text direction of @self.
8067 * Return value: the effective horizontal alignment
8070 _clutter_actor_get_effective_x_align (ClutterActor *self)
8072 return effective_align (clutter_actor_get_x_align (self),
8073 clutter_actor_get_text_direction (self));
8077 adjust_for_margin (float margin_start,
8079 float *minimum_size,
8080 float *natural_size,
8081 float *allocated_start,
8082 float *allocated_end)
8084 *minimum_size -= (margin_start + margin_end);
8085 *natural_size -= (margin_start + margin_end);
8086 *allocated_start += margin_start;
8087 *allocated_end -= margin_end;
8091 adjust_for_alignment (ClutterActorAlign alignment,
8093 float *allocated_start,
8094 float *allocated_end)
8096 float allocated_size = *allocated_end - *allocated_start;
8100 case CLUTTER_ACTOR_ALIGN_FILL:
8104 case CLUTTER_ACTOR_ALIGN_START:
8106 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
8109 case CLUTTER_ACTOR_ALIGN_END:
8110 if (allocated_size > natural_size)
8112 *allocated_start += (allocated_size - natural_size);
8113 *allocated_end = *allocated_start + natural_size;
8117 case CLUTTER_ACTOR_ALIGN_CENTER:
8118 if (allocated_size > natural_size)
8120 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
8121 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
8128 * clutter_actor_adjust_width:
8129 * @self: a #ClutterActor
8130 * @minimum_width: (inout): the actor's preferred minimum width, which
8131 * will be adjusted depending on the margin
8132 * @natural_width: (inout): the actor's preferred natural width, which
8133 * will be adjusted depending on the margin
8134 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
8135 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
8137 * Adjusts the preferred and allocated position and size of an actor,
8138 * depending on the margin and alignment properties.
8141 clutter_actor_adjust_width (ClutterActor *self,
8142 gfloat *minimum_width,
8143 gfloat *natural_width,
8144 gfloat *adjusted_x1,
8145 gfloat *adjusted_x2)
8147 ClutterTextDirection text_dir;
8148 const ClutterLayoutInfo *info;
8150 info = _clutter_actor_get_layout_info_or_defaults (self);
8151 text_dir = clutter_actor_get_text_direction (self);
8153 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
8155 /* this will tweak natural_width to remove the margin, so that
8156 * adjust_for_alignment() will use the correct size
8158 adjust_for_margin (info->margin.left, info->margin.right,
8159 minimum_width, natural_width,
8160 adjusted_x1, adjusted_x2);
8162 adjust_for_alignment (effective_align (info->x_align, text_dir),
8164 adjusted_x1, adjusted_x2);
8168 * clutter_actor_adjust_height:
8169 * @self: a #ClutterActor
8170 * @minimum_height: (inout): the actor's preferred minimum height, which
8171 * will be adjusted depending on the margin
8172 * @natural_height: (inout): the actor's preferred natural height, which
8173 * will be adjusted depending on the margin
8174 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
8175 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
8177 * Adjusts the preferred and allocated position and size of an actor,
8178 * depending on the margin and alignment properties.
8181 clutter_actor_adjust_height (ClutterActor *self,
8182 gfloat *minimum_height,
8183 gfloat *natural_height,
8184 gfloat *adjusted_y1,
8185 gfloat *adjusted_y2)
8187 const ClutterLayoutInfo *info;
8189 info = _clutter_actor_get_layout_info_or_defaults (self);
8191 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
8193 /* this will tweak natural_height to remove the margin, so that
8194 * adjust_for_alignment() will use the correct size
8196 adjust_for_margin (info->margin.top, info->margin.bottom,
8197 minimum_height, natural_height,
8201 /* we don't use effective_align() here, because text direction
8202 * only affects the horizontal axis
8204 adjust_for_alignment (info->y_align,
8211 /* looks for a cached size request for this for_size. If not
8212 * found, returns the oldest entry so it can be overwritten */
8214 _clutter_actor_get_cached_size_request (gfloat for_size,
8215 SizeRequest *cached_size_requests,
8216 SizeRequest **result)
8220 *result = &cached_size_requests[0];
8222 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
8226 sr = &cached_size_requests[i];
8229 sr->for_size == for_size)
8231 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8235 else if (sr->age < (*result)->age)
8241 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8247 * clutter_actor_get_preferred_width:
8248 * @self: A #ClutterActor
8249 * @for_height: available height when computing the preferred width,
8250 * or a negative value to indicate that no height is defined
8251 * @min_width_p: (out) (allow-none): return location for minimum width,
8253 * @natural_width_p: (out) (allow-none): return location for the natural
8256 * Computes the requested minimum and natural widths for an actor,
8257 * optionally depending on the specified height, or if they are
8258 * already computed, returns the cached values.
8260 * An actor may not get its request - depending on the layout
8261 * manager that's in effect.
8263 * A request should not incorporate the actor's scale or anchor point;
8264 * those transformations do not affect layout, only rendering.
8269 clutter_actor_get_preferred_width (ClutterActor *self,
8271 gfloat *min_width_p,
8272 gfloat *natural_width_p)
8274 float request_min_width, request_natural_width;
8275 SizeRequest *cached_size_request;
8276 const ClutterLayoutInfo *info;
8277 ClutterActorPrivate *priv;
8278 gboolean found_in_cache;
8280 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8284 info = _clutter_actor_get_layout_info_or_defaults (self);
8286 /* we shortcircuit the case of a fixed size set using set_width() */
8287 if (priv->min_width_set && priv->natural_width_set)
8289 if (min_width_p != NULL)
8290 *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8292 if (natural_width_p != NULL)
8293 *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8298 /* the remaining cases are:
8300 * - either min_width or natural_width have been set
8301 * - neither min_width or natural_width have been set
8303 * in both cases, we go through the cache (and through the actor in case
8304 * of cache misses) and determine the authoritative value depending on
8308 if (!priv->needs_width_request)
8311 _clutter_actor_get_cached_size_request (for_height,
8312 priv->width_requests,
8313 &cached_size_request);
8317 /* if the actor needs a width request we use the first slot */
8318 found_in_cache = FALSE;
8319 cached_size_request = &priv->width_requests[0];
8322 if (!found_in_cache)
8324 gfloat minimum_width, natural_width;
8325 ClutterActorClass *klass;
8327 minimum_width = natural_width = 0;
8329 /* adjust for the margin */
8330 if (for_height >= 0)
8332 for_height -= (info->margin.top + info->margin.bottom);
8337 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8339 klass = CLUTTER_ACTOR_GET_CLASS (self);
8340 klass->get_preferred_width (self, for_height,
8344 /* adjust for the margin */
8345 minimum_width += (info->margin.left + info->margin.right);
8346 natural_width += (info->margin.left + info->margin.right);
8348 /* Due to accumulated float errors, it's better not to warn
8349 * on this, but just fix it.
8351 if (natural_width < minimum_width)
8352 natural_width = minimum_width;
8354 cached_size_request->min_size = minimum_width;
8355 cached_size_request->natural_size = natural_width;
8356 cached_size_request->for_size = for_height;
8357 cached_size_request->age = priv->cached_width_age;
8359 priv->cached_width_age += 1;
8360 priv->needs_width_request = FALSE;
8363 if (!priv->min_width_set)
8364 request_min_width = cached_size_request->min_size;
8366 request_min_width = info->margin.left
8367 + info->minimum.width
8368 + info->margin.right;
8370 if (!priv->natural_width_set)
8371 request_natural_width = cached_size_request->natural_size;
8373 request_natural_width = info->margin.left
8374 + info->natural.width
8375 + info->margin.right;
8378 *min_width_p = request_min_width;
8380 if (natural_width_p)
8381 *natural_width_p = request_natural_width;
8385 * clutter_actor_get_preferred_height:
8386 * @self: A #ClutterActor
8387 * @for_width: available width to assume in computing desired height,
8388 * or a negative value to indicate that no width is defined
8389 * @min_height_p: (out) (allow-none): return location for minimum height,
8391 * @natural_height_p: (out) (allow-none): return location for natural
8394 * Computes the requested minimum and natural heights for an actor,
8395 * or if they are already computed, returns the cached values.
8397 * An actor may not get its request - depending on the layout
8398 * manager that's in effect.
8400 * A request should not incorporate the actor's scale or anchor point;
8401 * those transformations do not affect layout, only rendering.
8406 clutter_actor_get_preferred_height (ClutterActor *self,
8408 gfloat *min_height_p,
8409 gfloat *natural_height_p)
8411 float request_min_height, request_natural_height;
8412 SizeRequest *cached_size_request;
8413 const ClutterLayoutInfo *info;
8414 ClutterActorPrivate *priv;
8415 gboolean found_in_cache;
8417 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8421 info = _clutter_actor_get_layout_info_or_defaults (self);
8423 /* we shortcircuit the case of a fixed size set using set_height() */
8424 if (priv->min_height_set && priv->natural_height_set)
8426 if (min_height_p != NULL)
8427 *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8429 if (natural_height_p != NULL)
8430 *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8435 /* the remaining cases are:
8437 * - either min_height or natural_height have been set
8438 * - neither min_height or natural_height have been set
8440 * in both cases, we go through the cache (and through the actor in case
8441 * of cache misses) and determine the authoritative value depending on
8445 if (!priv->needs_height_request)
8448 _clutter_actor_get_cached_size_request (for_width,
8449 priv->height_requests,
8450 &cached_size_request);
8454 found_in_cache = FALSE;
8455 cached_size_request = &priv->height_requests[0];
8458 if (!found_in_cache)
8460 gfloat minimum_height, natural_height;
8461 ClutterActorClass *klass;
8463 minimum_height = natural_height = 0;
8465 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8467 /* adjust for margin */
8470 for_width -= (info->margin.left + info->margin.right);
8475 klass = CLUTTER_ACTOR_GET_CLASS (self);
8476 klass->get_preferred_height (self, for_width,
8480 /* adjust for margin */
8481 minimum_height += (info->margin.top + info->margin.bottom);
8482 natural_height += (info->margin.top + info->margin.bottom);
8484 /* Due to accumulated float errors, it's better not to warn
8485 * on this, but just fix it.
8487 if (natural_height < minimum_height)
8488 natural_height = minimum_height;
8490 cached_size_request->min_size = minimum_height;
8491 cached_size_request->natural_size = natural_height;
8492 cached_size_request->for_size = for_width;
8493 cached_size_request->age = priv->cached_height_age;
8495 priv->cached_height_age += 1;
8496 priv->needs_height_request = FALSE;
8499 if (!priv->min_height_set)
8500 request_min_height = cached_size_request->min_size;
8502 request_min_height = info->margin.top
8503 + info->minimum.height
8504 + info->margin.bottom;
8506 if (!priv->natural_height_set)
8507 request_natural_height = cached_size_request->natural_size;
8509 request_natural_height = info->margin.top
8510 + info->natural.height
8511 + info->margin.bottom;
8514 *min_height_p = request_min_height;
8516 if (natural_height_p)
8517 *natural_height_p = request_natural_height;
8521 * clutter_actor_get_allocation_box:
8522 * @self: A #ClutterActor
8523 * @box: (out): the function fills this in with the actor's allocation
8525 * Gets the layout box an actor has been assigned. The allocation can
8526 * only be assumed valid inside a paint() method; anywhere else, it
8527 * may be out-of-date.
8529 * An allocation does not incorporate the actor's scale or anchor point;
8530 * those transformations do not affect layout, only rendering.
8532 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8533 * of functions inside the implementation of the get_preferred_width()
8534 * or get_preferred_height() virtual functions.</note>
8539 clutter_actor_get_allocation_box (ClutterActor *self,
8540 ClutterActorBox *box)
8542 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8544 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8545 * which limits calling get_allocation to inside paint() basically; or
8546 * we can 2) force a layout, which could be expensive if someone calls
8547 * get_allocation somewhere silly; or we can 3) just return the latest
8548 * value, allowing it to be out-of-date, and assume people know what
8551 * The least-surprises approach that keeps existing code working is
8552 * likely to be 2). People can end up doing some inefficient things,
8553 * though, and in general code that requires 2) is probably broken.
8556 /* this implements 2) */
8557 if (G_UNLIKELY (self->priv->needs_allocation))
8559 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8561 /* do not queue a relayout on an unparented actor */
8563 _clutter_stage_maybe_relayout (stage);
8566 /* commenting out the code above and just keeping this assigment
8569 *box = self->priv->allocation;
8573 * clutter_actor_get_allocation_geometry:
8574 * @self: A #ClutterActor
8575 * @geom: (out): allocation geometry in pixels
8577 * Gets the layout box an actor has been assigned. The allocation can
8578 * only be assumed valid inside a paint() method; anywhere else, it
8579 * may be out-of-date.
8581 * An allocation does not incorporate the actor's scale or anchor point;
8582 * those transformations do not affect layout, only rendering.
8584 * The returned rectangle is in pixels.
8589 clutter_actor_get_allocation_geometry (ClutterActor *self,
8590 ClutterGeometry *geom)
8592 ClutterActorBox box;
8594 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8595 g_return_if_fail (geom != NULL);
8597 clutter_actor_get_allocation_box (self, &box);
8599 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8600 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8601 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8602 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8606 clutter_actor_update_constraints (ClutterActor *self,
8607 ClutterActorBox *allocation)
8609 ClutterActorPrivate *priv = self->priv;
8610 const GList *constraints, *l;
8612 if (priv->constraints == NULL)
8615 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8616 for (l = constraints; l != NULL; l = l->next)
8618 ClutterConstraint *constraint = l->data;
8619 ClutterActorMeta *meta = l->data;
8621 if (clutter_actor_meta_get_enabled (meta))
8623 _clutter_constraint_update_allocation (constraint,
8627 CLUTTER_NOTE (LAYOUT,
8628 "Allocation of '%s' after constraint '%s': "
8629 "{ %.2f, %.2f, %.2f, %.2f }",
8630 _clutter_actor_get_debug_name (self),
8631 _clutter_actor_meta_get_debug_name (meta),
8641 * clutter_actor_adjust_allocation:
8642 * @self: a #ClutterActor
8643 * @allocation: (inout): the allocation to adjust
8645 * Adjusts the passed allocation box taking into account the actor's
8646 * layout information, like alignment, expansion, and margin.
8649 clutter_actor_adjust_allocation (ClutterActor *self,
8650 ClutterActorBox *allocation)
8652 ClutterActorBox adj_allocation;
8653 float alloc_width, alloc_height;
8654 float min_width, min_height;
8655 float nat_width, nat_height;
8656 ClutterRequestMode req_mode;
8658 adj_allocation = *allocation;
8660 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8662 /* we want to hit the cache, so we use the public API */
8663 req_mode = clutter_actor_get_request_mode (self);
8665 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8667 clutter_actor_get_preferred_width (self, -1,
8670 clutter_actor_get_preferred_height (self, alloc_width,
8674 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8676 clutter_actor_get_preferred_height (self, -1,
8679 clutter_actor_get_preferred_width (self, alloc_height,
8684 #ifdef CLUTTER_ENABLE_DEBUG
8685 /* warn about underallocations */
8686 if (_clutter_diagnostic_enabled () &&
8687 (floorf (min_width - alloc_width) > 0 ||
8688 floorf (min_height - alloc_height) > 0))
8690 ClutterActor *parent = clutter_actor_get_parent (self);
8692 /* the only actors that are allowed to be underallocated are the Stage,
8693 * as it doesn't have an implicit size, and Actors that specifically
8694 * told us that they want to opt-out from layout control mechanisms
8695 * through the NO_LAYOUT escape hatch.
8697 if (parent != NULL &&
8698 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8700 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8701 "of %.2f x %.2f from its parent actor '%s', but its "
8702 "requested minimum size is of %.2f x %.2f",
8703 _clutter_actor_get_debug_name (self),
8704 alloc_width, alloc_height,
8705 _clutter_actor_get_debug_name (parent),
8706 min_width, min_height);
8711 clutter_actor_adjust_width (self,
8715 &adj_allocation.x2);
8717 clutter_actor_adjust_height (self,
8721 &adj_allocation.y2);
8723 /* we maintain the invariant that an allocation cannot be adjusted
8724 * to be outside the parent-given box
8726 if (adj_allocation.x1 < allocation->x1 ||
8727 adj_allocation.y1 < allocation->y1 ||
8728 adj_allocation.x2 > allocation->x2 ||
8729 adj_allocation.y2 > allocation->y2)
8731 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8732 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8733 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8734 _clutter_actor_get_debug_name (self),
8735 adj_allocation.x1, adj_allocation.y1,
8736 adj_allocation.x2 - adj_allocation.x1,
8737 adj_allocation.y2 - adj_allocation.y1,
8738 allocation->x1, allocation->y1,
8739 allocation->x2 - allocation->x1,
8740 allocation->y2 - allocation->y1);
8744 *allocation = adj_allocation;
8748 clutter_actor_allocate_internal (ClutterActor *self,
8749 const ClutterActorBox *allocation,
8750 ClutterAllocationFlags flags)
8752 ClutterActorClass *klass;
8754 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8756 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8757 _clutter_actor_get_debug_name (self));
8759 klass = CLUTTER_ACTOR_GET_CLASS (self);
8760 klass->allocate (self, allocation, flags);
8762 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8764 clutter_actor_queue_redraw (self);
8768 * clutter_actor_allocate:
8769 * @self: A #ClutterActor
8770 * @box: new allocation of the actor, in parent-relative coordinates
8771 * @flags: flags that control the allocation
8773 * Called by the parent of an actor to assign the actor its size.
8774 * Should never be called by applications (except when implementing
8775 * a container or layout manager).
8777 * Actors can know from their allocation box whether they have moved
8778 * with respect to their parent actor. The @flags parameter describes
8779 * additional information about the allocation, for instance whether
8780 * the parent has moved with respect to the stage, for example because
8781 * a grandparent's origin has moved.
8786 clutter_actor_allocate (ClutterActor *self,
8787 const ClutterActorBox *box,
8788 ClutterAllocationFlags flags)
8790 ClutterActorBox old_allocation, real_allocation;
8791 gboolean origin_changed, child_moved, size_changed;
8792 gboolean stage_allocation_changed;
8793 ClutterActorPrivate *priv;
8795 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8796 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8798 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8799 "which isn't a descendent of the stage!\n",
8800 self, _clutter_actor_get_debug_name (self));
8806 old_allocation = priv->allocation;
8807 real_allocation = *box;
8809 /* constraints are allowed to modify the allocation only here; we do
8810 * this prior to all the other checks so that we can bail out if the
8811 * allocation did not change
8813 clutter_actor_update_constraints (self, &real_allocation);
8815 /* adjust the allocation depending on the align/margin properties */
8816 clutter_actor_adjust_allocation (self, &real_allocation);
8818 if (real_allocation.x2 < real_allocation.x1 ||
8819 real_allocation.y2 < real_allocation.y1)
8821 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8822 _clutter_actor_get_debug_name (self),
8823 real_allocation.x2 - real_allocation.x1,
8824 real_allocation.y2 - real_allocation.y1);
8827 /* we allow 0-sized actors, but not negative-sized ones */
8828 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8829 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8831 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8833 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8834 real_allocation.y1 != old_allocation.y1);
8836 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8837 real_allocation.y2 != old_allocation.y2);
8839 if (origin_changed || child_moved || size_changed)
8840 stage_allocation_changed = TRUE;
8842 stage_allocation_changed = FALSE;
8844 /* If we get an allocation "out of the blue"
8845 * (we did not queue relayout), then we want to
8846 * ignore it. But if we have needs_allocation set,
8847 * we want to guarantee that allocate() virtual
8848 * method is always called, i.e. that queue_relayout()
8849 * always results in an allocate() invocation on
8852 * The optimization here is to avoid re-allocating
8853 * actors that did not queue relayout and were
8856 if (!priv->needs_allocation && !stage_allocation_changed)
8858 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8862 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8863 * clutter_actor_allocate(), it indicates whether the parent has its
8864 * absolute origin moved; when passed in to ClutterActor::allocate()
8865 * virtual method though, it indicates whether the child has its
8866 * absolute origin moved. So we set it when child_moved is TRUE
8869 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8871 /* store the flags here, so that they can be propagated by the
8874 self->priv->allocation_flags = flags;
8876 if (_clutter_actor_get_transition (self, obj_props[PROP_ALLOCATION]) == NULL)
8878 _clutter_actor_create_transition (self, obj_props[PROP_ALLOCATION],
8883 _clutter_actor_update_transition (self, obj_props[PROP_ALLOCATION],
8888 * clutter_actor_set_allocation:
8889 * @self: a #ClutterActor
8890 * @box: a #ClutterActorBox
8891 * @flags: allocation flags
8893 * Stores the allocation of @self as defined by @box.
8895 * This function can only be called from within the implementation of
8896 * the #ClutterActorClass.allocate() virtual function.
8898 * The allocation should have been adjusted to take into account constraints,
8899 * alignment, and margin properties. If you are implementing a #ClutterActor
8900 * subclass that provides its own layout management policy for its children
8901 * instead of using a #ClutterLayoutManager delegate, you should not call
8902 * this function on the children of @self; instead, you should call
8903 * clutter_actor_allocate(), which will adjust the allocation box for
8906 * This function should only be used by subclasses of #ClutterActor
8907 * that wish to store their allocation but cannot chain up to the
8908 * parent's implementation; the default implementation of the
8909 * #ClutterActorClass.allocate() virtual function will call this
8912 * It is important to note that, while chaining up was the recommended
8913 * behaviour for #ClutterActor subclasses prior to the introduction of
8914 * this function, it is recommended to call clutter_actor_set_allocation()
8917 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8918 * to handle the allocation of its children, this function will call
8919 * the clutter_layout_manager_allocate() function only if the
8920 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8921 * expected that the subclass will call clutter_layout_manager_allocate()
8922 * by itself. For instance, the following code:
8926 * my_actor_allocate (ClutterActor *actor,
8927 * const ClutterActorBox *allocation,
8928 * ClutterAllocationFlags flags)
8930 * ClutterActorBox new_alloc;
8931 * ClutterAllocationFlags new_flags;
8933 * adjust_allocation (allocation, &new_alloc);
8935 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8937 * /* this will use the layout manager set on the actor */
8938 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8942 * is equivalent to this:
8946 * my_actor_allocate (ClutterActor *actor,
8947 * const ClutterActorBox *allocation,
8948 * ClutterAllocationFlags flags)
8950 * ClutterLayoutManager *layout;
8951 * ClutterActorBox new_alloc;
8953 * adjust_allocation (allocation, &new_alloc);
8955 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8957 * layout = clutter_actor_get_layout_manager (actor);
8958 * clutter_layout_manager_allocate (layout,
8959 * CLUTTER_CONTAINER (actor),
8968 clutter_actor_set_allocation (ClutterActor *self,
8969 const ClutterActorBox *box,
8970 ClutterAllocationFlags flags)
8972 ClutterActorPrivate *priv;
8975 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8976 g_return_if_fail (box != NULL);
8978 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8980 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8981 "can only be called from within the implementation of "
8982 "the ClutterActor::allocate() virtual function.");
8988 g_object_freeze_notify (G_OBJECT (self));
8990 changed = clutter_actor_set_allocation_internal (self, box, flags);
8992 /* we allocate our children before we notify changes in our geometry,
8993 * so that people connecting to properties will be able to get valid
8994 * data out of the sub-tree of the scene graph that has this actor at
8997 clutter_actor_maybe_layout_children (self, box, flags);
9001 ClutterActorBox signal_box = priv->allocation;
9002 ClutterAllocationFlags signal_flags = priv->allocation_flags;
9004 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
9009 g_object_thaw_notify (G_OBJECT (self));
9013 * clutter_actor_set_geometry:
9014 * @self: A #ClutterActor
9015 * @geometry: A #ClutterGeometry
9017 * Sets the actor's fixed position and forces its minimum and natural
9018 * size, in pixels. This means the untransformed actor will have the
9019 * given geometry. This is the same as calling clutter_actor_set_position()
9020 * and clutter_actor_set_size().
9022 * Deprecated: 1.10: Use clutter_actor_set_position() and
9023 * clutter_actor_set_size() instead.
9026 clutter_actor_set_geometry (ClutterActor *self,
9027 const ClutterGeometry *geometry)
9029 g_object_freeze_notify (G_OBJECT (self));
9031 clutter_actor_set_position (self, geometry->x, geometry->y);
9032 clutter_actor_set_size (self, geometry->width, geometry->height);
9034 g_object_thaw_notify (G_OBJECT (self));
9038 * clutter_actor_get_geometry:
9039 * @self: A #ClutterActor
9040 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
9042 * Gets the size and position of an actor relative to its parent
9043 * actor. This is the same as calling clutter_actor_get_position() and
9044 * clutter_actor_get_size(). It tries to "do what you mean" and get the
9045 * requested size and position if the actor's allocation is invalid.
9047 * Deprecated: 1.10: Use clutter_actor_get_position() and
9048 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
9052 clutter_actor_get_geometry (ClutterActor *self,
9053 ClutterGeometry *geometry)
9055 gfloat x, y, width, height;
9057 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9058 g_return_if_fail (geometry != NULL);
9060 clutter_actor_get_position (self, &x, &y);
9061 clutter_actor_get_size (self, &width, &height);
9063 geometry->x = (int) x;
9064 geometry->y = (int) y;
9065 geometry->width = (int) width;
9066 geometry->height = (int) height;
9070 * clutter_actor_set_position:
9071 * @self: A #ClutterActor
9072 * @x: New left position of actor in pixels.
9073 * @y: New top position of actor in pixels.
9075 * Sets the actor's fixed position in pixels relative to any parent
9078 * If a layout manager is in use, this position will override the
9079 * layout manager and force a fixed position.
9082 clutter_actor_set_position (ClutterActor *self,
9086 ClutterPoint new_position;
9088 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9090 clutter_point_init (&new_position, x, y);
9092 if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
9094 ClutterPoint cur_position;
9096 cur_position.x = clutter_actor_get_x (self);
9097 cur_position.y = clutter_actor_get_y (self);
9099 _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
9104 _clutter_actor_update_transition (self,
9105 obj_props[PROP_POSITION],
9108 clutter_actor_queue_relayout (self);
9112 * clutter_actor_get_fixed_position_set:
9113 * @self: A #ClutterActor
9115 * Checks whether an actor has a fixed position set (and will thus be
9116 * unaffected by any layout manager).
9118 * Return value: %TRUE if the fixed position is set on the actor
9123 clutter_actor_get_fixed_position_set (ClutterActor *self)
9125 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9127 return self->priv->position_set;
9131 * clutter_actor_set_fixed_position_set:
9132 * @self: A #ClutterActor
9133 * @is_set: whether to use fixed position
9135 * Sets whether an actor has a fixed position set (and will thus be
9136 * unaffected by any layout manager).
9141 clutter_actor_set_fixed_position_set (ClutterActor *self,
9144 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9146 if (self->priv->position_set == (is_set != FALSE))
9151 ClutterLayoutInfo *info;
9153 /* Ensure we set back the default fixed position of 0,0 so that setting
9154 just one of x/y always atomically gets 0 for the other */
9155 info = _clutter_actor_peek_layout_info (self);
9158 info->fixed_pos.x = 0;
9159 info->fixed_pos.y = 0;
9163 self->priv->position_set = is_set != FALSE;
9164 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9166 clutter_actor_queue_relayout (self);
9170 * clutter_actor_move_by:
9171 * @self: A #ClutterActor
9172 * @dx: Distance to move Actor on X axis.
9173 * @dy: Distance to move Actor on Y axis.
9175 * Moves an actor by the specified distance relative to its current
9176 * position in pixels.
9178 * This function modifies the fixed position of an actor and thus removes
9179 * it from any layout management. Another way to move an actor is with an
9180 * anchor point, see clutter_actor_set_anchor_point().
9185 clutter_actor_move_by (ClutterActor *self,
9189 const ClutterLayoutInfo *info;
9192 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9194 info = _clutter_actor_get_layout_info_or_defaults (self);
9195 x = info->fixed_pos.x;
9196 y = info->fixed_pos.y;
9198 clutter_actor_set_position (self, x + dx, y + dy);
9202 clutter_actor_set_min_width (ClutterActor *self,
9205 ClutterActorPrivate *priv = self->priv;
9206 ClutterActorBox old = { 0, };
9207 ClutterLayoutInfo *info;
9209 /* if we are setting the size on a top-level actor and the
9210 * backend only supports static top-levels (e.g. framebuffers)
9211 * then we ignore the passed value and we override it with
9212 * the stage implementation's preferred size.
9214 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9215 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9218 info = _clutter_actor_get_layout_info (self);
9220 if (priv->min_width_set && min_width == info->minimum.width)
9223 g_object_freeze_notify (G_OBJECT (self));
9225 clutter_actor_store_old_geometry (self, &old);
9227 info->minimum.width = min_width;
9228 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9229 clutter_actor_set_min_width_set (self, TRUE);
9231 clutter_actor_notify_if_geometry_changed (self, &old);
9233 g_object_thaw_notify (G_OBJECT (self));
9235 clutter_actor_queue_relayout (self);
9239 clutter_actor_set_min_height (ClutterActor *self,
9243 ClutterActorPrivate *priv = self->priv;
9244 ClutterActorBox old = { 0, };
9245 ClutterLayoutInfo *info;
9247 /* if we are setting the size on a top-level actor and the
9248 * backend only supports static top-levels (e.g. framebuffers)
9249 * then we ignore the passed value and we override it with
9250 * the stage implementation's preferred size.
9252 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9253 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9256 info = _clutter_actor_get_layout_info (self);
9258 if (priv->min_height_set && min_height == info->minimum.height)
9261 g_object_freeze_notify (G_OBJECT (self));
9263 clutter_actor_store_old_geometry (self, &old);
9265 info->minimum.height = min_height;
9266 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9267 clutter_actor_set_min_height_set (self, TRUE);
9269 clutter_actor_notify_if_geometry_changed (self, &old);
9271 g_object_thaw_notify (G_OBJECT (self));
9273 clutter_actor_queue_relayout (self);
9277 clutter_actor_set_natural_width (ClutterActor *self,
9278 gfloat natural_width)
9280 ClutterActorPrivate *priv = self->priv;
9281 ClutterActorBox old = { 0, };
9282 ClutterLayoutInfo *info;
9284 /* if we are setting the size on a top-level actor and the
9285 * backend only supports static top-levels (e.g. framebuffers)
9286 * then we ignore the passed value and we override it with
9287 * the stage implementation's preferred size.
9289 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9290 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9293 info = _clutter_actor_get_layout_info (self);
9295 if (priv->natural_width_set && natural_width == info->natural.width)
9298 g_object_freeze_notify (G_OBJECT (self));
9300 clutter_actor_store_old_geometry (self, &old);
9302 info->natural.width = natural_width;
9303 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9304 clutter_actor_set_natural_width_set (self, TRUE);
9306 clutter_actor_notify_if_geometry_changed (self, &old);
9308 g_object_thaw_notify (G_OBJECT (self));
9310 clutter_actor_queue_relayout (self);
9314 clutter_actor_set_natural_height (ClutterActor *self,
9315 gfloat natural_height)
9317 ClutterActorPrivate *priv = self->priv;
9318 ClutterActorBox old = { 0, };
9319 ClutterLayoutInfo *info;
9321 /* if we are setting the size on a top-level actor and the
9322 * backend only supports static top-levels (e.g. framebuffers)
9323 * then we ignore the passed value and we override it with
9324 * the stage implementation's preferred size.
9326 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9327 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9330 info = _clutter_actor_get_layout_info (self);
9332 if (priv->natural_height_set && natural_height == info->natural.height)
9335 g_object_freeze_notify (G_OBJECT (self));
9337 clutter_actor_store_old_geometry (self, &old);
9339 info->natural.height = natural_height;
9340 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9341 clutter_actor_set_natural_height_set (self, TRUE);
9343 clutter_actor_notify_if_geometry_changed (self, &old);
9345 g_object_thaw_notify (G_OBJECT (self));
9347 clutter_actor_queue_relayout (self);
9351 clutter_actor_set_min_width_set (ClutterActor *self,
9352 gboolean use_min_width)
9354 ClutterActorPrivate *priv = self->priv;
9355 ClutterActorBox old = { 0, };
9357 if (priv->min_width_set == (use_min_width != FALSE))
9360 clutter_actor_store_old_geometry (self, &old);
9362 priv->min_width_set = use_min_width != FALSE;
9363 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9365 clutter_actor_notify_if_geometry_changed (self, &old);
9367 clutter_actor_queue_relayout (self);
9371 clutter_actor_set_min_height_set (ClutterActor *self,
9372 gboolean use_min_height)
9374 ClutterActorPrivate *priv = self->priv;
9375 ClutterActorBox old = { 0, };
9377 if (priv->min_height_set == (use_min_height != FALSE))
9380 clutter_actor_store_old_geometry (self, &old);
9382 priv->min_height_set = use_min_height != FALSE;
9383 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9385 clutter_actor_notify_if_geometry_changed (self, &old);
9387 clutter_actor_queue_relayout (self);
9391 clutter_actor_set_natural_width_set (ClutterActor *self,
9392 gboolean use_natural_width)
9394 ClutterActorPrivate *priv = self->priv;
9395 ClutterActorBox old = { 0, };
9397 if (priv->natural_width_set == (use_natural_width != FALSE))
9400 clutter_actor_store_old_geometry (self, &old);
9402 priv->natural_width_set = use_natural_width != FALSE;
9403 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9405 clutter_actor_notify_if_geometry_changed (self, &old);
9407 clutter_actor_queue_relayout (self);
9411 clutter_actor_set_natural_height_set (ClutterActor *self,
9412 gboolean use_natural_height)
9414 ClutterActorPrivate *priv = self->priv;
9415 ClutterActorBox old = { 0, };
9417 if (priv->natural_height_set == (use_natural_height != FALSE))
9420 clutter_actor_store_old_geometry (self, &old);
9422 priv->natural_height_set = use_natural_height != FALSE;
9423 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9425 clutter_actor_notify_if_geometry_changed (self, &old);
9427 clutter_actor_queue_relayout (self);
9431 * clutter_actor_set_request_mode:
9432 * @self: a #ClutterActor
9433 * @mode: the request mode
9435 * Sets the geometry request mode of @self.
9437 * The @mode determines the order for invoking
9438 * clutter_actor_get_preferred_width() and
9439 * clutter_actor_get_preferred_height()
9444 clutter_actor_set_request_mode (ClutterActor *self,
9445 ClutterRequestMode mode)
9447 ClutterActorPrivate *priv;
9449 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9453 if (priv->request_mode == mode)
9456 priv->request_mode = mode;
9458 priv->needs_width_request = TRUE;
9459 priv->needs_height_request = TRUE;
9461 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9463 clutter_actor_queue_relayout (self);
9467 * clutter_actor_get_request_mode:
9468 * @self: a #ClutterActor
9470 * Retrieves the geometry request mode of @self
9472 * Return value: the request mode for the actor
9477 clutter_actor_get_request_mode (ClutterActor *self)
9479 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9480 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9482 return self->priv->request_mode;
9485 /* variant of set_width() without checks and without notification
9486 * freeze+thaw, for internal usage only
9489 clutter_actor_set_width_internal (ClutterActor *self,
9494 /* the Stage will use the :min-width to control the minimum
9495 * width to be resized to, so we should not be setting it
9496 * along with the :natural-width
9498 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9499 clutter_actor_set_min_width (self, width);
9501 clutter_actor_set_natural_width (self, width);
9505 /* we only unset the :natural-width for the Stage */
9506 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9507 clutter_actor_set_min_width_set (self, FALSE);
9509 clutter_actor_set_natural_width_set (self, FALSE);
9513 /* variant of set_height() without checks and without notification
9514 * freeze+thaw, for internal usage only
9517 clutter_actor_set_height_internal (ClutterActor *self,
9522 /* see the comment above in set_width_internal() */
9523 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9524 clutter_actor_set_min_height (self, height);
9526 clutter_actor_set_natural_height (self, height);
9530 /* see the comment above in set_width_internal() */
9531 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9532 clutter_actor_set_min_height_set (self, FALSE);
9534 clutter_actor_set_natural_height_set (self, FALSE);
9539 clutter_actor_set_size_internal (ClutterActor *self,
9540 const ClutterSize *size)
9544 clutter_actor_set_width_internal (self, size->width);
9545 clutter_actor_set_height_internal (self, size->height);
9549 clutter_actor_set_width_internal (self, -1);
9550 clutter_actor_set_height_internal (self, -1);
9555 * clutter_actor_set_size:
9556 * @self: A #ClutterActor
9557 * @width: New width of actor in pixels, or -1
9558 * @height: New height of actor in pixels, or -1
9560 * Sets the actor's size request in pixels. This overrides any
9561 * "normal" size request the actor would have. For example
9562 * a text actor might normally request the size of the text;
9563 * this function would force a specific size instead.
9565 * If @width and/or @height are -1 the actor will use its
9566 * "normal" size request instead of overriding it, i.e.
9567 * you can "unset" the size with -1.
9569 * This function sets or unsets both the minimum and natural size.
9572 clutter_actor_set_size (ClutterActor *self,
9576 ClutterSize new_size;
9578 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9580 clutter_size_init (&new_size, width, height);
9582 if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9584 /* minor optimization: if we don't have a duration then we can
9585 * skip the get_size() below, to avoid the chance of going through
9586 * get_preferred_width() and get_preferred_height() just to jump to
9587 * a new desired size
9589 if (clutter_actor_get_easing_duration (self) == 0)
9591 g_object_freeze_notify (G_OBJECT (self));
9593 clutter_actor_set_size_internal (self, &new_size);
9595 g_object_thaw_notify (G_OBJECT (self));
9601 ClutterSize cur_size;
9603 clutter_size_init (&cur_size,
9604 clutter_actor_get_width (self),
9605 clutter_actor_get_height (self));
9607 _clutter_actor_create_transition (self,
9608 obj_props[PROP_SIZE],
9614 _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9616 clutter_actor_queue_relayout (self);
9620 * clutter_actor_get_size:
9621 * @self: A #ClutterActor
9622 * @width: (out) (allow-none): return location for the width, or %NULL.
9623 * @height: (out) (allow-none): return location for the height, or %NULL.
9625 * This function tries to "do what you mean" and return
9626 * the size an actor will have. If the actor has a valid
9627 * allocation, the allocation will be returned; otherwise,
9628 * the actors natural size request will be returned.
9630 * If you care whether you get the request vs. the allocation, you
9631 * should probably call a different function like
9632 * clutter_actor_get_allocation_box() or
9633 * clutter_actor_get_preferred_width().
9638 clutter_actor_get_size (ClutterActor *self,
9642 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9645 *width = clutter_actor_get_width (self);
9648 *height = clutter_actor_get_height (self);
9652 * clutter_actor_get_position:
9653 * @self: a #ClutterActor
9654 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9655 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9657 * This function tries to "do what you mean" and tell you where the
9658 * actor is, prior to any transformations. Retrieves the fixed
9659 * position of an actor in pixels, if one has been set; otherwise, if
9660 * the allocation is valid, returns the actor's allocated position;
9661 * otherwise, returns 0,0.
9663 * The returned position is in pixels.
9668 clutter_actor_get_position (ClutterActor *self,
9672 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9675 *x = clutter_actor_get_x (self);
9678 *y = clutter_actor_get_y (self);
9682 * clutter_actor_get_transformed_position:
9683 * @self: A #ClutterActor
9684 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9685 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9687 * Gets the absolute position of an actor, in pixels relative to the stage.
9692 clutter_actor_get_transformed_position (ClutterActor *self,
9699 v1.x = v1.y = v1.z = 0;
9700 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9710 * clutter_actor_get_transformed_size:
9711 * @self: A #ClutterActor
9712 * @width: (out) (allow-none): return location for the width, or %NULL
9713 * @height: (out) (allow-none): return location for the height, or %NULL
9715 * Gets the absolute size of an actor in pixels, taking into account the
9718 * If the actor has a valid allocation, the allocated size will be used.
9719 * If the actor has not a valid allocation then the preferred size will
9720 * be transformed and returned.
9722 * If you want the transformed allocation, see
9723 * clutter_actor_get_abs_allocation_vertices() instead.
9725 * <note>When the actor (or one of its ancestors) is rotated around the
9726 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9727 * as a generic quadrangle; in that case this function returns the size
9728 * of the smallest rectangle that encapsulates the entire quad. Please
9729 * note that in this case no assumptions can be made about the relative
9730 * position of this envelope to the absolute position of the actor, as
9731 * returned by clutter_actor_get_transformed_position(); if you need this
9732 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9733 * to get the coords of the actual quadrangle.</note>
9738 clutter_actor_get_transformed_size (ClutterActor *self,
9742 ClutterActorPrivate *priv;
9744 gfloat x_min, x_max, y_min, y_max;
9747 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9751 /* if the actor hasn't been allocated yet, get the preferred
9752 * size and transform that
9754 if (priv->needs_allocation)
9756 gfloat natural_width, natural_height;
9757 ClutterActorBox box;
9759 /* Make a fake allocation to transform.
9761 * NB: _clutter_actor_transform_and_project_box expects a box in
9762 * the actor's coordinate space... */
9767 natural_width = natural_height = 0;
9768 clutter_actor_get_preferred_size (self, NULL, NULL,
9772 box.x2 = natural_width;
9773 box.y2 = natural_height;
9775 _clutter_actor_transform_and_project_box (self, &box, v);
9778 clutter_actor_get_abs_allocation_vertices (self, v);
9780 x_min = x_max = v[0].x;
9781 y_min = y_max = v[0].y;
9783 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9799 *width = x_max - x_min;
9802 *height = y_max - y_min;
9806 * clutter_actor_get_width:
9807 * @self: A #ClutterActor
9809 * Retrieves the width of a #ClutterActor.
9811 * If the actor has a valid allocation, this function will return the
9812 * width of the allocated area given to the actor.
9814 * If the actor does not have a valid allocation, this function will
9815 * return the actor's natural width, that is the preferred width of
9818 * If you care whether you get the preferred width or the width that
9819 * has been assigned to the actor, you should probably call a different
9820 * function like clutter_actor_get_allocation_box() to retrieve the
9821 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9824 * If an actor has a fixed width, for instance a width that has been
9825 * assigned using clutter_actor_set_width(), the width returned will
9826 * be the same value.
9828 * Return value: the width of the actor, in pixels
9831 clutter_actor_get_width (ClutterActor *self)
9833 ClutterActorPrivate *priv;
9835 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9839 if (priv->needs_allocation)
9841 gfloat natural_width = 0;
9843 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9844 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9847 gfloat natural_height = 0;
9849 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9850 clutter_actor_get_preferred_width (self, natural_height,
9855 return natural_width;
9858 return priv->allocation.x2 - priv->allocation.x1;
9862 * clutter_actor_get_height:
9863 * @self: A #ClutterActor
9865 * Retrieves the height of a #ClutterActor.
9867 * If the actor has a valid allocation, this function will return the
9868 * height of the allocated area given to the actor.
9870 * If the actor does not have a valid allocation, this function will
9871 * return the actor's natural height, that is the preferred height of
9874 * If you care whether you get the preferred height or the height that
9875 * has been assigned to the actor, you should probably call a different
9876 * function like clutter_actor_get_allocation_box() to retrieve the
9877 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9880 * If an actor has a fixed height, for instance a height that has been
9881 * assigned using clutter_actor_set_height(), the height returned will
9882 * be the same value.
9884 * Return value: the height of the actor, in pixels
9887 clutter_actor_get_height (ClutterActor *self)
9889 ClutterActorPrivate *priv;
9891 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9895 if (priv->needs_allocation)
9897 gfloat natural_height = 0;
9899 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9901 gfloat natural_width = 0;
9903 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9904 clutter_actor_get_preferred_height (self, natural_width,
9905 NULL, &natural_height);
9908 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9910 return natural_height;
9913 return priv->allocation.y2 - priv->allocation.y1;
9917 * clutter_actor_set_width:
9918 * @self: A #ClutterActor
9919 * @width: Requested new width for the actor, in pixels, or -1
9921 * Forces a width on an actor, causing the actor's preferred width
9922 * and height (if any) to be ignored.
9924 * If @width is -1 the actor will use its preferred width request
9925 * instead of overriding it, i.e. you can "unset" the width with -1.
9927 * This function sets both the minimum and natural size of the actor.
9932 clutter_actor_set_width (ClutterActor *self,
9935 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9937 if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9941 /* minor optimization: if we don't have a duration
9942 * then we can skip the get_width() below, to avoid
9943 * the chance of going through get_preferred_width()
9944 * just to jump to a new desired width.
9946 if (clutter_actor_get_easing_duration (self) == 0)
9948 g_object_freeze_notify (G_OBJECT (self));
9950 clutter_actor_set_width_internal (self, width);
9952 g_object_thaw_notify (G_OBJECT (self));
9957 cur_size = clutter_actor_get_width (self);
9959 _clutter_actor_create_transition (self,
9960 obj_props[PROP_WIDTH],
9965 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9969 * clutter_actor_set_height:
9970 * @self: A #ClutterActor
9971 * @height: Requested new height for the actor, in pixels, or -1
9973 * Forces a height on an actor, causing the actor's preferred width
9974 * and height (if any) to be ignored.
9976 * If @height is -1 the actor will use its preferred height instead of
9977 * overriding it, i.e. you can "unset" the height with -1.
9979 * This function sets both the minimum and natural size of the actor.
9984 clutter_actor_set_height (ClutterActor *self,
9987 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9989 if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9993 /* see the comment in clutter_actor_set_width() above */
9994 if (clutter_actor_get_easing_duration (self) == 0)
9996 g_object_freeze_notify (G_OBJECT (self));
9998 clutter_actor_set_height_internal (self, height);
10000 g_object_thaw_notify (G_OBJECT (self));
10005 cur_size = clutter_actor_get_height (self);
10007 _clutter_actor_create_transition (self,
10008 obj_props[PROP_HEIGHT],
10013 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
10017 clutter_actor_set_x_internal (ClutterActor *self,
10020 ClutterActorPrivate *priv = self->priv;
10021 ClutterLayoutInfo *linfo;
10022 ClutterActorBox old = { 0, };
10024 linfo = _clutter_actor_get_layout_info (self);
10026 if (priv->position_set && linfo->fixed_pos.x == x)
10029 clutter_actor_store_old_geometry (self, &old);
10031 linfo->fixed_pos.x = x;
10032 clutter_actor_set_fixed_position_set (self, TRUE);
10034 clutter_actor_notify_if_geometry_changed (self, &old);
10036 clutter_actor_queue_relayout (self);
10040 clutter_actor_set_y_internal (ClutterActor *self,
10043 ClutterActorPrivate *priv = self->priv;
10044 ClutterLayoutInfo *linfo;
10045 ClutterActorBox old = { 0, };
10047 linfo = _clutter_actor_get_layout_info (self);
10049 if (priv->position_set && linfo->fixed_pos.y == y)
10052 clutter_actor_store_old_geometry (self, &old);
10054 linfo->fixed_pos.y = y;
10055 clutter_actor_set_fixed_position_set (self, TRUE);
10057 clutter_actor_notify_if_geometry_changed (self, &old);
10059 clutter_actor_queue_relayout (self);
10063 clutter_actor_set_position_internal (ClutterActor *self,
10064 const ClutterPoint *position)
10066 ClutterActorPrivate *priv = self->priv;
10067 ClutterLayoutInfo *linfo;
10068 ClutterActorBox old = { 0, };
10070 linfo = _clutter_actor_get_layout_info (self);
10072 if (priv->position_set &&
10073 clutter_point_equals (position, &linfo->fixed_pos))
10076 clutter_actor_store_old_geometry (self, &old);
10078 if (position != NULL)
10080 linfo->fixed_pos = *position;
10081 clutter_actor_set_fixed_position_set (self, TRUE);
10084 clutter_actor_set_fixed_position_set (self, FALSE);
10086 clutter_actor_notify_if_geometry_changed (self, &old);
10088 clutter_actor_queue_relayout (self);
10092 * clutter_actor_set_x:
10093 * @self: a #ClutterActor
10094 * @x: the actor's position on the X axis
10096 * Sets the actor's X coordinate, relative to its parent, in pixels.
10098 * Overrides any layout manager and forces a fixed position for
10101 * The #ClutterActor:x property is animatable.
10106 clutter_actor_set_x (ClutterActor *self,
10109 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10111 if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
10113 float cur_position = clutter_actor_get_x (self);
10115 _clutter_actor_create_transition (self, obj_props[PROP_X],
10120 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
10124 * clutter_actor_set_y:
10125 * @self: a #ClutterActor
10126 * @y: the actor's position on the Y axis
10128 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
10130 * Overrides any layout manager and forces a fixed position for
10133 * The #ClutterActor:y property is animatable.
10138 clutter_actor_set_y (ClutterActor *self,
10141 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10143 if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
10145 float cur_position = clutter_actor_get_y (self);
10147 _clutter_actor_create_transition (self, obj_props[PROP_Y],
10152 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
10156 * clutter_actor_get_x:
10157 * @self: A #ClutterActor
10159 * Retrieves the X coordinate of a #ClutterActor.
10161 * This function tries to "do what you mean", by returning the
10162 * correct value depending on the actor's state.
10164 * If the actor has a valid allocation, this function will return
10165 * the X coordinate of the origin of the allocation box.
10167 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10168 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10169 * function will return that coordinate.
10171 * If both the allocation and a fixed position are missing, this function
10174 * Return value: the X coordinate, in pixels, ignoring any
10175 * transformation (i.e. scaling, rotation)
10178 clutter_actor_get_x (ClutterActor *self)
10180 ClutterActorPrivate *priv;
10182 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10186 if (priv->needs_allocation)
10188 if (priv->position_set)
10190 const ClutterLayoutInfo *info;
10192 info = _clutter_actor_get_layout_info_or_defaults (self);
10194 return info->fixed_pos.x;
10200 return priv->allocation.x1;
10204 * clutter_actor_get_y:
10205 * @self: A #ClutterActor
10207 * Retrieves the Y coordinate of a #ClutterActor.
10209 * This function tries to "do what you mean", by returning the
10210 * correct value depending on the actor's state.
10212 * If the actor has a valid allocation, this function will return
10213 * the Y coordinate of the origin of the allocation box.
10215 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10216 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10217 * function will return that coordinate.
10219 * If both the allocation and a fixed position are missing, this function
10222 * Return value: the Y coordinate, in pixels, ignoring any
10223 * transformation (i.e. scaling, rotation)
10226 clutter_actor_get_y (ClutterActor *self)
10228 ClutterActorPrivate *priv;
10230 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10234 if (priv->needs_allocation)
10236 if (priv->position_set)
10238 const ClutterLayoutInfo *info;
10240 info = _clutter_actor_get_layout_info_or_defaults (self);
10242 return info->fixed_pos.y;
10248 return priv->allocation.y1;
10252 * clutter_actor_set_scale:
10253 * @self: A #ClutterActor
10254 * @scale_x: double factor to scale actor by horizontally.
10255 * @scale_y: double factor to scale actor by vertically.
10257 * Scales an actor with the given factors. The scaling is relative to
10258 * the scale center and the anchor point. The scale center is
10259 * unchanged by this function and defaults to 0,0.
10261 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10267 clutter_actor_set_scale (ClutterActor *self,
10271 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10273 g_object_freeze_notify (G_OBJECT (self));
10275 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10276 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10278 g_object_thaw_notify (G_OBJECT (self));
10282 * clutter_actor_set_scale_full:
10283 * @self: A #ClutterActor
10284 * @scale_x: double factor to scale actor by horizontally.
10285 * @scale_y: double factor to scale actor by vertically.
10286 * @center_x: X coordinate of the center of the scale.
10287 * @center_y: Y coordinate of the center of the scale
10289 * Scales an actor with the given factors around the given center
10290 * point. The center point is specified in pixels relative to the
10291 * anchor point (usually the top left corner of the actor).
10293 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10299 clutter_actor_set_scale_full (ClutterActor *self,
10305 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10307 g_object_freeze_notify (G_OBJECT (self));
10309 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10310 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10311 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10312 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10314 g_object_thaw_notify (G_OBJECT (self));
10318 * clutter_actor_set_scale_with_gravity:
10319 * @self: A #ClutterActor
10320 * @scale_x: double factor to scale actor by horizontally.
10321 * @scale_y: double factor to scale actor by vertically.
10322 * @gravity: the location of the scale center expressed as a compass
10325 * Scales an actor with the given factors around the given
10326 * center point. The center point is specified as one of the compass
10327 * directions in #ClutterGravity. For example, setting it to north
10328 * will cause the top of the actor to remain unchanged and the rest of
10329 * the actor to expand left, right and downwards.
10331 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10337 clutter_actor_set_scale_with_gravity (ClutterActor *self,
10340 ClutterGravity gravity)
10342 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10344 g_object_freeze_notify (G_OBJECT (self));
10346 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10347 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10348 clutter_actor_set_scale_gravity (self, gravity);
10350 g_object_thaw_notify (G_OBJECT (self));
10354 * clutter_actor_get_scale:
10355 * @self: A #ClutterActor
10356 * @scale_x: (out) (allow-none): Location to store horizonal
10357 * scale factor, or %NULL.
10358 * @scale_y: (out) (allow-none): Location to store vertical
10359 * scale factor, or %NULL.
10361 * Retrieves an actors scale factors.
10366 clutter_actor_get_scale (ClutterActor *self,
10370 const ClutterTransformInfo *info;
10372 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10374 info = _clutter_actor_get_transform_info_or_defaults (self);
10377 *scale_x = info->scale_x;
10380 *scale_y = info->scale_y;
10384 * clutter_actor_get_scale_center:
10385 * @self: A #ClutterActor
10386 * @center_x: (out) (allow-none): Location to store the X position
10387 * of the scale center, or %NULL.
10388 * @center_y: (out) (allow-none): Location to store the Y position
10389 * of the scale center, or %NULL.
10391 * Retrieves the scale center coordinate in pixels relative to the top
10392 * left corner of the actor. If the scale center was specified using a
10393 * #ClutterGravity this will calculate the pixel offset using the
10394 * current size of the actor.
10399 clutter_actor_get_scale_center (ClutterActor *self,
10403 const ClutterTransformInfo *info;
10405 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10407 info = _clutter_actor_get_transform_info_or_defaults (self);
10409 clutter_anchor_coord_get_units (self, &info->scale_center,
10416 * clutter_actor_get_scale_gravity:
10417 * @self: A #ClutterActor
10419 * Retrieves the scale center as a compass direction. If the scale
10420 * center was specified in pixels or units this will return
10421 * %CLUTTER_GRAVITY_NONE.
10423 * Return value: the scale gravity
10428 clutter_actor_get_scale_gravity (ClutterActor *self)
10430 const ClutterTransformInfo *info;
10432 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10434 info = _clutter_actor_get_transform_info_or_defaults (self);
10436 return clutter_anchor_coord_get_gravity (&info->scale_center);
10440 clutter_actor_set_opacity_internal (ClutterActor *self,
10443 ClutterActorPrivate *priv = self->priv;
10445 if (priv->opacity != opacity)
10447 priv->opacity = opacity;
10449 /* Queue a redraw from the flatten effect so that it can use
10450 its cached image if available instead of having to redraw the
10451 actual actor. If it doesn't end up using the FBO then the
10452 effect is still able to continue the paint anyway. If there
10453 is no flatten effect yet then this is equivalent to queueing
10455 _clutter_actor_queue_redraw_full (self,
10458 priv->flatten_effect);
10460 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10465 * clutter_actor_set_opacity:
10466 * @self: A #ClutterActor
10467 * @opacity: New opacity value for the actor.
10469 * Sets the actor's opacity, with zero being completely transparent and
10470 * 255 (0xff) being fully opaque.
10472 * The #ClutterActor:opacity property is animatable.
10475 clutter_actor_set_opacity (ClutterActor *self,
10478 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10480 if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10482 _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10483 self->priv->opacity,
10487 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10491 * clutter_actor_get_paint_opacity_internal:
10492 * @self: a #ClutterActor
10494 * Retrieves the absolute opacity of the actor, as it appears on the stage
10496 * This function does not do type checks
10498 * Return value: the absolute opacity of the actor
10501 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10503 ClutterActorPrivate *priv = self->priv;
10504 ClutterActor *parent;
10506 /* override the top-level opacity to always be 255; even in
10507 * case of ClutterStage:use-alpha being TRUE we want the rest
10508 * of the scene to be painted
10510 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10513 if (priv->opacity_override >= 0)
10514 return priv->opacity_override;
10516 parent = priv->parent;
10518 /* Factor in the actual actors opacity with parents */
10519 if (parent != NULL)
10521 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10523 if (opacity != 0xff)
10524 return (opacity * priv->opacity) / 0xff;
10527 return priv->opacity;
10532 * clutter_actor_get_paint_opacity:
10533 * @self: A #ClutterActor
10535 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10537 * This function traverses the hierarchy chain and composites the opacity of
10538 * the actor with that of its parents.
10540 * This function is intended for subclasses to use in the paint virtual
10541 * function, to paint themselves with the correct opacity.
10543 * Return value: The actor opacity value.
10548 clutter_actor_get_paint_opacity (ClutterActor *self)
10550 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10552 return clutter_actor_get_paint_opacity_internal (self);
10556 * clutter_actor_get_opacity:
10557 * @self: a #ClutterActor
10559 * Retrieves the opacity value of an actor, as set by
10560 * clutter_actor_set_opacity().
10562 * For retrieving the absolute opacity of the actor inside a paint
10563 * virtual function, see clutter_actor_get_paint_opacity().
10565 * Return value: the opacity of the actor
10568 clutter_actor_get_opacity (ClutterActor *self)
10570 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10572 return self->priv->opacity;
10576 * clutter_actor_set_offscreen_redirect:
10577 * @self: A #ClutterActor
10578 * @redirect: New offscreen redirect flags for the actor.
10580 * Defines the circumstances where the actor should be redirected into
10581 * an offscreen image. The offscreen image is used to flatten the
10582 * actor into a single image while painting for two main reasons.
10583 * Firstly, when the actor is painted a second time without any of its
10584 * contents changing it can simply repaint the cached image without
10585 * descending further down the actor hierarchy. Secondly, it will make
10586 * the opacity look correct even if there are overlapping primitives
10589 * Caching the actor could in some cases be a performance win and in
10590 * some cases be a performance lose so it is important to determine
10591 * which value is right for an actor before modifying this value. For
10592 * example, there is never any reason to flatten an actor that is just
10593 * a single texture (such as a #ClutterTexture) because it is
10594 * effectively already cached in an image so the offscreen would be
10595 * redundant. Also if the actor contains primitives that are far apart
10596 * with a large transparent area in the middle (such as a large
10597 * CluterGroup with a small actor in the top left and a small actor in
10598 * the bottom right) then the cached image will contain the entire
10599 * image of the large area and the paint will waste time blending all
10600 * of the transparent pixels in the middle.
10602 * The default method of implementing opacity on a container simply
10603 * forwards on the opacity to all of the children. If the children are
10604 * overlapping then it will appear as if they are two separate glassy
10605 * objects and there will be a break in the color where they
10606 * overlap. By redirecting to an offscreen buffer it will be as if the
10607 * two opaque objects are combined into one and then made transparent
10608 * which is usually what is expected.
10610 * The image below demonstrates the difference between redirecting and
10611 * not. The image shows two Clutter groups, each containing a red and
10612 * a green rectangle which overlap. The opacity on the group is set to
10613 * 128 (which is 50%). When the offscreen redirect is not used, the
10614 * red rectangle can be seen through the blue rectangle as if the two
10615 * rectangles were separately transparent. When the redirect is used
10616 * the group as a whole is transparent instead so the red rectangle is
10617 * not visible where they overlap.
10619 * <figure id="offscreen-redirect">
10620 * <title>Sample of using an offscreen redirect for transparency</title>
10621 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10624 * The default value for this property is 0, so we effectively will
10625 * never redirect an actor offscreen by default. This means that there
10626 * are times that transparent actors may look glassy as described
10627 * above. The reason this is the default is because there is a
10628 * performance trade off between quality and performance here. In many
10629 * cases the default form of glassy opacity looks good enough, but if
10630 * it's not you will need to set the
10631 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10632 * redirection for opacity.
10634 * Custom actors that don't contain any overlapping primitives are
10635 * recommended to override the has_overlaps() virtual to return %FALSE
10636 * for maximum efficiency.
10641 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10642 ClutterOffscreenRedirect redirect)
10644 ClutterActorPrivate *priv;
10646 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10650 if (priv->offscreen_redirect != redirect)
10652 priv->offscreen_redirect = redirect;
10654 /* Queue a redraw from the effect so that it can use its cached
10655 image if available instead of having to redraw the actual
10656 actor. If it doesn't end up using the FBO then the effect is
10657 still able to continue the paint anyway. If there is no
10658 effect then this is equivalent to queuing a full redraw */
10659 _clutter_actor_queue_redraw_full (self,
10662 priv->flatten_effect);
10664 g_object_notify_by_pspec (G_OBJECT (self),
10665 obj_props[PROP_OFFSCREEN_REDIRECT]);
10670 * clutter_actor_get_offscreen_redirect:
10671 * @self: a #ClutterActor
10673 * Retrieves whether to redirect the actor to an offscreen buffer, as
10674 * set by clutter_actor_set_offscreen_redirect().
10676 * Return value: the value of the offscreen-redirect property of the actor
10680 ClutterOffscreenRedirect
10681 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10683 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10685 return self->priv->offscreen_redirect;
10689 * clutter_actor_set_name:
10690 * @self: A #ClutterActor
10691 * @name: Textual tag to apply to actor
10693 * Sets the given name to @self. The name can be used to identify
10697 clutter_actor_set_name (ClutterActor *self,
10700 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10702 g_free (self->priv->name);
10703 self->priv->name = g_strdup (name);
10705 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10709 * clutter_actor_get_name:
10710 * @self: A #ClutterActor
10712 * Retrieves the name of @self.
10714 * Return value: the name of the actor, or %NULL. The returned string is
10715 * owned by the actor and should not be modified or freed.
10718 clutter_actor_get_name (ClutterActor *self)
10720 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10722 return self->priv->name;
10726 * clutter_actor_get_gid:
10727 * @self: A #ClutterActor
10729 * Retrieves the unique id for @self.
10731 * Return value: Globally unique value for this object instance.
10735 * Deprecated: 1.8: The id is not used any longer.
10738 clutter_actor_get_gid (ClutterActor *self)
10740 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10742 return self->priv->id;
10746 clutter_actor_set_depth_internal (ClutterActor *self,
10749 ClutterTransformInfo *info;
10751 info = _clutter_actor_get_transform_info (self);
10753 if (info->depth != depth)
10755 /* Sets Z value - XXX 2.0: should we invert? */
10756 info->depth = depth;
10758 self->priv->transform_valid = FALSE;
10760 /* FIXME - remove this crap; sadly, there are still containers
10761 * in Clutter that depend on this utter brain damage
10763 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10765 clutter_actor_queue_redraw (self);
10767 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10772 * clutter_actor_set_depth:
10773 * @self: a #ClutterActor
10776 * Sets the Z coordinate of @self to @depth.
10778 * The unit used by @depth is dependant on the perspective setup. See
10779 * also clutter_stage_set_perspective().
10782 clutter_actor_set_depth (ClutterActor *self,
10785 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10787 if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10789 const ClutterTransformInfo *info;
10791 info = _clutter_actor_get_transform_info_or_defaults (self);
10793 _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10798 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10800 clutter_actor_queue_redraw (self);
10804 * clutter_actor_get_depth:
10805 * @self: a #ClutterActor
10807 * Retrieves the depth of @self.
10809 * Return value: the depth of the actor
10812 clutter_actor_get_depth (ClutterActor *self)
10814 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10816 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10820 * clutter_actor_set_rotation:
10821 * @self: a #ClutterActor
10822 * @axis: the axis of rotation
10823 * @angle: the angle of rotation
10824 * @x: X coordinate of the rotation center
10825 * @y: Y coordinate of the rotation center
10826 * @z: Z coordinate of the rotation center
10828 * Sets the rotation angle of @self around the given axis.
10830 * The rotation center coordinates used depend on the value of @axis:
10832 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10833 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10834 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10837 * The rotation coordinates are relative to the anchor point of the
10838 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10839 * point is set, the upper left corner is assumed as the origin.
10844 clutter_actor_set_rotation (ClutterActor *self,
10845 ClutterRotateAxis axis,
10853 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10859 g_object_freeze_notify (G_OBJECT (self));
10861 clutter_actor_set_rotation_angle (self, axis, angle);
10862 clutter_actor_set_rotation_center_internal (self, axis, &v);
10864 g_object_thaw_notify (G_OBJECT (self));
10868 * clutter_actor_set_z_rotation_from_gravity:
10869 * @self: a #ClutterActor
10870 * @angle: the angle of rotation
10871 * @gravity: the center point of the rotation
10873 * Sets the rotation angle of @self around the Z axis using the center
10874 * point specified as a compass point. For example to rotate such that
10875 * the center of the actor remains static you can use
10876 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10877 * will move accordingly.
10882 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10884 ClutterGravity gravity)
10886 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10888 if (gravity == CLUTTER_GRAVITY_NONE)
10889 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10892 GObject *obj = G_OBJECT (self);
10893 ClutterTransformInfo *info;
10895 info = _clutter_actor_get_transform_info (self);
10897 g_object_freeze_notify (obj);
10899 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10901 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10902 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10903 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10905 g_object_thaw_notify (obj);
10910 * clutter_actor_get_rotation:
10911 * @self: a #ClutterActor
10912 * @axis: the axis of rotation
10913 * @x: (out): return value for the X coordinate of the center of rotation
10914 * @y: (out): return value for the Y coordinate of the center of rotation
10915 * @z: (out): return value for the Z coordinate of the center of rotation
10917 * Retrieves the angle and center of rotation on the given axis,
10918 * set using clutter_actor_set_rotation().
10920 * Return value: the angle of rotation
10925 clutter_actor_get_rotation (ClutterActor *self,
10926 ClutterRotateAxis axis,
10931 const ClutterTransformInfo *info;
10932 const AnchorCoord *anchor_coord;
10933 gdouble retval = 0;
10935 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10937 info = _clutter_actor_get_transform_info_or_defaults (self);
10941 case CLUTTER_X_AXIS:
10942 anchor_coord = &info->rx_center;
10943 retval = info->rx_angle;
10946 case CLUTTER_Y_AXIS:
10947 anchor_coord = &info->ry_center;
10948 retval = info->ry_angle;
10951 case CLUTTER_Z_AXIS:
10952 anchor_coord = &info->rz_center;
10953 retval = info->rz_angle;
10957 anchor_coord = NULL;
10962 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10968 * clutter_actor_get_z_rotation_gravity:
10969 * @self: A #ClutterActor
10971 * Retrieves the center for the rotation around the Z axis as a
10972 * compass direction. If the center was specified in pixels or units
10973 * this will return %CLUTTER_GRAVITY_NONE.
10975 * Return value: the Z rotation center
10980 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10982 const ClutterTransformInfo *info;
10984 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10986 info = _clutter_actor_get_transform_info_or_defaults (self);
10988 return clutter_anchor_coord_get_gravity (&info->rz_center);
10992 * clutter_actor_set_clip:
10993 * @self: A #ClutterActor
10994 * @xoff: X offset of the clip rectangle
10995 * @yoff: Y offset of the clip rectangle
10996 * @width: Width of the clip rectangle
10997 * @height: Height of the clip rectangle
10999 * Sets clip area for @self. The clip area is always computed from the
11000 * upper left corner of the actor, even if the anchor point is set
11006 clutter_actor_set_clip (ClutterActor *self,
11012 ClutterActorPrivate *priv;
11014 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11018 if (priv->has_clip &&
11019 priv->clip.x == xoff &&
11020 priv->clip.y == yoff &&
11021 priv->clip.width == width &&
11022 priv->clip.height == height)
11025 priv->clip.x = xoff;
11026 priv->clip.y = yoff;
11027 priv->clip.width = width;
11028 priv->clip.height = height;
11030 priv->has_clip = TRUE;
11032 clutter_actor_queue_redraw (self);
11034 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
11035 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
11039 * clutter_actor_remove_clip:
11040 * @self: A #ClutterActor
11042 * Removes clip area from @self.
11045 clutter_actor_remove_clip (ClutterActor *self)
11047 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11049 if (!self->priv->has_clip)
11052 self->priv->has_clip = FALSE;
11054 clutter_actor_queue_redraw (self);
11056 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
11060 * clutter_actor_has_clip:
11061 * @self: a #ClutterActor
11063 * Determines whether the actor has a clip area set or not.
11065 * Return value: %TRUE if the actor has a clip area set.
11070 clutter_actor_has_clip (ClutterActor *self)
11072 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11074 return self->priv->has_clip;
11078 * clutter_actor_get_clip:
11079 * @self: a #ClutterActor
11080 * @xoff: (out) (allow-none): return location for the X offset of
11081 * the clip rectangle, or %NULL
11082 * @yoff: (out) (allow-none): return location for the Y offset of
11083 * the clip rectangle, or %NULL
11084 * @width: (out) (allow-none): return location for the width of
11085 * the clip rectangle, or %NULL
11086 * @height: (out) (allow-none): return location for the height of
11087 * the clip rectangle, or %NULL
11089 * Gets the clip area for @self, if any is set
11094 clutter_actor_get_clip (ClutterActor *self,
11100 ClutterActorPrivate *priv;
11102 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11106 if (!priv->has_clip)
11110 *xoff = priv->clip.x;
11113 *yoff = priv->clip.y;
11116 *width = priv->clip.width;
11118 if (height != NULL)
11119 *height = priv->clip.height;
11123 * clutter_actor_get_children:
11124 * @self: a #ClutterActor
11126 * Retrieves the list of children of @self.
11128 * Return value: (transfer container) (element-type ClutterActor): A newly
11129 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
11135 clutter_actor_get_children (ClutterActor *self)
11137 ClutterActor *iter;
11140 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11142 /* we walk the list backward so that we can use prepend(),
11145 for (iter = self->priv->last_child, res = NULL;
11147 iter = iter->priv->prev_sibling)
11149 res = g_list_prepend (res, iter);
11156 * insert_child_at_depth:
11157 * @self: a #ClutterActor
11158 * @child: a #ClutterActor
11160 * Inserts @child inside the list of children held by @self, using
11161 * the depth as the insertion criteria.
11163 * This sadly makes the insertion not O(1), but we can keep the
11164 * list sorted so that the painters algorithm we use for painting
11165 * the children will work correctly.
11168 insert_child_at_depth (ClutterActor *self,
11169 ClutterActor *child,
11170 gpointer dummy G_GNUC_UNUSED)
11172 ClutterActor *iter;
11175 child->priv->parent = self;
11178 _clutter_actor_get_transform_info_or_defaults (child)->depth;
11180 /* special-case the first child */
11181 if (self->priv->n_children == 0)
11183 self->priv->first_child = child;
11184 self->priv->last_child = child;
11186 child->priv->next_sibling = NULL;
11187 child->priv->prev_sibling = NULL;
11192 /* Find the right place to insert the child so that it will still be
11193 sorted and the child will be after all of the actors at the same
11195 for (iter = self->priv->first_child;
11197 iter = iter->priv->next_sibling)
11202 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11204 if (iter_depth > child_depth)
11210 ClutterActor *tmp = iter->priv->prev_sibling;
11213 tmp->priv->next_sibling = child;
11215 /* Insert the node before the found one */
11216 child->priv->prev_sibling = iter->priv->prev_sibling;
11217 child->priv->next_sibling = iter;
11218 iter->priv->prev_sibling = child;
11222 ClutterActor *tmp = self->priv->last_child;
11225 tmp->priv->next_sibling = child;
11227 /* insert the node at the end of the list */
11228 child->priv->prev_sibling = self->priv->last_child;
11229 child->priv->next_sibling = NULL;
11232 if (child->priv->prev_sibling == NULL)
11233 self->priv->first_child = child;
11235 if (child->priv->next_sibling == NULL)
11236 self->priv->last_child = child;
11240 insert_child_at_index (ClutterActor *self,
11241 ClutterActor *child,
11244 gint index_ = GPOINTER_TO_INT (data_);
11246 child->priv->parent = self;
11250 ClutterActor *tmp = self->priv->first_child;
11253 tmp->priv->prev_sibling = child;
11255 child->priv->prev_sibling = NULL;
11256 child->priv->next_sibling = tmp;
11258 else if (index_ < 0 || index_ >= self->priv->n_children)
11260 ClutterActor *tmp = self->priv->last_child;
11263 tmp->priv->next_sibling = child;
11265 child->priv->prev_sibling = tmp;
11266 child->priv->next_sibling = NULL;
11270 ClutterActor *iter;
11273 for (iter = self->priv->first_child, i = 0;
11275 iter = iter->priv->next_sibling, i += 1)
11279 ClutterActor *tmp = iter->priv->prev_sibling;
11281 child->priv->prev_sibling = tmp;
11282 child->priv->next_sibling = iter;
11284 iter->priv->prev_sibling = child;
11287 tmp->priv->next_sibling = child;
11294 if (child->priv->prev_sibling == NULL)
11295 self->priv->first_child = child;
11297 if (child->priv->next_sibling == NULL)
11298 self->priv->last_child = child;
11302 insert_child_above (ClutterActor *self,
11303 ClutterActor *child,
11306 ClutterActor *sibling = data;
11308 child->priv->parent = self;
11310 if (sibling == NULL)
11311 sibling = self->priv->last_child;
11313 child->priv->prev_sibling = sibling;
11315 if (sibling != NULL)
11317 ClutterActor *tmp = sibling->priv->next_sibling;
11319 child->priv->next_sibling = tmp;
11322 tmp->priv->prev_sibling = child;
11324 sibling->priv->next_sibling = child;
11327 child->priv->next_sibling = NULL;
11329 if (child->priv->prev_sibling == NULL)
11330 self->priv->first_child = child;
11332 if (child->priv->next_sibling == NULL)
11333 self->priv->last_child = child;
11337 insert_child_below (ClutterActor *self,
11338 ClutterActor *child,
11341 ClutterActor *sibling = data;
11343 child->priv->parent = self;
11345 if (sibling == NULL)
11346 sibling = self->priv->first_child;
11348 child->priv->next_sibling = sibling;
11350 if (sibling != NULL)
11352 ClutterActor *tmp = sibling->priv->prev_sibling;
11354 child->priv->prev_sibling = tmp;
11357 tmp->priv->next_sibling = child;
11359 sibling->priv->prev_sibling = child;
11362 child->priv->prev_sibling = NULL;
11364 if (child->priv->prev_sibling == NULL)
11365 self->priv->first_child = child;
11367 if (child->priv->next_sibling == NULL)
11368 self->priv->last_child = child;
11371 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11372 ClutterActor *child,
11376 ADD_CHILD_CREATE_META = 1 << 0,
11377 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
11378 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
11379 ADD_CHILD_CHECK_STATE = 1 << 3,
11380 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
11381 ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11383 /* default flags for public API */
11384 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
11385 ADD_CHILD_EMIT_PARENT_SET |
11386 ADD_CHILD_EMIT_ACTOR_ADDED |
11387 ADD_CHILD_CHECK_STATE |
11388 ADD_CHILD_NOTIFY_FIRST_LAST |
11389 ADD_CHILD_SHOW_ON_SET_PARENT,
11391 /* flags for legacy/deprecated API */
11392 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
11393 ADD_CHILD_CHECK_STATE |
11394 ADD_CHILD_NOTIFY_FIRST_LAST |
11395 ADD_CHILD_SHOW_ON_SET_PARENT
11396 } ClutterActorAddChildFlags;
11399 * clutter_actor_add_child_internal:
11400 * @self: a #ClutterActor
11401 * @child: a #ClutterActor
11402 * @flags: control flags for actions
11403 * @add_func: delegate function
11404 * @data: (closure): data to pass to @add_func
11406 * Adds @child to the list of children of @self.
11408 * The actual insertion inside the list is delegated to @add_func: this
11409 * function will just set up the state, perform basic checks, and emit
11412 * The @flags argument is used to perform additional operations.
11415 clutter_actor_add_child_internal (ClutterActor *self,
11416 ClutterActor *child,
11417 ClutterActorAddChildFlags flags,
11418 ClutterActorAddChildFunc add_func,
11421 ClutterTextDirection text_dir;
11422 gboolean create_meta;
11423 gboolean emit_parent_set, emit_actor_added;
11424 gboolean check_state;
11425 gboolean notify_first_last;
11426 gboolean show_on_set_parent;
11427 ClutterActor *old_first_child, *old_last_child;
11429 if (child->priv->parent != NULL)
11431 g_warning ("The actor '%s' already has a parent, '%s'. You must "
11432 "use clutter_actor_remove_child() first.",
11433 _clutter_actor_get_debug_name (child),
11434 _clutter_actor_get_debug_name (child->priv->parent));
11438 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11440 g_warning ("The actor '%s' is a top-level actor, and cannot be "
11441 "a child of another actor.",
11442 _clutter_actor_get_debug_name (child));
11447 /* XXX - this check disallows calling methods that change the stacking
11448 * order within the destruction sequence, by triggering a critical
11449 * warning first, and leaving the actor in an undefined state, which
11450 * then ends up being caught by an assertion.
11452 * the reproducible sequence is:
11454 * - actor gets destroyed;
11455 * - another actor, linked to the first, will try to change the
11456 * stacking order of the first actor;
11457 * - changing the stacking order is a composite operation composed
11458 * by the following steps:
11459 * 1. ref() the child;
11460 * 2. remove_child_internal(), which removes the reference;
11461 * 3. add_child_internal(), which adds a reference;
11462 * - the state of the actor is not changed between (2) and (3), as
11463 * it could be an expensive recomputation;
11464 * - if (3) bails out, then the actor is in an undefined state, but
11466 * - the destruction sequence terminates, but the actor is unparented
11467 * while its state indicates being parented instead.
11468 * - assertion failure.
11470 * the obvious fix would be to decompose each set_child_*_sibling()
11471 * method into proper remove_child()/add_child(), with state validation;
11472 * this may cause excessive work, though, and trigger a cascade of other
11473 * bugs in code that assumes that a change in the stacking order is an
11474 * atomic operation.
11476 * another potential fix is to just remove this check here, and let
11477 * code doing stacking order changes inside the destruction sequence
11478 * of an actor continue doing the work.
11480 * the third fix is to silently bail out early from every
11481 * set_child_*_sibling() and set_child_at_index() method, and avoid
11484 * I have a preference for the second solution, since it involves the
11485 * least amount of work, and the least amount of code duplication.
11487 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11489 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11491 g_warning ("The actor '%s' is currently being destroyed, and "
11492 "cannot be added as a child of another actor.",
11493 _clutter_actor_get_debug_name (child));
11498 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11499 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11500 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11501 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11502 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11503 show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11505 old_first_child = self->priv->first_child;
11506 old_last_child = self->priv->last_child;
11508 g_object_freeze_notify (G_OBJECT (self));
11511 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11513 g_object_ref_sink (child);
11514 child->priv->parent = NULL;
11515 child->priv->next_sibling = NULL;
11516 child->priv->prev_sibling = NULL;
11518 /* delegate the actual insertion */
11519 add_func (self, child, data);
11521 g_assert (child->priv->parent == self);
11523 self->priv->n_children += 1;
11525 self->priv->age += 1;
11527 /* if push_internal() has been called then we automatically set
11528 * the flag on the actor
11530 if (self->priv->internal_child)
11531 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11533 /* children may cause their parent to expand, if they are set
11534 * to expand; if a child is not expanded then it cannot change
11535 * its parent's state. any further change later on will queue
11536 * an expand state check.
11538 * this check, with the initial state of the needs_compute_expand
11539 * flag set to FALSE, should avoid recomputing the expand flags
11540 * state while building the actor tree.
11542 if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11543 (child->priv->needs_compute_expand ||
11544 child->priv->needs_x_expand ||
11545 child->priv->needs_y_expand))
11547 clutter_actor_queue_compute_expand (self);
11550 /* clutter_actor_reparent() will emit ::parent-set for us */
11551 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11552 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11556 /* If parent is mapped or realized, we need to also be mapped or
11557 * realized once we're inside the parent.
11559 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11561 /* propagate the parent's text direction to the child */
11562 text_dir = clutter_actor_get_text_direction (self);
11563 clutter_actor_set_text_direction (child, text_dir);
11566 if (show_on_set_parent && child->priv->show_on_set_parent)
11567 clutter_actor_show (child);
11569 if (CLUTTER_ACTOR_IS_MAPPED (child))
11570 clutter_actor_queue_redraw (child);
11572 /* maintain the invariant that if an actor needs layout,
11573 * its parents do as well
11575 if (child->priv->needs_width_request ||
11576 child->priv->needs_height_request ||
11577 child->priv->needs_allocation)
11579 /* we work around the short-circuiting we do
11580 * in clutter_actor_queue_relayout() since we
11581 * want to force a relayout
11583 child->priv->needs_width_request = TRUE;
11584 child->priv->needs_height_request = TRUE;
11585 child->priv->needs_allocation = TRUE;
11587 clutter_actor_queue_relayout (child->priv->parent);
11590 if (emit_actor_added)
11591 g_signal_emit_by_name (self, "actor-added", child);
11593 if (notify_first_last)
11595 if (old_first_child != self->priv->first_child)
11596 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11598 if (old_last_child != self->priv->last_child)
11599 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11602 g_object_thaw_notify (G_OBJECT (self));
11606 * clutter_actor_add_child:
11607 * @self: a #ClutterActor
11608 * @child: a #ClutterActor
11610 * Adds @child to the children of @self.
11612 * This function will acquire a reference on @child that will only
11613 * be released when calling clutter_actor_remove_child().
11615 * This function will take into consideration the #ClutterActor:depth
11616 * of @child, and will keep the list of children sorted.
11618 * This function will emit the #ClutterContainer::actor-added signal
11624 clutter_actor_add_child (ClutterActor *self,
11625 ClutterActor *child)
11627 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11628 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11629 g_return_if_fail (self != child);
11630 g_return_if_fail (child->priv->parent == NULL);
11632 clutter_actor_add_child_internal (self, child,
11633 ADD_CHILD_DEFAULT_FLAGS,
11634 insert_child_at_depth,
11639 * clutter_actor_insert_child_at_index:
11640 * @self: a #ClutterActor
11641 * @child: a #ClutterActor
11642 * @index_: the index
11644 * Inserts @child into the list of children of @self, using the
11645 * given @index_. If @index_ is greater than the number of children
11646 * in @self, or is less than 0, then the new child is added at the end.
11648 * This function will acquire a reference on @child that will only
11649 * be released when calling clutter_actor_remove_child().
11651 * This function will not take into consideration the #ClutterActor:depth
11654 * This function will emit the #ClutterContainer::actor-added signal
11660 clutter_actor_insert_child_at_index (ClutterActor *self,
11661 ClutterActor *child,
11664 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11665 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11666 g_return_if_fail (self != child);
11667 g_return_if_fail (child->priv->parent == NULL);
11669 clutter_actor_add_child_internal (self, child,
11670 ADD_CHILD_DEFAULT_FLAGS,
11671 insert_child_at_index,
11672 GINT_TO_POINTER (index_));
11676 * clutter_actor_insert_child_above:
11677 * @self: a #ClutterActor
11678 * @child: a #ClutterActor
11679 * @sibling: (allow-none): a child of @self, or %NULL
11681 * Inserts @child into the list of children of @self, above another
11682 * child of @self or, if @sibling is %NULL, above all the children
11685 * This function will acquire a reference on @child that will only
11686 * be released when calling clutter_actor_remove_child().
11688 * This function will not take into consideration the #ClutterActor:depth
11691 * This function will emit the #ClutterContainer::actor-added signal
11697 clutter_actor_insert_child_above (ClutterActor *self,
11698 ClutterActor *child,
11699 ClutterActor *sibling)
11701 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11702 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11703 g_return_if_fail (self != child);
11704 g_return_if_fail (child != sibling);
11705 g_return_if_fail (child->priv->parent == NULL);
11706 g_return_if_fail (sibling == NULL ||
11707 (CLUTTER_IS_ACTOR (sibling) &&
11708 sibling->priv->parent == self));
11710 clutter_actor_add_child_internal (self, child,
11711 ADD_CHILD_DEFAULT_FLAGS,
11712 insert_child_above,
11717 * clutter_actor_insert_child_below:
11718 * @self: a #ClutterActor
11719 * @child: a #ClutterActor
11720 * @sibling: (allow-none): a child of @self, or %NULL
11722 * Inserts @child into the list of children of @self, below another
11723 * child of @self or, if @sibling is %NULL, below all the children
11726 * This function will acquire a reference on @child that will only
11727 * be released when calling clutter_actor_remove_child().
11729 * This function will not take into consideration the #ClutterActor:depth
11732 * This function will emit the #ClutterContainer::actor-added signal
11738 clutter_actor_insert_child_below (ClutterActor *self,
11739 ClutterActor *child,
11740 ClutterActor *sibling)
11742 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11743 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11744 g_return_if_fail (self != child);
11745 g_return_if_fail (child != sibling);
11746 g_return_if_fail (child->priv->parent == NULL);
11747 g_return_if_fail (sibling == NULL ||
11748 (CLUTTER_IS_ACTOR (sibling) &&
11749 sibling->priv->parent == self));
11751 clutter_actor_add_child_internal (self, child,
11752 ADD_CHILD_DEFAULT_FLAGS,
11753 insert_child_below,
11758 * clutter_actor_set_parent:
11759 * @self: A #ClutterActor
11760 * @parent: A new #ClutterActor parent
11762 * Sets the parent of @self to @parent.
11764 * This function will result in @parent acquiring a reference on @self,
11765 * eventually by sinking its floating reference first. The reference
11766 * will be released by clutter_actor_unparent().
11768 * This function should only be called by legacy #ClutterActor<!-- -->s
11769 * implementing the #ClutterContainer interface.
11771 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11774 clutter_actor_set_parent (ClutterActor *self,
11775 ClutterActor *parent)
11777 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11778 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11779 g_return_if_fail (self != parent);
11780 g_return_if_fail (self->priv->parent == NULL);
11782 /* as this function will be called inside ClutterContainer::add
11783 * implementations or when building up a composite actor, we have
11784 * to preserve the old behaviour, and not create child meta or
11785 * emit the ::actor-added signal, to avoid recursion or double
11788 clutter_actor_add_child_internal (parent, self,
11789 ADD_CHILD_LEGACY_FLAGS,
11790 insert_child_at_depth,
11795 * clutter_actor_get_parent:
11796 * @self: A #ClutterActor
11798 * Retrieves the parent of @self.
11800 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11801 * if no parent is set
11804 clutter_actor_get_parent (ClutterActor *self)
11806 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11808 return self->priv->parent;
11812 * clutter_actor_get_paint_visibility:
11813 * @self: A #ClutterActor
11815 * Retrieves the 'paint' visibility of an actor recursively checking for non
11818 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11820 * Return Value: %TRUE if the actor is visibile and will be painted.
11825 clutter_actor_get_paint_visibility (ClutterActor *actor)
11827 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11829 return CLUTTER_ACTOR_IS_MAPPED (actor);
11833 * clutter_actor_remove_child:
11834 * @self: a #ClutterActor
11835 * @child: a #ClutterActor
11837 * Removes @child from the children of @self.
11839 * This function will release the reference added by
11840 * clutter_actor_add_child(), so if you want to keep using @child
11841 * you will have to acquire a referenced on it before calling this
11844 * This function will emit the #ClutterContainer::actor-removed
11850 clutter_actor_remove_child (ClutterActor *self,
11851 ClutterActor *child)
11853 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11854 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11855 g_return_if_fail (self != child);
11856 g_return_if_fail (child->priv->parent != NULL);
11857 g_return_if_fail (child->priv->parent == self);
11859 clutter_actor_remove_child_internal (self, child,
11860 REMOVE_CHILD_DEFAULT_FLAGS);
11864 * clutter_actor_remove_all_children:
11865 * @self: a #ClutterActor
11867 * Removes all children of @self.
11869 * This function releases the reference added by inserting a child actor
11870 * in the list of children of @self.
11872 * If the reference count of a child drops to zero, the child will be
11873 * destroyed. If you want to ensure the destruction of all the children
11874 * of @self, use clutter_actor_destroy_all_children().
11879 clutter_actor_remove_all_children (ClutterActor *self)
11881 ClutterActorIter iter;
11883 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11885 if (self->priv->n_children == 0)
11888 g_object_freeze_notify (G_OBJECT (self));
11890 clutter_actor_iter_init (&iter, self);
11891 while (clutter_actor_iter_next (&iter, NULL))
11892 clutter_actor_iter_remove (&iter);
11894 g_object_thaw_notify (G_OBJECT (self));
11897 g_assert (self->priv->first_child == NULL);
11898 g_assert (self->priv->last_child == NULL);
11899 g_assert (self->priv->n_children == 0);
11903 * clutter_actor_destroy_all_children:
11904 * @self: a #ClutterActor
11906 * Destroys all children of @self.
11908 * This function releases the reference added by inserting a child
11909 * actor in the list of children of @self, and ensures that the
11910 * #ClutterActor::destroy signal is emitted on each child of the
11913 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11914 * when its reference count drops to 0; the default handler of the
11915 * #ClutterActor::destroy signal will destroy all the children of an
11916 * actor. This function ensures that all children are destroyed, instead
11917 * of just removed from @self, unlike clutter_actor_remove_all_children()
11918 * which will merely release the reference and remove each child.
11920 * Unless you acquired an additional reference on each child of @self
11921 * prior to calling clutter_actor_remove_all_children() and want to reuse
11922 * the actors, you should use clutter_actor_destroy_all_children() in
11923 * order to make sure that children are destroyed and signal handlers
11924 * are disconnected even in cases where circular references prevent this
11925 * from automatically happening through reference counting alone.
11930 clutter_actor_destroy_all_children (ClutterActor *self)
11932 ClutterActorIter iter;
11934 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11936 if (self->priv->n_children == 0)
11939 g_object_freeze_notify (G_OBJECT (self));
11941 clutter_actor_iter_init (&iter, self);
11942 while (clutter_actor_iter_next (&iter, NULL))
11943 clutter_actor_iter_destroy (&iter);
11945 g_object_thaw_notify (G_OBJECT (self));
11948 g_assert (self->priv->first_child == NULL);
11949 g_assert (self->priv->last_child == NULL);
11950 g_assert (self->priv->n_children == 0);
11953 typedef struct _InsertBetweenData {
11954 ClutterActor *prev_sibling;
11955 ClutterActor *next_sibling;
11956 } InsertBetweenData;
11959 insert_child_between (ClutterActor *self,
11960 ClutterActor *child,
11963 InsertBetweenData *data = data_;
11964 ClutterActor *prev_sibling = data->prev_sibling;
11965 ClutterActor *next_sibling = data->next_sibling;
11967 child->priv->parent = self;
11968 child->priv->prev_sibling = prev_sibling;
11969 child->priv->next_sibling = next_sibling;
11971 if (prev_sibling != NULL)
11972 prev_sibling->priv->next_sibling = child;
11974 if (next_sibling != NULL)
11975 next_sibling->priv->prev_sibling = child;
11977 if (child->priv->prev_sibling == NULL)
11978 self->priv->first_child = child;
11980 if (child->priv->next_sibling == NULL)
11981 self->priv->last_child = child;
11985 * clutter_actor_replace_child:
11986 * @self: a #ClutterActor
11987 * @old_child: the child of @self to replace
11988 * @new_child: the #ClutterActor to replace @old_child
11990 * Replaces @old_child with @new_child in the list of children of @self.
11995 clutter_actor_replace_child (ClutterActor *self,
11996 ClutterActor *old_child,
11997 ClutterActor *new_child)
11999 ClutterActor *prev_sibling, *next_sibling;
12000 InsertBetweenData clos;
12002 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12003 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
12004 g_return_if_fail (old_child->priv->parent == self);
12005 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
12006 g_return_if_fail (old_child != new_child);
12007 g_return_if_fail (new_child != self);
12008 g_return_if_fail (new_child->priv->parent == NULL);
12010 prev_sibling = old_child->priv->prev_sibling;
12011 next_sibling = old_child->priv->next_sibling;
12012 clutter_actor_remove_child_internal (self, old_child,
12013 REMOVE_CHILD_DEFAULT_FLAGS);
12015 clos.prev_sibling = prev_sibling;
12016 clos.next_sibling = next_sibling;
12017 clutter_actor_add_child_internal (self, new_child,
12018 ADD_CHILD_DEFAULT_FLAGS,
12019 insert_child_between,
12024 * clutter_actor_unparent:
12025 * @self: a #ClutterActor
12027 * Removes the parent of @self.
12029 * This will cause the parent of @self to release the reference
12030 * acquired when calling clutter_actor_set_parent(), so if you
12031 * want to keep @self you will have to acquire a reference of
12032 * your own, through g_object_ref().
12034 * This function should only be called by legacy #ClutterActor<!-- -->s
12035 * implementing the #ClutterContainer interface.
12039 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
12042 clutter_actor_unparent (ClutterActor *self)
12044 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12046 if (self->priv->parent == NULL)
12049 clutter_actor_remove_child_internal (self->priv->parent, self,
12050 REMOVE_CHILD_LEGACY_FLAGS);
12054 * clutter_actor_reparent:
12055 * @self: a #ClutterActor
12056 * @new_parent: the new #ClutterActor parent
12058 * Resets the parent actor of @self.
12060 * This function is logically equivalent to calling clutter_actor_unparent()
12061 * and clutter_actor_set_parent(), but more efficiently implemented, as it
12062 * ensures the child is not finalized when unparented, and emits the
12063 * #ClutterActor::parent-set signal only once.
12065 * In reality, calling this function is less useful than it sounds, as some
12066 * application code may rely on changes in the intermediate state between
12067 * removal and addition of the actor from its old parent to the @new_parent.
12068 * Thus, it is strongly encouraged to avoid using this function in application
12073 * Deprecated: 1.10: Use clutter_actor_remove_child() and
12074 * clutter_actor_add_child() instead; remember to take a reference on
12075 * the actor being removed before calling clutter_actor_remove_child()
12076 * to avoid the reference count dropping to zero and the actor being
12080 clutter_actor_reparent (ClutterActor *self,
12081 ClutterActor *new_parent)
12083 ClutterActorPrivate *priv;
12085 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12086 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
12087 g_return_if_fail (self != new_parent);
12089 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
12091 g_warning ("Cannot set a parent on a toplevel actor");
12095 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
12097 g_warning ("Cannot set a parent currently being destroyed");
12103 if (priv->parent != new_parent)
12105 ClutterActor *old_parent;
12107 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12109 old_parent = priv->parent;
12111 g_object_ref (self);
12113 if (old_parent != NULL)
12115 /* go through the Container implementation if this is a regular
12116 * child and not an internal one
12118 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12120 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
12122 /* this will have to call unparent() */
12123 clutter_container_remove_actor (parent, self);
12126 clutter_actor_remove_child_internal (old_parent, self,
12127 REMOVE_CHILD_LEGACY_FLAGS);
12130 /* Note, will call set_parent() */
12131 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12132 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
12134 clutter_actor_add_child_internal (new_parent, self,
12135 ADD_CHILD_LEGACY_FLAGS,
12136 insert_child_at_depth,
12139 /* we emit the ::parent-set signal once */
12140 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
12142 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12144 /* the IN_REPARENT flag suspends state updates */
12145 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
12147 g_object_unref (self);
12152 * clutter_actor_contains:
12153 * @self: A #ClutterActor
12154 * @descendant: A #ClutterActor, possibly contained in @self
12156 * Determines if @descendant is contained inside @self (either as an
12157 * immediate child, or as a deeper descendant). If @self and
12158 * @descendant point to the same actor then it will also return %TRUE.
12160 * Return value: whether @descendent is contained within @self
12165 clutter_actor_contains (ClutterActor *self,
12166 ClutterActor *descendant)
12168 ClutterActor *actor;
12170 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12171 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12173 for (actor = descendant; actor; actor = actor->priv->parent)
12181 * clutter_actor_set_child_above_sibling:
12182 * @self: a #ClutterActor
12183 * @child: a #ClutterActor child of @self
12184 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12186 * Sets @child to be above @sibling in the list of children of @self.
12188 * If @sibling is %NULL, @child will be the new last child of @self.
12190 * This function is logically equivalent to removing @child and using
12191 * clutter_actor_insert_child_above(), but it will not emit signals
12192 * or change state on @child.
12197 clutter_actor_set_child_above_sibling (ClutterActor *self,
12198 ClutterActor *child,
12199 ClutterActor *sibling)
12201 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12202 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12203 g_return_if_fail (child->priv->parent == self);
12204 g_return_if_fail (child != sibling);
12205 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12207 if (sibling != NULL)
12208 g_return_if_fail (sibling->priv->parent == self);
12210 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12211 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12212 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12215 /* we don't want to change the state of child, or emit signals, or
12216 * regenerate ChildMeta instances here, but we still want to follow
12217 * the correct sequence of steps encoded in remove_child() and
12218 * add_child(), so that correctness is ensured, and we only go
12219 * through one known code path.
12221 g_object_ref (child);
12222 clutter_actor_remove_child_internal (self, child, 0);
12223 clutter_actor_add_child_internal (self, child,
12224 ADD_CHILD_NOTIFY_FIRST_LAST,
12225 insert_child_above,
12228 clutter_actor_queue_relayout (self);
12232 * clutter_actor_set_child_below_sibling:
12233 * @self: a #ClutterActor
12234 * @child: a #ClutterActor child of @self
12235 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12237 * Sets @child to be below @sibling in the list of children of @self.
12239 * If @sibling is %NULL, @child will be the new first child of @self.
12241 * This function is logically equivalent to removing @self and using
12242 * clutter_actor_insert_child_below(), but it will not emit signals
12243 * or change state on @child.
12248 clutter_actor_set_child_below_sibling (ClutterActor *self,
12249 ClutterActor *child,
12250 ClutterActor *sibling)
12252 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12253 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12254 g_return_if_fail (child->priv->parent == self);
12255 g_return_if_fail (child != sibling);
12256 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12258 if (sibling != NULL)
12259 g_return_if_fail (sibling->priv->parent == self);
12261 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12262 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12263 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12266 /* see the comment in set_child_above_sibling() */
12267 g_object_ref (child);
12268 clutter_actor_remove_child_internal (self, child, 0);
12269 clutter_actor_add_child_internal (self, child,
12270 ADD_CHILD_NOTIFY_FIRST_LAST,
12271 insert_child_below,
12274 clutter_actor_queue_relayout (self);
12278 * clutter_actor_set_child_at_index:
12279 * @self: a #ClutterActor
12280 * @child: a #ClutterActor child of @self
12281 * @index_: the new index for @child
12283 * Changes the index of @child in the list of children of @self.
12285 * This function is logically equivalent to removing @child and
12286 * calling clutter_actor_insert_child_at_index(), but it will not
12287 * emit signals or change state on @child.
12292 clutter_actor_set_child_at_index (ClutterActor *self,
12293 ClutterActor *child,
12296 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12297 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12298 g_return_if_fail (child->priv->parent == self);
12299 g_return_if_fail (index_ <= self->priv->n_children);
12301 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12302 CLUTTER_ACTOR_IN_DESTRUCTION (child))
12305 g_object_ref (child);
12306 clutter_actor_remove_child_internal (self, child, 0);
12307 clutter_actor_add_child_internal (self, child,
12308 ADD_CHILD_NOTIFY_FIRST_LAST,
12309 insert_child_at_index,
12310 GINT_TO_POINTER (index_));
12312 clutter_actor_queue_relayout (self);
12316 * clutter_actor_raise:
12317 * @self: A #ClutterActor
12318 * @below: (allow-none): A #ClutterActor to raise above.
12320 * Puts @self above @below.
12322 * Both actors must have the same parent, and the parent must implement
12323 * the #ClutterContainer interface
12325 * This function calls clutter_container_raise_child() internally.
12327 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12330 clutter_actor_raise (ClutterActor *self,
12331 ClutterActor *below)
12333 ClutterActor *parent;
12335 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12337 parent = clutter_actor_get_parent (self);
12338 if (parent == NULL)
12340 g_warning ("%s: Actor '%s' is not inside a container",
12342 _clutter_actor_get_debug_name (self));
12348 if (parent != clutter_actor_get_parent (below))
12350 g_warning ("%s Actor '%s' is not in the same container as "
12353 _clutter_actor_get_debug_name (self),
12354 _clutter_actor_get_debug_name (below));
12359 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12363 * clutter_actor_lower:
12364 * @self: A #ClutterActor
12365 * @above: (allow-none): A #ClutterActor to lower below
12367 * Puts @self below @above.
12369 * Both actors must have the same parent, and the parent must implement
12370 * the #ClutterContainer interface.
12372 * This function calls clutter_container_lower_child() internally.
12374 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12377 clutter_actor_lower (ClutterActor *self,
12378 ClutterActor *above)
12380 ClutterActor *parent;
12382 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12384 parent = clutter_actor_get_parent (self);
12385 if (parent == NULL)
12387 g_warning ("%s: Actor of type %s is not inside a container",
12389 _clutter_actor_get_debug_name (self));
12395 if (parent != clutter_actor_get_parent (above))
12397 g_warning ("%s: Actor '%s' is not in the same container as "
12400 _clutter_actor_get_debug_name (self),
12401 _clutter_actor_get_debug_name (above));
12406 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12410 * clutter_actor_raise_top:
12411 * @self: A #ClutterActor
12413 * Raises @self to the top.
12415 * This function calls clutter_actor_raise() internally.
12417 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12418 * a %NULL sibling, instead.
12421 clutter_actor_raise_top (ClutterActor *self)
12423 clutter_actor_raise (self, NULL);
12427 * clutter_actor_lower_bottom:
12428 * @self: A #ClutterActor
12430 * Lowers @self to the bottom.
12432 * This function calls clutter_actor_lower() internally.
12434 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12435 * a %NULL sibling, instead.
12438 clutter_actor_lower_bottom (ClutterActor *self)
12440 clutter_actor_lower (self, NULL);
12448 * clutter_actor_event:
12449 * @actor: a #ClutterActor
12450 * @event: a #ClutterEvent
12451 * @capture: TRUE if event in in capture phase, FALSE otherwise.
12453 * This function is used to emit an event on the main stage.
12454 * You should rarely need to use this function, except for
12455 * synthetising events.
12457 * Return value: the return value from the signal emission: %TRUE
12458 * if the actor handled the event, or %FALSE if the event was
12464 clutter_actor_event (ClutterActor *actor,
12465 ClutterEvent *event,
12468 gboolean retval = FALSE;
12469 gint signal_num = -1;
12471 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12472 g_return_val_if_fail (event != NULL, FALSE);
12474 g_object_ref (actor);
12478 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12484 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12488 switch (event->type)
12490 case CLUTTER_NOTHING:
12492 case CLUTTER_BUTTON_PRESS:
12493 signal_num = BUTTON_PRESS_EVENT;
12495 case CLUTTER_BUTTON_RELEASE:
12496 signal_num = BUTTON_RELEASE_EVENT;
12498 case CLUTTER_SCROLL:
12499 signal_num = SCROLL_EVENT;
12501 case CLUTTER_KEY_PRESS:
12502 signal_num = KEY_PRESS_EVENT;
12504 case CLUTTER_KEY_RELEASE:
12505 signal_num = KEY_RELEASE_EVENT;
12507 case CLUTTER_MOTION:
12508 signal_num = MOTION_EVENT;
12510 case CLUTTER_ENTER:
12511 signal_num = ENTER_EVENT;
12513 case CLUTTER_LEAVE:
12514 signal_num = LEAVE_EVENT;
12516 case CLUTTER_DELETE:
12517 case CLUTTER_DESTROY_NOTIFY:
12518 case CLUTTER_CLIENT_MESSAGE:
12524 if (signal_num != -1)
12525 g_signal_emit (actor, actor_signals[signal_num], 0,
12530 g_object_unref (actor);
12536 * clutter_actor_set_reactive:
12537 * @actor: a #ClutterActor
12538 * @reactive: whether the actor should be reactive to events
12540 * Sets @actor as reactive. Reactive actors will receive events.
12545 clutter_actor_set_reactive (ClutterActor *actor,
12548 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12550 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12554 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12556 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12558 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12562 * clutter_actor_get_reactive:
12563 * @actor: a #ClutterActor
12565 * Checks whether @actor is marked as reactive.
12567 * Return value: %TRUE if the actor is reactive
12572 clutter_actor_get_reactive (ClutterActor *actor)
12574 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12576 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12580 * clutter_actor_get_anchor_point:
12581 * @self: a #ClutterActor
12582 * @anchor_x: (out): return location for the X coordinate of the anchor point
12583 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12585 * Gets the current anchor point of the @actor in pixels.
12590 clutter_actor_get_anchor_point (ClutterActor *self,
12594 const ClutterTransformInfo *info;
12596 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12598 info = _clutter_actor_get_transform_info_or_defaults (self);
12599 clutter_anchor_coord_get_units (self, &info->anchor,
12606 * clutter_actor_set_anchor_point:
12607 * @self: a #ClutterActor
12608 * @anchor_x: X coordinate of the anchor point
12609 * @anchor_y: Y coordinate of the anchor point
12611 * Sets an anchor point for @self. The anchor point is a point in the
12612 * coordinate space of an actor to which the actor position within its
12613 * parent is relative; the default is (0, 0), i.e. the top-left corner
12619 clutter_actor_set_anchor_point (ClutterActor *self,
12623 ClutterTransformInfo *info;
12624 ClutterActorPrivate *priv;
12625 gboolean changed = FALSE;
12626 gfloat old_anchor_x, old_anchor_y;
12629 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12631 obj = G_OBJECT (self);
12633 info = _clutter_actor_get_transform_info (self);
12635 g_object_freeze_notify (obj);
12637 clutter_anchor_coord_get_units (self, &info->anchor,
12642 if (info->anchor.is_fractional)
12643 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12645 if (old_anchor_x != anchor_x)
12647 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12651 if (old_anchor_y != anchor_y)
12653 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12657 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12661 priv->transform_valid = FALSE;
12662 clutter_actor_queue_redraw (self);
12665 g_object_thaw_notify (obj);
12669 * clutter_actor_get_anchor_point_gravity:
12670 * @self: a #ClutterActor
12672 * Retrieves the anchor position expressed as a #ClutterGravity. If
12673 * the anchor point was specified using pixels or units this will
12674 * return %CLUTTER_GRAVITY_NONE.
12676 * Return value: the #ClutterGravity used by the anchor point
12681 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12683 const ClutterTransformInfo *info;
12685 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12687 info = _clutter_actor_get_transform_info_or_defaults (self);
12689 return clutter_anchor_coord_get_gravity (&info->anchor);
12693 * clutter_actor_move_anchor_point:
12694 * @self: a #ClutterActor
12695 * @anchor_x: X coordinate of the anchor point
12696 * @anchor_y: Y coordinate of the anchor point
12698 * Sets an anchor point for the actor, and adjusts the actor postion so that
12699 * the relative position of the actor toward its parent remains the same.
12704 clutter_actor_move_anchor_point (ClutterActor *self,
12708 gfloat old_anchor_x, old_anchor_y;
12709 const ClutterTransformInfo *info;
12711 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12713 info = _clutter_actor_get_transform_info (self);
12714 clutter_anchor_coord_get_units (self, &info->anchor,
12719 g_object_freeze_notify (G_OBJECT (self));
12721 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12723 if (self->priv->position_set)
12724 clutter_actor_move_by (self,
12725 anchor_x - old_anchor_x,
12726 anchor_y - old_anchor_y);
12728 g_object_thaw_notify (G_OBJECT (self));
12732 * clutter_actor_move_anchor_point_from_gravity:
12733 * @self: a #ClutterActor
12734 * @gravity: #ClutterGravity.
12736 * Sets an anchor point on the actor based on the given gravity, adjusting the
12737 * actor postion so that its relative position within its parent remains
12740 * Since version 1.0 the anchor point will be stored as a gravity so
12741 * that if the actor changes size then the anchor point will move. For
12742 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12743 * and later double the size of the actor, the anchor point will move
12744 * to the bottom right.
12749 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12750 ClutterGravity gravity)
12752 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12753 const ClutterTransformInfo *info;
12754 ClutterActorPrivate *priv;
12756 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12759 info = _clutter_actor_get_transform_info (self);
12761 g_object_freeze_notify (G_OBJECT (self));
12763 clutter_anchor_coord_get_units (self, &info->anchor,
12767 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12768 clutter_anchor_coord_get_units (self, &info->anchor,
12773 if (priv->position_set)
12774 clutter_actor_move_by (self,
12775 new_anchor_x - old_anchor_x,
12776 new_anchor_y - old_anchor_y);
12778 g_object_thaw_notify (G_OBJECT (self));
12782 * clutter_actor_set_anchor_point_from_gravity:
12783 * @self: a #ClutterActor
12784 * @gravity: #ClutterGravity.
12786 * Sets an anchor point on the actor, based on the given gravity (this is a
12787 * convenience function wrapping clutter_actor_set_anchor_point()).
12789 * Since version 1.0 the anchor point will be stored as a gravity so
12790 * that if the actor changes size then the anchor point will move. For
12791 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12792 * and later double the size of the actor, the anchor point will move
12793 * to the bottom right.
12798 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12799 ClutterGravity gravity)
12801 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12803 if (gravity == CLUTTER_GRAVITY_NONE)
12804 clutter_actor_set_anchor_point (self, 0, 0);
12807 GObject *obj = G_OBJECT (self);
12808 ClutterTransformInfo *info;
12810 g_object_freeze_notify (obj);
12812 info = _clutter_actor_get_transform_info (self);
12813 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12815 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12816 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12817 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12819 self->priv->transform_valid = FALSE;
12821 clutter_actor_queue_redraw (self);
12823 g_object_thaw_notify (obj);
12828 clutter_actor_store_content_box (ClutterActor *self,
12829 const ClutterActorBox *box)
12833 self->priv->content_box = *box;
12834 self->priv->content_box_valid = TRUE;
12837 self->priv->content_box_valid = FALSE;
12839 clutter_actor_queue_redraw (self);
12841 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12845 clutter_container_iface_init (ClutterContainerIface *iface)
12847 /* we don't override anything, as ClutterContainer already has a default
12848 * implementation that we can use, and which calls into our own API.
12863 parse_units (ClutterActor *self,
12864 ParseDimension dimension,
12867 GValue value = G_VALUE_INIT;
12870 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12873 json_node_get_value (node, &value);
12875 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12877 retval = (gfloat) g_value_get_int64 (&value);
12879 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12881 retval = g_value_get_double (&value);
12883 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12885 ClutterUnits units;
12888 res = clutter_units_from_string (&units, g_value_get_string (&value));
12890 retval = clutter_units_to_pixels (&units);
12893 g_warning ("Invalid value '%s': integers, strings or floating point "
12894 "values can be used for the x, y, width and height "
12895 "properties. Valid modifiers for strings are 'px', 'mm', "
12897 g_value_get_string (&value));
12903 g_warning ("Invalid value of type '%s': integers, strings of floating "
12904 "point values can be used for the x, y, width, height "
12905 "anchor-x and anchor-y properties.",
12906 g_type_name (G_VALUE_TYPE (&value)));
12909 g_value_unset (&value);
12915 ClutterRotateAxis axis;
12924 static inline gboolean
12925 parse_rotation_array (ClutterActor *actor,
12927 RotationInfo *info)
12931 if (json_array_get_length (array) != 2)
12935 element = json_array_get_element (array, 0);
12936 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12937 info->angle = json_node_get_double (element);
12942 element = json_array_get_element (array, 1);
12943 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12945 JsonArray *center = json_node_get_array (element);
12947 if (json_array_get_length (center) != 2)
12950 switch (info->axis)
12952 case CLUTTER_X_AXIS:
12953 info->center_y = parse_units (actor, PARSE_Y,
12954 json_array_get_element (center, 0));
12955 info->center_z = parse_units (actor, PARSE_Y,
12956 json_array_get_element (center, 1));
12959 case CLUTTER_Y_AXIS:
12960 info->center_x = parse_units (actor, PARSE_X,
12961 json_array_get_element (center, 0));
12962 info->center_z = parse_units (actor, PARSE_X,
12963 json_array_get_element (center, 1));
12966 case CLUTTER_Z_AXIS:
12967 info->center_x = parse_units (actor, PARSE_X,
12968 json_array_get_element (center, 0));
12969 info->center_y = parse_units (actor, PARSE_Y,
12970 json_array_get_element (center, 1));
12979 parse_rotation (ClutterActor *actor,
12981 RotationInfo *info)
12985 gboolean retval = FALSE;
12987 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12989 g_warning ("Invalid node of type '%s' found, expecting an array",
12990 json_node_type_name (node));
12994 array = json_node_get_array (node);
12995 len = json_array_get_length (array);
12997 for (i = 0; i < len; i++)
12999 JsonNode *element = json_array_get_element (array, i);
13000 JsonObject *object;
13003 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
13005 g_warning ("Invalid node of type '%s' found, expecting an object",
13006 json_node_type_name (element));
13010 object = json_node_get_object (element);
13012 if (json_object_has_member (object, "x-axis"))
13014 member = json_object_get_member (object, "x-axis");
13016 info->axis = CLUTTER_X_AXIS;
13018 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
13020 info->angle = json_node_get_double (member);
13023 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13024 retval = parse_rotation_array (actor,
13025 json_node_get_array (member),
13030 else if (json_object_has_member (object, "y-axis"))
13032 member = json_object_get_member (object, "y-axis");
13034 info->axis = CLUTTER_Y_AXIS;
13036 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
13038 info->angle = json_node_get_double (member);
13041 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13042 retval = parse_rotation_array (actor,
13043 json_node_get_array (member),
13048 else if (json_object_has_member (object, "z-axis"))
13050 member = json_object_get_member (object, "z-axis");
13052 info->axis = CLUTTER_Z_AXIS;
13054 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
13056 info->angle = json_node_get_double (member);
13059 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13060 retval = parse_rotation_array (actor,
13061 json_node_get_array (member),
13072 parse_actor_metas (ClutterScript *script,
13073 ClutterActor *actor,
13076 GList *elements, *l;
13077 GSList *retval = NULL;
13079 if (!JSON_NODE_HOLDS_ARRAY (node))
13082 elements = json_array_get_elements (json_node_get_array (node));
13084 for (l = elements; l != NULL; l = l->next)
13086 JsonNode *element = l->data;
13087 const gchar *id_ = _clutter_script_get_id_from_node (element);
13090 if (id_ == NULL || *id_ == '\0')
13093 meta = clutter_script_get_object (script, id_);
13097 retval = g_slist_prepend (retval, meta);
13100 g_list_free (elements);
13102 return g_slist_reverse (retval);
13106 parse_behaviours (ClutterScript *script,
13107 ClutterActor *actor,
13110 GList *elements, *l;
13111 GSList *retval = NULL;
13113 if (!JSON_NODE_HOLDS_ARRAY (node))
13116 elements = json_array_get_elements (json_node_get_array (node));
13118 for (l = elements; l != NULL; l = l->next)
13120 JsonNode *element = l->data;
13121 const gchar *id_ = _clutter_script_get_id_from_node (element);
13122 GObject *behaviour;
13124 if (id_ == NULL || *id_ == '\0')
13127 behaviour = clutter_script_get_object (script, id_);
13128 if (behaviour == NULL)
13131 retval = g_slist_prepend (retval, behaviour);
13134 g_list_free (elements);
13136 return g_slist_reverse (retval);
13139 static ClutterMargin *
13140 parse_margin (ClutterActor *self,
13143 ClutterMargin *margin;
13146 if (!JSON_NODE_HOLDS_ARRAY (node))
13148 g_warning ("The margin property must be an array of 1 to 4 elements");
13152 margin = clutter_margin_new ();
13153 array = json_node_get_array (node);
13154 switch (json_array_get_length (array))
13157 margin->top = margin->right = margin->bottom = margin->left =
13158 parse_units (self, 0, json_array_get_element (array, 0));
13162 margin->top = margin->bottom =
13163 parse_units (self, 0, json_array_get_element (array, 0));
13164 margin->right = margin->left =
13165 parse_units (self, 0, json_array_get_element (array, 1));
13170 parse_units (self, 0, json_array_get_element (array, 0));
13171 margin->right = margin->left =
13172 parse_units (self, 0, json_array_get_element (array, 1));
13174 parse_units (self, 0, json_array_get_element (array, 2));
13179 parse_units (self, 0, json_array_get_element (array, 0));
13181 parse_units (self, 0, json_array_get_element (array, 1));
13183 parse_units (self, 0, json_array_get_element (array, 2));
13185 parse_units (self, 0, json_array_get_element (array, 3));
13189 g_warning ("The margin property must be an array of 1 to 4 elements");
13190 clutter_margin_free (margin);
13197 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
13198 ClutterScript *script,
13203 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13204 gboolean retval = FALSE;
13206 if ((name[0] == 'x' && name[1] == '\0') ||
13207 (name[0] == 'y' && name[1] == '\0') ||
13208 (strcmp (name, "width") == 0) ||
13209 (strcmp (name, "height") == 0) ||
13210 (strcmp (name, "anchor_x") == 0) ||
13211 (strcmp (name, "anchor_y") == 0))
13213 ParseDimension dimension;
13216 if (name[0] == 'x')
13217 dimension = PARSE_X;
13218 else if (name[0] == 'y')
13219 dimension = PARSE_Y;
13220 else if (name[0] == 'w')
13221 dimension = PARSE_WIDTH;
13222 else if (name[0] == 'h')
13223 dimension = PARSE_HEIGHT;
13224 else if (name[0] == 'a' && name[7] == 'x')
13225 dimension = PARSE_ANCHOR_X;
13226 else if (name[0] == 'a' && name[7] == 'y')
13227 dimension = PARSE_ANCHOR_Y;
13231 units = parse_units (actor, dimension, node);
13233 /* convert back to pixels: all properties are pixel-based */
13234 g_value_init (value, G_TYPE_FLOAT);
13235 g_value_set_float (value, units);
13239 else if (strcmp (name, "rotation") == 0)
13241 RotationInfo *info;
13243 info = g_slice_new0 (RotationInfo);
13244 retval = parse_rotation (actor, node, info);
13248 g_value_init (value, G_TYPE_POINTER);
13249 g_value_set_pointer (value, info);
13252 g_slice_free (RotationInfo, info);
13254 else if (strcmp (name, "behaviours") == 0)
13258 #ifdef CLUTTER_ENABLE_DEBUG
13259 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13260 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13261 "and it should not be used in newly "
13262 "written ClutterScript definitions.");
13265 l = parse_behaviours (script, actor, node);
13267 g_value_init (value, G_TYPE_POINTER);
13268 g_value_set_pointer (value, l);
13272 else if (strcmp (name, "actions") == 0 ||
13273 strcmp (name, "constraints") == 0 ||
13274 strcmp (name, "effects") == 0)
13278 l = parse_actor_metas (script, actor, node);
13280 g_value_init (value, G_TYPE_POINTER);
13281 g_value_set_pointer (value, l);
13285 else if (strcmp (name, "margin") == 0)
13287 ClutterMargin *margin = parse_margin (actor, node);
13291 g_value_init (value, CLUTTER_TYPE_MARGIN);
13292 g_value_set_boxed (value, margin);
13301 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13302 ClutterScript *script,
13304 const GValue *value)
13306 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13308 #ifdef CLUTTER_ENABLE_DEBUG
13309 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13311 gchar *tmp = g_strdup_value_contents (value);
13313 CLUTTER_NOTE (SCRIPT,
13314 "in ClutterActor::set_custom_property('%s') = %s",
13320 #endif /* CLUTTER_ENABLE_DEBUG */
13322 if (strcmp (name, "rotation") == 0)
13324 RotationInfo *info;
13326 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13329 info = g_value_get_pointer (value);
13331 clutter_actor_set_rotation (actor,
13332 info->axis, info->angle,
13337 g_slice_free (RotationInfo, info);
13342 if (strcmp (name, "behaviours") == 0)
13344 GSList *behaviours, *l;
13346 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13349 behaviours = g_value_get_pointer (value);
13350 for (l = behaviours; l != NULL; l = l->next)
13352 ClutterBehaviour *behaviour = l->data;
13354 clutter_behaviour_apply (behaviour, actor);
13357 g_slist_free (behaviours);
13362 if (strcmp (name, "actions") == 0 ||
13363 strcmp (name, "constraints") == 0 ||
13364 strcmp (name, "effects") == 0)
13368 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13371 metas = g_value_get_pointer (value);
13372 for (l = metas; l != NULL; l = l->next)
13374 if (name[0] == 'a')
13375 clutter_actor_add_action (actor, l->data);
13377 if (name[0] == 'c')
13378 clutter_actor_add_constraint (actor, l->data);
13380 if (name[0] == 'e')
13381 clutter_actor_add_effect (actor, l->data);
13384 g_slist_free (metas);
13388 if (strcmp (name, "margin") == 0)
13390 clutter_actor_set_margin (actor, g_value_get_boxed (value));
13394 g_object_set_property (G_OBJECT (scriptable), name, value);
13398 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13400 iface->parse_custom_node = clutter_actor_parse_custom_node;
13401 iface->set_custom_property = clutter_actor_set_custom_property;
13404 static ClutterActorMeta *
13405 get_meta_from_animation_property (ClutterActor *actor,
13409 ClutterActorPrivate *priv = actor->priv;
13410 ClutterActorMeta *meta = NULL;
13413 /* if this is not a special property, fall through */
13414 if (name[0] != '@')
13417 /* detect the properties named using the following spec:
13419 * @<section>.<meta-name>.<property-name>
13421 * where <section> can be one of the following:
13427 * and <meta-name> is the name set on a specific ActorMeta
13430 tokens = g_strsplit (name + 1, ".", -1);
13431 if (tokens == NULL || g_strv_length (tokens) != 3)
13433 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13435 g_strfreev (tokens);
13439 if (strcmp (tokens[0], "actions") == 0)
13440 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13442 if (strcmp (tokens[0], "constraints") == 0)
13443 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13445 if (strcmp (tokens[0], "effects") == 0)
13446 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13448 if (name_p != NULL)
13449 *name_p = g_strdup (tokens[2]);
13451 CLUTTER_NOTE (ANIMATION,
13452 "Looking for property '%s' of object '%s' in section '%s'",
13457 g_strfreev (tokens);
13462 static GParamSpec *
13463 clutter_actor_find_property (ClutterAnimatable *animatable,
13464 const gchar *property_name)
13466 ClutterActorMeta *meta = NULL;
13467 GObjectClass *klass = NULL;
13468 GParamSpec *pspec = NULL;
13469 gchar *p_name = NULL;
13471 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13477 klass = G_OBJECT_GET_CLASS (meta);
13479 pspec = g_object_class_find_property (klass, p_name);
13483 klass = G_OBJECT_GET_CLASS (animatable);
13485 pspec = g_object_class_find_property (klass, property_name);
13494 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13495 const gchar *property_name,
13498 ClutterActorMeta *meta = NULL;
13499 gchar *p_name = NULL;
13501 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13506 g_object_get_property (G_OBJECT (meta), p_name, initial);
13508 g_object_get_property (G_OBJECT (animatable), property_name, initial);
13514 * clutter_actor_set_animatable_property:
13515 * @actor: a #ClutterActor
13516 * @prop_id: the paramspec id
13517 * @value: the value to set
13518 * @pspec: the paramspec
13520 * Sets values of animatable properties.
13522 * This is a variant of clutter_actor_set_property() that gets called
13523 * by the #ClutterAnimatable implementation of #ClutterActor for the
13524 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13527 * Unlike the implementation of #GObjectClass.set_property(), this
13528 * function will not update the interval if a transition involving an
13529 * animatable property is in progress - this avoids cycles with the
13530 * transition API calling the public API.
13533 clutter_actor_set_animatable_property (ClutterActor *actor,
13535 const GValue *value,
13538 GObject *obj = G_OBJECT (actor);
13540 g_object_freeze_notify (obj);
13545 clutter_actor_set_x_internal (actor, g_value_get_float (value));
13549 clutter_actor_set_y_internal (actor, g_value_get_float (value));
13552 case PROP_POSITION:
13553 clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13557 clutter_actor_set_width_internal (actor, g_value_get_float (value));
13561 clutter_actor_set_height_internal (actor, g_value_get_float (value));
13565 clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13568 case PROP_ALLOCATION:
13569 clutter_actor_allocate_internal (actor,
13570 g_value_get_boxed (value),
13571 actor->priv->allocation_flags);
13575 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13579 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13582 case PROP_BACKGROUND_COLOR:
13583 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13587 clutter_actor_set_scale_factor_internal (actor,
13588 g_value_get_double (value),
13593 clutter_actor_set_scale_factor_internal (actor,
13594 g_value_get_double (value),
13598 case PROP_ROTATION_ANGLE_X:
13599 clutter_actor_set_rotation_angle_internal (actor,
13601 g_value_get_double (value));
13604 case PROP_ROTATION_ANGLE_Y:
13605 clutter_actor_set_rotation_angle_internal (actor,
13607 g_value_get_double (value));
13610 case PROP_ROTATION_ANGLE_Z:
13611 clutter_actor_set_rotation_angle_internal (actor,
13613 g_value_get_double (value));
13616 case PROP_CONTENT_BOX:
13617 clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13621 g_object_set_property (obj, pspec->name, value);
13625 g_object_thaw_notify (obj);
13629 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13630 const gchar *property_name,
13631 const GValue *final)
13633 ClutterActor *actor = CLUTTER_ACTOR (animatable);
13634 ClutterActorMeta *meta = NULL;
13635 gchar *p_name = NULL;
13637 meta = get_meta_from_animation_property (actor,
13641 g_object_set_property (G_OBJECT (meta), p_name, final);
13644 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13647 pspec = g_object_class_find_property (obj_class, property_name);
13649 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13651 /* XXX - I'm going to the special hell for this */
13652 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13655 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13662 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13664 iface->find_property = clutter_actor_find_property;
13665 iface->get_initial_state = clutter_actor_get_initial_state;
13666 iface->set_final_state = clutter_actor_set_final_state;
13670 * clutter_actor_transform_stage_point:
13671 * @self: A #ClutterActor
13672 * @x: (in): x screen coordinate of the point to unproject
13673 * @y: (in): y screen coordinate of the point to unproject
13674 * @x_out: (out): return location for the unprojected x coordinance
13675 * @y_out: (out): return location for the unprojected y coordinance
13677 * This function translates screen coordinates (@x, @y) to
13678 * coordinates relative to the actor. For example, it can be used to translate
13679 * screen events from global screen coordinates into actor-local coordinates.
13681 * The conversion can fail, notably if the transform stack results in the
13682 * actor being projected on the screen as a mere line.
13684 * The conversion should not be expected to be pixel-perfect due to the
13685 * nature of the operation. In general the error grows when the skewing
13686 * of the actor rectangle on screen increases.
13688 * <note><para>This function can be computationally intensive.</para></note>
13690 * <note><para>This function only works when the allocation is up-to-date,
13691 * i.e. inside of paint().</para></note>
13693 * Return value: %TRUE if conversion was successful.
13698 clutter_actor_transform_stage_point (ClutterActor *self,
13704 ClutterVertex v[4];
13707 int du, dv, xi, yi;
13709 float xf, yf, wf, det;
13710 ClutterActorPrivate *priv;
13712 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13716 /* This implementation is based on the quad -> quad projection algorithm
13717 * described by Paul Heckbert in:
13719 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13721 * and the sample implementation at:
13723 * http://www.cs.cmu.edu/~ph/src/texfund/
13725 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13726 * quad to rectangle only, which significantly simplifies things; the
13727 * function calls have been unrolled, and most of the math is done in fixed
13731 clutter_actor_get_abs_allocation_vertices (self, v);
13733 /* Keeping these as ints simplifies the multiplication (no significant
13734 * loss of precision here).
13736 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13737 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13742 #define UX2FP(x) (x)
13743 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13745 /* First, find mapping from unit uv square to xy quadrilateral; this
13746 * equivalent to the pmap_square_quad() functions in the sample
13747 * implementation, which we can simplify, since our target is always
13750 px = v[0].x - v[1].x + v[3].x - v[2].x;
13751 py = v[0].y - v[1].y + v[3].y - v[2].y;
13755 /* affine transform */
13756 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13757 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13758 RQ[2][0] = UX2FP (v[0].x);
13759 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13760 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13761 RQ[2][1] = UX2FP (v[0].y);
13768 /* projective transform */
13769 double dx1, dx2, dy1, dy2, del;
13771 dx1 = UX2FP (v[1].x - v[3].x);
13772 dx2 = UX2FP (v[2].x - v[3].x);
13773 dy1 = UX2FP (v[1].y - v[3].y);
13774 dy2 = UX2FP (v[2].y - v[3].y);
13776 del = DET2FP (dx1, dx2, dy1, dy2);
13781 * The division here needs to be done in floating point for
13782 * precisions reasons.
13784 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13785 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13786 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13788 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13789 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13790 RQ[2][0] = UX2FP (v[0].x);
13791 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13792 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13793 RQ[2][1] = UX2FP (v[0].y);
13797 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13798 * square. Since our rectangle is based at 0,0 we only need to scale.
13808 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13811 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13812 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13813 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13814 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13815 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13816 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13817 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13818 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13819 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13822 * Check the resulting matrix is OK.
13824 det = (RQ[0][0] * ST[0][0])
13825 + (RQ[0][1] * ST[0][1])
13826 + (RQ[0][2] * ST[0][2]);
13831 * Now transform our point with the ST matrix; the notional w
13832 * coordinate is 1, hence the last part is simply added.
13837 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13838 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13839 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13854 * clutter_actor_is_rotated:
13855 * @self: a #ClutterActor
13857 * Checks whether any rotation is applied to the actor.
13859 * Return value: %TRUE if the actor is rotated.
13864 clutter_actor_is_rotated (ClutterActor *self)
13866 const ClutterTransformInfo *info;
13868 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13870 info = _clutter_actor_get_transform_info_or_defaults (self);
13872 if (info->rx_angle || info->ry_angle || info->rz_angle)
13879 * clutter_actor_is_scaled:
13880 * @self: a #ClutterActor
13882 * Checks whether the actor is scaled in either dimension.
13884 * Return value: %TRUE if the actor is scaled.
13889 clutter_actor_is_scaled (ClutterActor *self)
13891 const ClutterTransformInfo *info;
13893 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13895 info = _clutter_actor_get_transform_info_or_defaults (self);
13897 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13904 _clutter_actor_get_stage_internal (ClutterActor *actor)
13906 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13907 actor = actor->priv->parent;
13913 * clutter_actor_get_stage:
13914 * @actor: a #ClutterActor
13916 * Retrieves the #ClutterStage where @actor is contained.
13918 * Return value: (transfer none) (type Clutter.Stage): the stage
13919 * containing the actor, or %NULL
13924 clutter_actor_get_stage (ClutterActor *actor)
13926 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13928 return _clutter_actor_get_stage_internal (actor);
13932 * clutter_actor_allocate_available_size:
13933 * @self: a #ClutterActor
13934 * @x: the actor's X coordinate
13935 * @y: the actor's Y coordinate
13936 * @available_width: the maximum available width, or -1 to use the
13937 * actor's natural width
13938 * @available_height: the maximum available height, or -1 to use the
13939 * actor's natural height
13940 * @flags: flags controlling the allocation
13942 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13943 * preferred size, but limiting it to the maximum available width
13944 * and height provided.
13946 * This function will do the right thing when dealing with the
13947 * actor's request mode.
13949 * The implementation of this function is equivalent to:
13952 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13954 * clutter_actor_get_preferred_width (self, available_height,
13956 * &natural_width);
13957 * width = CLAMP (natural_width, min_width, available_width);
13959 * clutter_actor_get_preferred_height (self, width,
13961 * &natural_height);
13962 * height = CLAMP (natural_height, min_height, available_height);
13966 * clutter_actor_get_preferred_height (self, available_width,
13968 * &natural_height);
13969 * height = CLAMP (natural_height, min_height, available_height);
13971 * clutter_actor_get_preferred_width (self, height,
13973 * &natural_width);
13974 * width = CLAMP (natural_width, min_width, available_width);
13977 * box.x1 = x; box.y1 = y;
13978 * box.x2 = box.x1 + available_width;
13979 * box.y2 = box.y1 + available_height;
13980 * clutter_actor_allocate (self, &box, flags);
13983 * This function can be used by fluid layout managers to allocate
13984 * an actor's preferred size without making it bigger than the area
13985 * available for the container.
13990 clutter_actor_allocate_available_size (ClutterActor *self,
13993 gfloat available_width,
13994 gfloat available_height,
13995 ClutterAllocationFlags flags)
13997 ClutterActorPrivate *priv;
13998 gfloat width, height;
13999 gfloat min_width, min_height;
14000 gfloat natural_width, natural_height;
14001 ClutterActorBox box;
14003 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14007 width = height = 0.0;
14009 switch (priv->request_mode)
14011 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
14012 clutter_actor_get_preferred_width (self, available_height,
14015 width = CLAMP (natural_width, min_width, available_width);
14017 clutter_actor_get_preferred_height (self, width,
14020 height = CLAMP (natural_height, min_height, available_height);
14023 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
14024 clutter_actor_get_preferred_height (self, available_width,
14027 height = CLAMP (natural_height, min_height, available_height);
14029 clutter_actor_get_preferred_width (self, height,
14032 width = CLAMP (natural_width, min_width, available_width);
14039 box.x2 = box.x1 + width;
14040 box.y2 = box.y1 + height;
14041 clutter_actor_allocate (self, &box, flags);
14045 * clutter_actor_allocate_preferred_size:
14046 * @self: a #ClutterActor
14047 * @flags: flags controlling the allocation
14049 * Allocates the natural size of @self.
14051 * This function is a utility call for #ClutterActor implementations
14052 * that allocates the actor's preferred natural size. It can be used
14053 * by fixed layout managers (like #ClutterGroup or so called
14054 * 'composite actors') inside the ClutterActor::allocate
14055 * implementation to give each child exactly how much space it
14058 * This function is not meant to be used by applications. It is also
14059 * not meant to be used outside the implementation of the
14060 * ClutterActor::allocate virtual function.
14065 clutter_actor_allocate_preferred_size (ClutterActor *self,
14066 ClutterAllocationFlags flags)
14068 gfloat actor_x, actor_y;
14069 gfloat natural_width, natural_height;
14070 ClutterActorBox actor_box;
14072 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14074 actor_x = clutter_actor_get_x (self);
14075 actor_y = clutter_actor_get_y (self);
14077 clutter_actor_get_preferred_size (self,
14082 actor_box.x1 = actor_x;
14083 actor_box.y1 = actor_y;
14084 actor_box.x2 = actor_box.x1 + natural_width;
14085 actor_box.y2 = actor_box.y1 + natural_height;
14087 clutter_actor_allocate (self, &actor_box, flags);
14091 * clutter_actor_allocate_align_fill:
14092 * @self: a #ClutterActor
14093 * @box: a #ClutterActorBox, containing the available width and height
14094 * @x_align: the horizontal alignment, between 0 and 1
14095 * @y_align: the vertical alignment, between 0 and 1
14096 * @x_fill: whether the actor should fill horizontally
14097 * @y_fill: whether the actor should fill vertically
14098 * @flags: allocation flags to be passed to clutter_actor_allocate()
14100 * Allocates @self by taking into consideration the available allocation
14101 * area; an alignment factor on either axis; and whether the actor should
14102 * fill the allocation on either axis.
14104 * The @box should contain the available allocation width and height;
14105 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
14106 * allocation will be offset by their value.
14108 * This function takes into consideration the geometry request specified by
14109 * the #ClutterActor:request-mode property, and the text direction.
14111 * This function is useful for fluid layout managers, like #ClutterBinLayout
14112 * or #ClutterTableLayout
14117 clutter_actor_allocate_align_fill (ClutterActor *self,
14118 const ClutterActorBox *box,
14123 ClutterAllocationFlags flags)
14125 ClutterActorPrivate *priv;
14126 ClutterActorBox allocation = { 0, };
14127 gfloat x_offset, y_offset;
14128 gfloat available_width, available_height;
14129 gfloat child_width, child_height;
14131 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14132 g_return_if_fail (box != NULL);
14133 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
14134 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
14138 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
14139 clutter_actor_box_get_size (box, &available_width, &available_height);
14141 if (available_width < 0)
14142 available_width = 0;
14144 if (available_height < 0)
14145 available_height = 0;
14149 allocation.x1 = x_offset;
14150 allocation.x2 = allocation.x1 + available_width;
14155 allocation.y1 = y_offset;
14156 allocation.y2 = allocation.y1 + available_height;
14159 /* if we are filling horizontally and vertically then we're done */
14160 if (x_fill && y_fill)
14163 child_width = child_height = 0.0f;
14165 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
14167 gfloat min_width, natural_width;
14168 gfloat min_height, natural_height;
14170 clutter_actor_get_preferred_width (self, available_height,
14174 child_width = CLAMP (natural_width, min_width, available_width);
14178 clutter_actor_get_preferred_height (self, child_width,
14182 child_height = CLAMP (natural_height, min_height, available_height);
14187 gfloat min_width, natural_width;
14188 gfloat min_height, natural_height;
14190 clutter_actor_get_preferred_height (self, available_width,
14194 child_height = CLAMP (natural_height, min_height, available_height);
14198 clutter_actor_get_preferred_width (self, child_height,
14202 child_width = CLAMP (natural_width, min_width, available_width);
14206 /* invert the horizontal alignment for RTL languages */
14207 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
14208 x_align = 1.0 - x_align;
14212 allocation.x1 = x_offset
14213 + ((available_width - child_width) * x_align);
14214 allocation.x2 = allocation.x1 + child_width;
14219 allocation.y1 = y_offset
14220 + ((available_height - child_height) * y_align);
14221 allocation.y2 = allocation.y1 + child_height;
14225 clutter_actor_box_clamp_to_pixel (&allocation);
14226 clutter_actor_allocate (self, &allocation, flags);
14230 * clutter_actor_grab_key_focus:
14231 * @self: a #ClutterActor
14233 * Sets the key focus of the #ClutterStage including @self
14234 * to this #ClutterActor.
14239 clutter_actor_grab_key_focus (ClutterActor *self)
14241 ClutterActor *stage;
14243 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14245 stage = _clutter_actor_get_stage_internal (self);
14247 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14251 * clutter_actor_get_pango_context:
14252 * @self: a #ClutterActor
14254 * Retrieves the #PangoContext for @self. The actor's #PangoContext
14255 * is already configured using the appropriate font map, resolution
14256 * and font options.
14258 * Unlike clutter_actor_create_pango_context(), this context is owend
14259 * by the #ClutterActor and it will be updated each time the options
14260 * stored by the #ClutterBackend change.
14262 * You can use the returned #PangoContext to create a #PangoLayout
14263 * and render text using cogl_pango_render_layout() to reuse the
14264 * glyphs cache also used by Clutter.
14266 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14267 * The returned #PangoContext is owned by the actor and should not be
14268 * unreferenced by the application code
14273 clutter_actor_get_pango_context (ClutterActor *self)
14275 ClutterActorPrivate *priv;
14277 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14281 if (priv->pango_context != NULL)
14282 return priv->pango_context;
14284 priv->pango_context = _clutter_context_get_pango_context ();
14285 g_object_ref (priv->pango_context);
14287 return priv->pango_context;
14291 * clutter_actor_create_pango_context:
14292 * @self: a #ClutterActor
14294 * Creates a #PangoContext for the given actor. The #PangoContext
14295 * is already configured using the appropriate font map, resolution
14296 * and font options.
14298 * See also clutter_actor_get_pango_context().
14300 * Return value: (transfer full): the newly created #PangoContext.
14301 * Use g_object_unref() on the returned value to deallocate its
14307 clutter_actor_create_pango_context (ClutterActor *self)
14309 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14311 return _clutter_context_create_pango_context ();
14315 * clutter_actor_create_pango_layout:
14316 * @self: a #ClutterActor
14317 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14319 * Creates a new #PangoLayout from the same #PangoContext used
14320 * by the #ClutterActor. The #PangoLayout is already configured
14321 * with the font map, resolution and font options, and the
14324 * If you want to keep around a #PangoLayout created by this
14325 * function you will have to connect to the #ClutterBackend::font-changed
14326 * and #ClutterBackend::resolution-changed signals, and call
14327 * pango_layout_context_changed() in response to them.
14329 * Return value: (transfer full): the newly created #PangoLayout.
14330 * Use g_object_unref() when done
14335 clutter_actor_create_pango_layout (ClutterActor *self,
14338 PangoContext *context;
14339 PangoLayout *layout;
14341 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14343 context = clutter_actor_get_pango_context (self);
14344 layout = pango_layout_new (context);
14347 pango_layout_set_text (layout, text, -1);
14352 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14353 * ClutterOffscreenEffect.
14356 _clutter_actor_set_opacity_override (ClutterActor *self,
14359 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14361 self->priv->opacity_override = opacity;
14365 _clutter_actor_get_opacity_override (ClutterActor *self)
14367 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14369 return self->priv->opacity_override;
14372 /* Allows you to disable applying the actors model view transform during
14373 * a paint. Used by ClutterClone. */
14375 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14378 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14380 self->priv->enable_model_view_transform = enable;
14384 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14387 ClutterActorPrivate *priv;
14389 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14393 priv->enable_paint_unmapped = enable;
14395 if (priv->enable_paint_unmapped)
14397 /* Make sure that the parents of the widget are realized first;
14398 * otherwise checks in clutter_actor_update_map_state() will
14401 clutter_actor_realize (self);
14403 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14407 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14412 clutter_anchor_coord_get_units (ClutterActor *self,
14413 const AnchorCoord *coord,
14418 if (coord->is_fractional)
14420 gfloat actor_width, actor_height;
14422 clutter_actor_get_size (self, &actor_width, &actor_height);
14425 *x = actor_width * coord->v.fraction.x;
14428 *y = actor_height * coord->v.fraction.y;
14436 *x = coord->v.units.x;
14439 *y = coord->v.units.y;
14442 *z = coord->v.units.z;
14447 clutter_anchor_coord_set_units (AnchorCoord *coord,
14452 coord->is_fractional = FALSE;
14453 coord->v.units.x = x;
14454 coord->v.units.y = y;
14455 coord->v.units.z = z;
14458 static ClutterGravity
14459 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14461 if (coord->is_fractional)
14463 if (coord->v.fraction.x == 0.0)
14465 if (coord->v.fraction.y == 0.0)
14466 return CLUTTER_GRAVITY_NORTH_WEST;
14467 else if (coord->v.fraction.y == 0.5)
14468 return CLUTTER_GRAVITY_WEST;
14469 else if (coord->v.fraction.y == 1.0)
14470 return CLUTTER_GRAVITY_SOUTH_WEST;
14472 return CLUTTER_GRAVITY_NONE;
14474 else if (coord->v.fraction.x == 0.5)
14476 if (coord->v.fraction.y == 0.0)
14477 return CLUTTER_GRAVITY_NORTH;
14478 else if (coord->v.fraction.y == 0.5)
14479 return CLUTTER_GRAVITY_CENTER;
14480 else if (coord->v.fraction.y == 1.0)
14481 return CLUTTER_GRAVITY_SOUTH;
14483 return CLUTTER_GRAVITY_NONE;
14485 else if (coord->v.fraction.x == 1.0)
14487 if (coord->v.fraction.y == 0.0)
14488 return CLUTTER_GRAVITY_NORTH_EAST;
14489 else if (coord->v.fraction.y == 0.5)
14490 return CLUTTER_GRAVITY_EAST;
14491 else if (coord->v.fraction.y == 1.0)
14492 return CLUTTER_GRAVITY_SOUTH_EAST;
14494 return CLUTTER_GRAVITY_NONE;
14497 return CLUTTER_GRAVITY_NONE;
14500 return CLUTTER_GRAVITY_NONE;
14504 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14505 ClutterGravity gravity)
14509 case CLUTTER_GRAVITY_NORTH:
14510 coord->v.fraction.x = 0.5;
14511 coord->v.fraction.y = 0.0;
14514 case CLUTTER_GRAVITY_NORTH_EAST:
14515 coord->v.fraction.x = 1.0;
14516 coord->v.fraction.y = 0.0;
14519 case CLUTTER_GRAVITY_EAST:
14520 coord->v.fraction.x = 1.0;
14521 coord->v.fraction.y = 0.5;
14524 case CLUTTER_GRAVITY_SOUTH_EAST:
14525 coord->v.fraction.x = 1.0;
14526 coord->v.fraction.y = 1.0;
14529 case CLUTTER_GRAVITY_SOUTH:
14530 coord->v.fraction.x = 0.5;
14531 coord->v.fraction.y = 1.0;
14534 case CLUTTER_GRAVITY_SOUTH_WEST:
14535 coord->v.fraction.x = 0.0;
14536 coord->v.fraction.y = 1.0;
14539 case CLUTTER_GRAVITY_WEST:
14540 coord->v.fraction.x = 0.0;
14541 coord->v.fraction.y = 0.5;
14544 case CLUTTER_GRAVITY_NORTH_WEST:
14545 coord->v.fraction.x = 0.0;
14546 coord->v.fraction.y = 0.0;
14549 case CLUTTER_GRAVITY_CENTER:
14550 coord->v.fraction.x = 0.5;
14551 coord->v.fraction.y = 0.5;
14555 coord->v.fraction.x = 0.0;
14556 coord->v.fraction.y = 0.0;
14560 coord->is_fractional = TRUE;
14564 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14566 if (coord->is_fractional)
14567 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14569 return (coord->v.units.x == 0.0
14570 && coord->v.units.y == 0.0
14571 && coord->v.units.z == 0.0);
14575 * clutter_actor_get_flags:
14576 * @self: a #ClutterActor
14578 * Retrieves the flags set on @self
14580 * Return value: a bitwise or of #ClutterActorFlags or 0
14585 clutter_actor_get_flags (ClutterActor *self)
14587 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14589 return self->flags;
14593 * clutter_actor_set_flags:
14594 * @self: a #ClutterActor
14595 * @flags: the flags to set
14597 * Sets @flags on @self
14599 * This function will emit notifications for the changed properties
14604 clutter_actor_set_flags (ClutterActor *self,
14605 ClutterActorFlags flags)
14607 ClutterActorFlags old_flags;
14609 gboolean was_reactive_set, reactive_set;
14610 gboolean was_realized_set, realized_set;
14611 gboolean was_mapped_set, mapped_set;
14612 gboolean was_visible_set, visible_set;
14614 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14616 if (self->flags == flags)
14619 obj = G_OBJECT (self);
14620 g_object_ref (obj);
14621 g_object_freeze_notify (obj);
14623 old_flags = self->flags;
14625 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14626 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14627 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14628 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14630 self->flags |= flags;
14632 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14633 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14634 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14635 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14637 if (reactive_set != was_reactive_set)
14638 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14640 if (realized_set != was_realized_set)
14641 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14643 if (mapped_set != was_mapped_set)
14644 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14646 if (visible_set != was_visible_set)
14647 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14649 g_object_thaw_notify (obj);
14650 g_object_unref (obj);
14654 * clutter_actor_unset_flags:
14655 * @self: a #ClutterActor
14656 * @flags: the flags to unset
14658 * Unsets @flags on @self
14660 * This function will emit notifications for the changed properties
14665 clutter_actor_unset_flags (ClutterActor *self,
14666 ClutterActorFlags flags)
14668 ClutterActorFlags old_flags;
14670 gboolean was_reactive_set, reactive_set;
14671 gboolean was_realized_set, realized_set;
14672 gboolean was_mapped_set, mapped_set;
14673 gboolean was_visible_set, visible_set;
14675 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14677 obj = G_OBJECT (self);
14678 g_object_freeze_notify (obj);
14680 old_flags = self->flags;
14682 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14683 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14684 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14685 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14687 self->flags &= ~flags;
14689 if (self->flags == old_flags)
14692 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14693 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14694 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14695 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14697 if (reactive_set != was_reactive_set)
14698 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14700 if (realized_set != was_realized_set)
14701 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14703 if (mapped_set != was_mapped_set)
14704 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14706 if (visible_set != was_visible_set)
14707 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14709 g_object_thaw_notify (obj);
14713 * clutter_actor_get_transformation_matrix:
14714 * @self: a #ClutterActor
14715 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14717 * Retrieves the transformations applied to @self relative to its
14723 clutter_actor_get_transformation_matrix (ClutterActor *self,
14724 CoglMatrix *matrix)
14726 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14728 cogl_matrix_init_identity (matrix);
14730 _clutter_actor_apply_modelview_transform (self, matrix);
14734 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14735 gboolean is_in_clone_paint)
14737 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14738 self->priv->in_clone_paint = is_in_clone_paint;
14742 * clutter_actor_is_in_clone_paint:
14743 * @self: a #ClutterActor
14745 * Checks whether @self is being currently painted by a #ClutterClone
14747 * This function is useful only inside the ::paint virtual function
14748 * implementations or within handlers for the #ClutterActor::paint
14751 * This function should not be used by applications
14753 * Return value: %TRUE if the #ClutterActor is currently being painted
14754 * by a #ClutterClone, and %FALSE otherwise
14759 clutter_actor_is_in_clone_paint (ClutterActor *self)
14761 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14763 return self->priv->in_clone_paint;
14767 set_direction_recursive (ClutterActor *actor,
14768 gpointer user_data)
14770 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14772 clutter_actor_set_text_direction (actor, text_dir);
14778 * clutter_actor_set_text_direction:
14779 * @self: a #ClutterActor
14780 * @text_dir: the text direction for @self
14782 * Sets the #ClutterTextDirection for an actor
14784 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14786 * If @self implements #ClutterContainer then this function will recurse
14787 * inside all the children of @self (including the internal ones).
14789 * Composite actors not implementing #ClutterContainer, or actors requiring
14790 * special handling when the text direction changes, should connect to
14791 * the #GObject::notify signal for the #ClutterActor:text-direction property
14796 clutter_actor_set_text_direction (ClutterActor *self,
14797 ClutterTextDirection text_dir)
14799 ClutterActorPrivate *priv;
14801 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14802 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14806 if (priv->text_direction != text_dir)
14808 priv->text_direction = text_dir;
14810 /* we need to emit the notify::text-direction first, so that
14811 * the sub-classes can catch that and do specific handling of
14812 * the text direction; see clutter_text_direction_changed_cb()
14813 * inside clutter-text.c
14815 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14817 _clutter_actor_foreach_child (self, set_direction_recursive,
14818 GINT_TO_POINTER (text_dir));
14820 clutter_actor_queue_relayout (self);
14825 _clutter_actor_set_has_pointer (ClutterActor *self,
14826 gboolean has_pointer)
14828 ClutterActorPrivate *priv = self->priv;
14830 if (priv->has_pointer != has_pointer)
14832 priv->has_pointer = has_pointer;
14834 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14839 * clutter_actor_get_text_direction:
14840 * @self: a #ClutterActor
14842 * Retrieves the value set using clutter_actor_set_text_direction()
14844 * If no text direction has been previously set, the default text
14845 * direction, as returned by clutter_get_default_text_direction(), will
14846 * be returned instead
14848 * Return value: the #ClutterTextDirection for the actor
14852 ClutterTextDirection
14853 clutter_actor_get_text_direction (ClutterActor *self)
14855 ClutterActorPrivate *priv;
14857 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14858 CLUTTER_TEXT_DIRECTION_LTR);
14862 /* if no direction has been set yet use the default */
14863 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14864 priv->text_direction = clutter_get_default_text_direction ();
14866 return priv->text_direction;
14870 * clutter_actor_push_internal:
14871 * @self: a #ClutterActor
14873 * Should be used by actors implementing the #ClutterContainer and with
14874 * internal children added through clutter_actor_set_parent(), for instance:
14878 * my_actor_init (MyActor *self)
14880 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14882 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14884 * /* calling clutter_actor_set_parent() now will result in
14885 * * the internal flag being set on a child of MyActor
14888 * /* internal child - a background texture */
14889 * self->priv->background_tex = clutter_texture_new ();
14890 * clutter_actor_set_parent (self->priv->background_tex,
14891 * CLUTTER_ACTOR (self));
14893 * /* internal child - a label */
14894 * self->priv->label = clutter_text_new ();
14895 * clutter_actor_set_parent (self->priv->label,
14896 * CLUTTER_ACTOR (self));
14898 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14900 * /* calling clutter_actor_set_parent() now will not result in
14901 * * the internal flag being set on a child of MyActor
14906 * This function will be used by Clutter to toggle an "internal child"
14907 * flag whenever clutter_actor_set_parent() is called; internal children
14908 * are handled differently by Clutter, specifically when destroying their
14911 * Call clutter_actor_pop_internal() when you finished adding internal
14914 * Nested calls to clutter_actor_push_internal() are allowed, but each
14915 * one must by followed by a clutter_actor_pop_internal() call.
14919 * Deprecated: 1.10: All children of an actor are accessible through
14920 * the #ClutterActor API, and #ClutterActor implements the
14921 * #ClutterContainer interface, so this function is only useful
14922 * for legacy containers overriding the default implementation.
14925 clutter_actor_push_internal (ClutterActor *self)
14927 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14929 self->priv->internal_child += 1;
14933 * clutter_actor_pop_internal:
14934 * @self: a #ClutterActor
14936 * Disables the effects of clutter_actor_push_internal().
14940 * Deprecated: 1.10: All children of an actor are accessible through
14941 * the #ClutterActor API. This function is only useful for legacy
14942 * containers overriding the default implementation of the
14943 * #ClutterContainer interface.
14946 clutter_actor_pop_internal (ClutterActor *self)
14948 ClutterActorPrivate *priv;
14950 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14954 if (priv->internal_child == 0)
14956 g_warning ("Mismatched %s: you need to call "
14957 "clutter_actor_push_composite() at least once before "
14958 "calling this function", G_STRFUNC);
14962 priv->internal_child -= 1;
14966 * clutter_actor_has_pointer:
14967 * @self: a #ClutterActor
14969 * Checks whether an actor contains the pointer of a
14970 * #ClutterInputDevice
14972 * Return value: %TRUE if the actor contains the pointer, and
14978 clutter_actor_has_pointer (ClutterActor *self)
14980 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14982 return self->priv->has_pointer;
14985 /* XXX: This is a workaround for not being able to break the ABI of
14986 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14987 * clutter_actor_queue_clipped_redraw() for details.
14989 ClutterPaintVolume *
14990 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14992 return g_object_get_data (G_OBJECT (self),
14993 "-clutter-actor-queue-redraw-clip");
14997 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14998 ClutterPaintVolume *clip)
15000 g_object_set_data (G_OBJECT (self),
15001 "-clutter-actor-queue-redraw-clip",
15006 * clutter_actor_has_allocation:
15007 * @self: a #ClutterActor
15009 * Checks if the actor has an up-to-date allocation assigned to
15010 * it. This means that the actor should have an allocation: it's
15011 * visible and has a parent. It also means that there is no
15012 * outstanding relayout request in progress for the actor or its
15013 * children (There might be other outstanding layout requests in
15014 * progress that will cause the actor to get a new allocation
15015 * when the stage is laid out, however).
15017 * If this function returns %FALSE, then the actor will normally
15018 * be allocated before it is next drawn on the screen.
15020 * Return value: %TRUE if the actor has an up-to-date allocation
15025 clutter_actor_has_allocation (ClutterActor *self)
15027 ClutterActorPrivate *priv;
15029 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15033 return priv->parent != NULL &&
15034 CLUTTER_ACTOR_IS_VISIBLE (self) &&
15035 !priv->needs_allocation;
15039 * clutter_actor_add_action:
15040 * @self: a #ClutterActor
15041 * @action: a #ClutterAction
15043 * Adds @action to the list of actions applied to @self
15045 * A #ClutterAction can only belong to one actor at a time
15047 * The #ClutterActor will hold a reference on @action until either
15048 * clutter_actor_remove_action() or clutter_actor_clear_actions()
15054 clutter_actor_add_action (ClutterActor *self,
15055 ClutterAction *action)
15057 ClutterActorPrivate *priv;
15059 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15060 g_return_if_fail (CLUTTER_IS_ACTION (action));
15064 if (priv->actions == NULL)
15066 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15067 priv->actions->actor = self;
15070 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
15072 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15076 * clutter_actor_add_action_with_name:
15077 * @self: a #ClutterActor
15078 * @name: the name to set on the action
15079 * @action: a #ClutterAction
15081 * A convenience function for setting the name of a #ClutterAction
15082 * while adding it to the list of actions applied to @self
15084 * This function is the logical equivalent of:
15087 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15088 * clutter_actor_add_action (self, action);
15094 clutter_actor_add_action_with_name (ClutterActor *self,
15096 ClutterAction *action)
15098 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15099 g_return_if_fail (name != NULL);
15100 g_return_if_fail (CLUTTER_IS_ACTION (action));
15102 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15103 clutter_actor_add_action (self, action);
15107 * clutter_actor_remove_action:
15108 * @self: a #ClutterActor
15109 * @action: a #ClutterAction
15111 * Removes @action from the list of actions applied to @self
15113 * The reference held by @self on the #ClutterAction will be released
15118 clutter_actor_remove_action (ClutterActor *self,
15119 ClutterAction *action)
15121 ClutterActorPrivate *priv;
15123 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15124 g_return_if_fail (CLUTTER_IS_ACTION (action));
15128 if (priv->actions == NULL)
15131 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
15133 if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
15134 g_clear_object (&priv->actions);
15136 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15140 * clutter_actor_remove_action_by_name:
15141 * @self: a #ClutterActor
15142 * @name: the name of the action to remove
15144 * Removes the #ClutterAction with the given name from the list
15145 * of actions applied to @self
15150 clutter_actor_remove_action_by_name (ClutterActor *self,
15153 ClutterActorPrivate *priv;
15154 ClutterActorMeta *meta;
15156 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15157 g_return_if_fail (name != NULL);
15161 if (priv->actions == NULL)
15164 meta = _clutter_meta_group_get_meta (priv->actions, name);
15168 _clutter_meta_group_remove_meta (priv->actions, meta);
15170 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15174 * clutter_actor_get_actions:
15175 * @self: a #ClutterActor
15177 * Retrieves the list of actions applied to @self
15179 * Return value: (transfer container) (element-type Clutter.Action): a copy
15180 * of the list of #ClutterAction<!-- -->s. The contents of the list are
15181 * owned by the #ClutterActor. Use g_list_free() to free the resources
15182 * allocated by the returned #GList
15187 clutter_actor_get_actions (ClutterActor *self)
15189 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15191 if (self->priv->actions == NULL)
15194 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
15198 * clutter_actor_get_action:
15199 * @self: a #ClutterActor
15200 * @name: the name of the action to retrieve
15202 * Retrieves the #ClutterAction with the given name in the list
15203 * of actions applied to @self
15205 * Return value: (transfer none): a #ClutterAction for the given
15206 * name, or %NULL. The returned #ClutterAction is owned by the
15207 * actor and it should not be unreferenced directly
15212 clutter_actor_get_action (ClutterActor *self,
15215 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15216 g_return_val_if_fail (name != NULL, NULL);
15218 if (self->priv->actions == NULL)
15221 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
15225 * clutter_actor_clear_actions:
15226 * @self: a #ClutterActor
15228 * Clears the list of actions applied to @self
15233 clutter_actor_clear_actions (ClutterActor *self)
15235 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15237 if (self->priv->actions == NULL)
15240 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
15244 * clutter_actor_add_constraint:
15245 * @self: a #ClutterActor
15246 * @constraint: a #ClutterConstraint
15248 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15251 * The #ClutterActor will hold a reference on the @constraint until
15252 * either clutter_actor_remove_constraint() or
15253 * clutter_actor_clear_constraints() is called.
15258 clutter_actor_add_constraint (ClutterActor *self,
15259 ClutterConstraint *constraint)
15261 ClutterActorPrivate *priv;
15263 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15264 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15268 if (priv->constraints == NULL)
15270 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15271 priv->constraints->actor = self;
15274 _clutter_meta_group_add_meta (priv->constraints,
15275 CLUTTER_ACTOR_META (constraint));
15276 clutter_actor_queue_relayout (self);
15278 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15282 * clutter_actor_add_constraint_with_name:
15283 * @self: a #ClutterActor
15284 * @name: the name to set on the constraint
15285 * @constraint: a #ClutterConstraint
15287 * A convenience function for setting the name of a #ClutterConstraint
15288 * while adding it to the list of constraints applied to @self
15290 * This function is the logical equivalent of:
15293 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15294 * clutter_actor_add_constraint (self, constraint);
15300 clutter_actor_add_constraint_with_name (ClutterActor *self,
15302 ClutterConstraint *constraint)
15304 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15305 g_return_if_fail (name != NULL);
15306 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15308 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15309 clutter_actor_add_constraint (self, constraint);
15313 * clutter_actor_remove_constraint:
15314 * @self: a #ClutterActor
15315 * @constraint: a #ClutterConstraint
15317 * Removes @constraint from the list of constraints applied to @self
15319 * The reference held by @self on the #ClutterConstraint will be released
15324 clutter_actor_remove_constraint (ClutterActor *self,
15325 ClutterConstraint *constraint)
15327 ClutterActorPrivate *priv;
15329 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15330 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15334 if (priv->constraints == NULL)
15337 _clutter_meta_group_remove_meta (priv->constraints,
15338 CLUTTER_ACTOR_META (constraint));
15340 if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15341 g_clear_object (&priv->constraints);
15343 clutter_actor_queue_relayout (self);
15345 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15349 * clutter_actor_remove_constraint_by_name:
15350 * @self: a #ClutterActor
15351 * @name: the name of the constraint to remove
15353 * Removes the #ClutterConstraint with the given name from the list
15354 * of constraints applied to @self
15359 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15362 ClutterActorPrivate *priv;
15363 ClutterActorMeta *meta;
15365 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15366 g_return_if_fail (name != NULL);
15370 if (priv->constraints == NULL)
15373 meta = _clutter_meta_group_get_meta (priv->constraints, name);
15377 _clutter_meta_group_remove_meta (priv->constraints, meta);
15378 clutter_actor_queue_relayout (self);
15382 * clutter_actor_get_constraints:
15383 * @self: a #ClutterActor
15385 * Retrieves the list of constraints applied to @self
15387 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15388 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15389 * owned by the #ClutterActor. Use g_list_free() to free the resources
15390 * allocated by the returned #GList
15395 clutter_actor_get_constraints (ClutterActor *self)
15397 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15399 if (self->priv->constraints == NULL)
15402 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15406 * clutter_actor_get_constraint:
15407 * @self: a #ClutterActor
15408 * @name: the name of the constraint to retrieve
15410 * Retrieves the #ClutterConstraint with the given name in the list
15411 * of constraints applied to @self
15413 * Return value: (transfer none): a #ClutterConstraint for the given
15414 * name, or %NULL. The returned #ClutterConstraint is owned by the
15415 * actor and it should not be unreferenced directly
15419 ClutterConstraint *
15420 clutter_actor_get_constraint (ClutterActor *self,
15423 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15424 g_return_val_if_fail (name != NULL, NULL);
15426 if (self->priv->constraints == NULL)
15429 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15433 * clutter_actor_clear_constraints:
15434 * @self: a #ClutterActor
15436 * Clears the list of constraints applied to @self
15441 clutter_actor_clear_constraints (ClutterActor *self)
15443 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15445 if (self->priv->constraints == NULL)
15448 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15450 clutter_actor_queue_relayout (self);
15454 * clutter_actor_set_clip_to_allocation:
15455 * @self: a #ClutterActor
15456 * @clip_set: %TRUE to apply a clip tracking the allocation
15458 * Sets whether @self should be clipped to the same size as its
15464 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15467 ClutterActorPrivate *priv;
15469 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15471 clip_set = !!clip_set;
15475 if (priv->clip_to_allocation != clip_set)
15477 priv->clip_to_allocation = clip_set;
15479 clutter_actor_queue_redraw (self);
15481 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15486 * clutter_actor_get_clip_to_allocation:
15487 * @self: a #ClutterActor
15489 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15491 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15496 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15498 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15500 return self->priv->clip_to_allocation;
15504 * clutter_actor_add_effect:
15505 * @self: a #ClutterActor
15506 * @effect: a #ClutterEffect
15508 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15510 * The #ClutterActor will hold a reference on the @effect until either
15511 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15517 clutter_actor_add_effect (ClutterActor *self,
15518 ClutterEffect *effect)
15520 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15521 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15523 _clutter_actor_add_effect_internal (self, effect);
15525 clutter_actor_queue_redraw (self);
15527 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15531 * clutter_actor_add_effect_with_name:
15532 * @self: a #ClutterActor
15533 * @name: the name to set on the effect
15534 * @effect: a #ClutterEffect
15536 * A convenience function for setting the name of a #ClutterEffect
15537 * while adding it to the list of effectss applied to @self
15539 * This function is the logical equivalent of:
15542 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15543 * clutter_actor_add_effect (self, effect);
15549 clutter_actor_add_effect_with_name (ClutterActor *self,
15551 ClutterEffect *effect)
15553 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15554 g_return_if_fail (name != NULL);
15555 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15557 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15558 clutter_actor_add_effect (self, effect);
15562 * clutter_actor_remove_effect:
15563 * @self: a #ClutterActor
15564 * @effect: a #ClutterEffect
15566 * Removes @effect from the list of effects applied to @self
15568 * The reference held by @self on the #ClutterEffect will be released
15573 clutter_actor_remove_effect (ClutterActor *self,
15574 ClutterEffect *effect)
15576 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15577 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15579 _clutter_actor_remove_effect_internal (self, effect);
15581 clutter_actor_queue_redraw (self);
15583 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15587 * clutter_actor_remove_effect_by_name:
15588 * @self: a #ClutterActor
15589 * @name: the name of the effect to remove
15591 * Removes the #ClutterEffect with the given name from the list
15592 * of effects applied to @self
15597 clutter_actor_remove_effect_by_name (ClutterActor *self,
15600 ClutterActorPrivate *priv;
15601 ClutterActorMeta *meta;
15603 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15604 g_return_if_fail (name != NULL);
15608 if (priv->effects == NULL)
15611 meta = _clutter_meta_group_get_meta (priv->effects, name);
15615 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15619 * clutter_actor_get_effects:
15620 * @self: a #ClutterActor
15622 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15624 * Return value: (transfer container) (element-type Clutter.Effect): a list
15625 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15626 * list are owned by Clutter and they should not be freed. You should
15627 * free the returned list using g_list_free() when done
15632 clutter_actor_get_effects (ClutterActor *self)
15634 ClutterActorPrivate *priv;
15636 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15640 if (priv->effects == NULL)
15643 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15647 * clutter_actor_get_effect:
15648 * @self: a #ClutterActor
15649 * @name: the name of the effect to retrieve
15651 * Retrieves the #ClutterEffect with the given name in the list
15652 * of effects applied to @self
15654 * Return value: (transfer none): a #ClutterEffect for the given
15655 * name, or %NULL. The returned #ClutterEffect is owned by the
15656 * actor and it should not be unreferenced directly
15661 clutter_actor_get_effect (ClutterActor *self,
15664 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15665 g_return_val_if_fail (name != NULL, NULL);
15667 if (self->priv->effects == NULL)
15670 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15674 * clutter_actor_clear_effects:
15675 * @self: a #ClutterActor
15677 * Clears the list of effects applied to @self
15682 clutter_actor_clear_effects (ClutterActor *self)
15684 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15686 if (self->priv->effects == NULL)
15689 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15691 clutter_actor_queue_redraw (self);
15695 * clutter_actor_has_key_focus:
15696 * @self: a #ClutterActor
15698 * Checks whether @self is the #ClutterActor that has key focus
15700 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15705 clutter_actor_has_key_focus (ClutterActor *self)
15707 ClutterActor *stage;
15709 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15711 stage = _clutter_actor_get_stage_internal (self);
15715 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15719 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15720 ClutterPaintVolume *pv)
15722 ClutterActorPrivate *priv = self->priv;
15724 /* Actors are only expected to report a valid paint volume
15725 * while they have a valid allocation. */
15726 if (G_UNLIKELY (priv->needs_allocation))
15728 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15729 "Actor needs allocation",
15730 _clutter_actor_get_debug_name (self));
15734 /* Check if there are any handlers connected to the paint
15735 * signal. If there are then all bets are off for what the paint
15736 * volume for this actor might possibly be!
15738 * XXX: It's expected that this is going to end up being quite a
15739 * costly check to have to do here, but we haven't come up with
15740 * another solution that can reliably catch paint signal handlers at
15741 * the right time to either avoid artefacts due to invalid stage
15742 * clipping or due to incorrect culling.
15744 * Previously we checked in clutter_actor_paint(), but at that time
15745 * we may already be using a stage clip that could be derived from
15746 * an invalid paint-volume. We used to try and handle that by
15747 * queuing a follow up, unclipped, redraw but still the previous
15748 * checking wasn't enough to catch invalid volumes involved in
15749 * culling (considering that containers may derive their volume from
15750 * children that haven't yet been painted)
15752 * Longer term, improved solutions could be:
15753 * - Disallow painting in the paint signal, only allow using it
15754 * for tracking when paints happen. We can add another API that
15755 * allows monkey patching the paint of arbitrary actors but in a
15756 * more controlled way and that also supports modifying the
15758 * - If we could be notified somehow when signal handlers are
15759 * connected we wouldn't have to poll for handlers like this.
15761 if (g_signal_has_handler_pending (self,
15762 actor_signals[PAINT],
15766 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15767 "Actor has \"paint\" signal handlers",
15768 _clutter_actor_get_debug_name (self));
15772 _clutter_paint_volume_init_static (pv, self);
15774 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15776 clutter_paint_volume_free (pv);
15777 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15778 "Actor failed to report a volume",
15779 _clutter_actor_get_debug_name (self));
15783 /* since effects can modify the paint volume, we allow them to actually
15784 * do this by making get_paint_volume() "context sensitive"
15786 if (priv->effects != NULL)
15788 if (priv->current_effect != NULL)
15790 const GList *effects, *l;
15792 /* if we are being called from within the paint sequence of
15793 * an actor, get the paint volume up to the current effect
15795 effects = _clutter_meta_group_peek_metas (priv->effects);
15797 l != NULL || (l != NULL && l->data != priv->current_effect);
15800 if (!_clutter_effect_get_paint_volume (l->data, pv))
15802 clutter_paint_volume_free (pv);
15803 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15804 "Effect (%s) failed to report a volume",
15805 _clutter_actor_get_debug_name (self),
15806 _clutter_actor_meta_get_debug_name (l->data));
15813 const GList *effects, *l;
15815 /* otherwise, get the cumulative volume */
15816 effects = _clutter_meta_group_peek_metas (priv->effects);
15817 for (l = effects; l != NULL; l = l->next)
15818 if (!_clutter_effect_get_paint_volume (l->data, pv))
15820 clutter_paint_volume_free (pv);
15821 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15822 "Effect (%s) failed to report a volume",
15823 _clutter_actor_get_debug_name (self),
15824 _clutter_actor_meta_get_debug_name (l->data));
15833 /* The public clutter_actor_get_paint_volume API returns a const
15834 * pointer since we return a pointer directly to the cached
15835 * PaintVolume associated with the actor and don't want the user to
15836 * inadvertently modify it, but for internal uses we sometimes need
15837 * access to the same PaintVolume but need to apply some book-keeping
15838 * modifications to it so we don't want a const pointer.
15840 static ClutterPaintVolume *
15841 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15843 ClutterActorPrivate *priv;
15847 if (priv->paint_volume_valid)
15848 clutter_paint_volume_free (&priv->paint_volume);
15850 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15852 priv->paint_volume_valid = TRUE;
15853 return &priv->paint_volume;
15857 priv->paint_volume_valid = FALSE;
15863 * clutter_actor_get_paint_volume:
15864 * @self: a #ClutterActor
15866 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15867 * when a paint volume can't be determined.
15869 * The paint volume is defined as the 3D space occupied by an actor
15870 * when being painted.
15872 * This function will call the <function>get_paint_volume()</function>
15873 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15874 * should not usually care about overriding the default implementation,
15875 * unless they are, for instance: painting outside their allocation, or
15876 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15879 * <note>2D actors overriding <function>get_paint_volume()</function>
15880 * ensure their volume has a depth of 0. (This will be true so long as
15881 * you don't call clutter_paint_volume_set_depth().)</note>
15883 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15884 * or %NULL if no volume could be determined. The returned pointer
15885 * is not guaranteed to be valid across multiple frames; if you want
15886 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15890 const ClutterPaintVolume *
15891 clutter_actor_get_paint_volume (ClutterActor *self)
15893 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15895 return _clutter_actor_get_paint_volume_mutable (self);
15899 * clutter_actor_get_transformed_paint_volume:
15900 * @self: a #ClutterActor
15901 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15902 * (or %NULL for the stage)
15904 * Retrieves the 3D paint volume of an actor like
15905 * clutter_actor_get_paint_volume() does (Please refer to the
15906 * documentation of clutter_actor_get_paint_volume() for more
15907 * details.) and it additionally transforms the paint volume into the
15908 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15909 * is passed for @relative_to_ancestor)
15911 * This can be used by containers that base their paint volume on
15912 * the volume of their children. Such containers can query the
15913 * transformed paint volume of all of its children and union them
15914 * together using clutter_paint_volume_union().
15916 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15917 * or %NULL if no volume could be determined. The returned pointer is
15918 * not guaranteed to be valid across multiple frames; if you wish to
15919 * keep it, you will have to copy it using clutter_paint_volume_copy().
15923 const ClutterPaintVolume *
15924 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15925 ClutterActor *relative_to_ancestor)
15927 const ClutterPaintVolume *volume;
15928 ClutterActor *stage;
15929 ClutterPaintVolume *transformed_volume;
15931 stage = _clutter_actor_get_stage_internal (self);
15932 if (G_UNLIKELY (stage == NULL))
15935 if (relative_to_ancestor == NULL)
15936 relative_to_ancestor = stage;
15938 volume = clutter_actor_get_paint_volume (self);
15939 if (volume == NULL)
15942 transformed_volume =
15943 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15945 _clutter_paint_volume_copy_static (volume, transformed_volume);
15947 _clutter_paint_volume_transform_relative (transformed_volume,
15948 relative_to_ancestor);
15950 return transformed_volume;
15954 * clutter_actor_get_paint_box:
15955 * @self: a #ClutterActor
15956 * @box: (out): return location for a #ClutterActorBox
15958 * Retrieves the paint volume of the passed #ClutterActor, and
15959 * transforms it into a 2D bounding box in stage coordinates.
15961 * This function is useful to determine the on screen area occupied by
15962 * the actor. The box is only an approximation and may often be
15963 * considerably larger due to the optimizations used to calculate the
15964 * box. The box is never smaller though, so it can reliably be used
15967 * There are times when a 2D paint box can't be determined, e.g.
15968 * because the actor isn't yet parented under a stage or because
15969 * the actor is unable to determine a paint volume.
15971 * Return value: %TRUE if a 2D paint box could be determined, else
15977 clutter_actor_get_paint_box (ClutterActor *self,
15978 ClutterActorBox *box)
15980 ClutterActor *stage;
15981 ClutterPaintVolume *pv;
15983 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15984 g_return_val_if_fail (box != NULL, FALSE);
15986 stage = _clutter_actor_get_stage_internal (self);
15987 if (G_UNLIKELY (!stage))
15990 pv = _clutter_actor_get_paint_volume_mutable (self);
15991 if (G_UNLIKELY (!pv))
15994 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
16000 * clutter_actor_has_overlaps:
16001 * @self: A #ClutterActor
16003 * Asks the actor's implementation whether it may contain overlapping
16006 * For example; Clutter may use this to determine whether the painting
16007 * should be redirected to an offscreen buffer to correctly implement
16008 * the opacity property.
16010 * Custom actors can override the default response by implementing the
16011 * #ClutterActor <function>has_overlaps</function> virtual function. See
16012 * clutter_actor_set_offscreen_redirect() for more information.
16014 * Return value: %TRUE if the actor may have overlapping primitives, and
16020 clutter_actor_has_overlaps (ClutterActor *self)
16022 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
16024 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
16028 * clutter_actor_has_effects:
16029 * @self: A #ClutterActor
16031 * Returns whether the actor has any effects applied.
16033 * Return value: %TRUE if the actor has any effects,
16039 clutter_actor_has_effects (ClutterActor *self)
16041 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16043 if (self->priv->effects == NULL)
16046 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
16050 * clutter_actor_has_constraints:
16051 * @self: A #ClutterActor
16053 * Returns whether the actor has any constraints applied.
16055 * Return value: %TRUE if the actor has any constraints,
16061 clutter_actor_has_constraints (ClutterActor *self)
16063 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16065 return self->priv->constraints != NULL;
16069 * clutter_actor_has_actions:
16070 * @self: A #ClutterActor
16072 * Returns whether the actor has any actions applied.
16074 * Return value: %TRUE if the actor has any actions,
16080 clutter_actor_has_actions (ClutterActor *self)
16082 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16084 return self->priv->actions != NULL;
16088 * clutter_actor_get_n_children:
16089 * @self: a #ClutterActor
16091 * Retrieves the number of children of @self.
16093 * Return value: the number of children of an actor
16098 clutter_actor_get_n_children (ClutterActor *self)
16100 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
16102 return self->priv->n_children;
16106 * clutter_actor_get_child_at_index:
16107 * @self: a #ClutterActor
16108 * @index_: the position in the list of children
16110 * Retrieves the actor at the given @index_ inside the list of
16111 * children of @self.
16113 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16118 clutter_actor_get_child_at_index (ClutterActor *self,
16121 ClutterActor *iter;
16124 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16125 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
16127 for (iter = self->priv->first_child, i = 0;
16128 iter != NULL && i < index_;
16129 iter = iter->priv->next_sibling, i += 1)
16136 * _clutter_actor_foreach_child:
16137 * @actor: The actor whos children you want to iterate
16138 * @callback: The function to call for each child
16139 * @user_data: Private data to pass to @callback
16141 * Calls a given @callback once for each child of the specified @actor and
16142 * passing the @user_data pointer each time.
16144 * Return value: returns %TRUE if all children were iterated, else
16145 * %FALSE if a callback broke out of iteration early.
16148 _clutter_actor_foreach_child (ClutterActor *self,
16149 ClutterForeachCallback callback,
16150 gpointer user_data)
16152 ClutterActor *iter;
16155 if (self->priv->first_child == NULL)
16159 iter = self->priv->first_child;
16161 /* we use this form so that it's safe to change the children
16162 * list while iterating it
16164 while (cont && iter != NULL)
16166 ClutterActor *next = iter->priv->next_sibling;
16168 cont = callback (iter, user_data);
16177 /* For debugging purposes this gives us a simple way to print out
16178 * the scenegraph e.g in gdb using:
16180 * _clutter_actor_traverse (stage,
16182 * clutter_debug_print_actor_cb,
16187 static ClutterActorTraverseVisitFlags
16188 clutter_debug_print_actor_cb (ClutterActor *actor,
16192 g_print ("%*s%s:%p\n",
16194 _clutter_actor_get_debug_name (actor),
16197 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16202 _clutter_actor_traverse_breadth (ClutterActor *actor,
16203 ClutterTraverseCallback callback,
16204 gpointer user_data)
16206 GQueue *queue = g_queue_new ();
16207 ClutterActor dummy;
16208 int current_depth = 0;
16210 g_queue_push_tail (queue, actor);
16211 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
16213 while ((actor = g_queue_pop_head (queue)))
16215 ClutterActorTraverseVisitFlags flags;
16217 if (actor == &dummy)
16220 g_queue_push_tail (queue, &dummy);
16224 flags = callback (actor, current_depth, user_data);
16225 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16227 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16229 ClutterActor *iter;
16231 for (iter = actor->priv->first_child;
16233 iter = iter->priv->next_sibling)
16235 g_queue_push_tail (queue, iter);
16240 g_queue_free (queue);
16243 static ClutterActorTraverseVisitFlags
16244 _clutter_actor_traverse_depth (ClutterActor *actor,
16245 ClutterTraverseCallback before_children_callback,
16246 ClutterTraverseCallback after_children_callback,
16248 gpointer user_data)
16250 ClutterActorTraverseVisitFlags flags;
16252 flags = before_children_callback (actor, current_depth, user_data);
16253 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16254 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16256 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16258 ClutterActor *iter;
16260 for (iter = actor->priv->first_child;
16262 iter = iter->priv->next_sibling)
16264 flags = _clutter_actor_traverse_depth (iter,
16265 before_children_callback,
16266 after_children_callback,
16270 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16271 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16275 if (after_children_callback)
16276 return after_children_callback (actor, current_depth, user_data);
16278 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16281 /* _clutter_actor_traverse:
16282 * @actor: The actor to start traversing the graph from
16283 * @flags: These flags may affect how the traversal is done
16284 * @before_children_callback: A function to call before visiting the
16285 * children of the current actor.
16286 * @after_children_callback: A function to call after visiting the
16287 * children of the current actor. (Ignored if
16288 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16289 * @user_data: The private data to pass to the callbacks
16291 * Traverses the scenegraph starting at the specified @actor and
16292 * descending through all its children and its children's children.
16293 * For each actor traversed @before_children_callback and
16294 * @after_children_callback are called with the specified
16295 * @user_data, before and after visiting that actor's children.
16297 * The callbacks can return flags that affect the ongoing traversal
16298 * such as by skipping over an actors children or bailing out of
16299 * any further traversing.
16302 _clutter_actor_traverse (ClutterActor *actor,
16303 ClutterActorTraverseFlags flags,
16304 ClutterTraverseCallback before_children_callback,
16305 ClutterTraverseCallback after_children_callback,
16306 gpointer user_data)
16308 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16309 _clutter_actor_traverse_breadth (actor,
16310 before_children_callback,
16312 else /* DEPTH_FIRST */
16313 _clutter_actor_traverse_depth (actor,
16314 before_children_callback,
16315 after_children_callback,
16316 0, /* start depth */
16321 on_layout_manager_changed (ClutterLayoutManager *manager,
16322 ClutterActor *self)
16324 clutter_actor_queue_relayout (self);
16328 * clutter_actor_set_layout_manager:
16329 * @self: a #ClutterActor
16330 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16332 * Sets the #ClutterLayoutManager delegate object that will be used to
16333 * lay out the children of @self.
16335 * The #ClutterActor will take a reference on the passed @manager which
16336 * will be released either when the layout manager is removed, or when
16337 * the actor is destroyed.
16342 clutter_actor_set_layout_manager (ClutterActor *self,
16343 ClutterLayoutManager *manager)
16345 ClutterActorPrivate *priv;
16347 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16348 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16352 if (priv->layout_manager != NULL)
16354 g_signal_handlers_disconnect_by_func (priv->layout_manager,
16355 G_CALLBACK (on_layout_manager_changed),
16357 clutter_layout_manager_set_container (priv->layout_manager, NULL);
16358 g_clear_object (&priv->layout_manager);
16361 priv->layout_manager = manager;
16363 if (priv->layout_manager != NULL)
16365 g_object_ref_sink (priv->layout_manager);
16366 clutter_layout_manager_set_container (priv->layout_manager,
16367 CLUTTER_CONTAINER (self));
16368 g_signal_connect (priv->layout_manager, "layout-changed",
16369 G_CALLBACK (on_layout_manager_changed),
16373 clutter_actor_queue_relayout (self);
16375 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16379 * clutter_actor_get_layout_manager:
16380 * @self: a #ClutterActor
16382 * Retrieves the #ClutterLayoutManager used by @self.
16384 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16389 ClutterLayoutManager *
16390 clutter_actor_get_layout_manager (ClutterActor *self)
16392 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16394 return self->priv->layout_manager;
16397 static const ClutterLayoutInfo default_layout_info = {
16398 CLUTTER_POINT_INIT_ZERO, /* fixed-pos */
16399 { 0, 0, 0, 0 }, /* margin */
16400 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
16401 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
16402 FALSE, FALSE, /* expand */
16403 CLUTTER_SIZE_INIT_ZERO, /* minimum */
16404 CLUTTER_SIZE_INIT_ZERO, /* natural */
16408 layout_info_free (gpointer data)
16410 if (G_LIKELY (data != NULL))
16411 g_slice_free (ClutterLayoutInfo, data);
16415 * _clutter_actor_peek_layout_info:
16416 * @self: a #ClutterActor
16418 * Retrieves a pointer to the ClutterLayoutInfo structure.
16420 * If the actor does not have a ClutterLayoutInfo associated to it, %NULL is returned.
16422 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16424 ClutterLayoutInfo *
16425 _clutter_actor_peek_layout_info (ClutterActor *self)
16427 return g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16431 * _clutter_actor_get_layout_info:
16432 * @self: a #ClutterActor
16434 * Retrieves a pointer to the ClutterLayoutInfo structure.
16436 * If the actor does not have a ClutterLayoutInfo associated to it, one
16437 * will be created and initialized to the default values.
16439 * This function should be used for setters.
16441 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16444 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16446 ClutterLayoutInfo *
16447 _clutter_actor_get_layout_info (ClutterActor *self)
16449 ClutterLayoutInfo *retval;
16451 retval = _clutter_actor_peek_layout_info (self);
16452 if (retval == NULL)
16454 retval = g_slice_new (ClutterLayoutInfo);
16456 *retval = default_layout_info;
16458 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16467 * _clutter_actor_get_layout_info_or_defaults:
16468 * @self: a #ClutterActor
16470 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16472 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16473 * then the default structure will be returned.
16475 * This function should only be used for getters.
16477 * Return value: a const pointer to the ClutterLayoutInfo structure
16479 const ClutterLayoutInfo *
16480 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16482 const ClutterLayoutInfo *info;
16484 info = _clutter_actor_peek_layout_info (self);
16486 return &default_layout_info;
16492 * clutter_actor_set_x_align:
16493 * @self: a #ClutterActor
16494 * @x_align: the horizontal alignment policy
16496 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16497 * actor received extra horizontal space.
16499 * See also the #ClutterActor:x-align property.
16504 clutter_actor_set_x_align (ClutterActor *self,
16505 ClutterActorAlign x_align)
16507 ClutterLayoutInfo *info;
16509 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16511 info = _clutter_actor_get_layout_info (self);
16513 if (info->x_align != x_align)
16515 info->x_align = x_align;
16517 clutter_actor_queue_relayout (self);
16519 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16524 * clutter_actor_get_x_align:
16525 * @self: a #ClutterActor
16527 * Retrieves the horizontal alignment policy set using
16528 * clutter_actor_set_x_align().
16530 * Return value: the horizontal alignment policy.
16535 clutter_actor_get_x_align (ClutterActor *self)
16537 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16539 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16543 * clutter_actor_set_y_align:
16544 * @self: a #ClutterActor
16545 * @y_align: the vertical alignment policy
16547 * Sets the vertical alignment policy of a #ClutterActor, in case the
16548 * actor received extra vertical space.
16550 * See also the #ClutterActor:y-align property.
16555 clutter_actor_set_y_align (ClutterActor *self,
16556 ClutterActorAlign y_align)
16558 ClutterLayoutInfo *info;
16560 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16562 info = _clutter_actor_get_layout_info (self);
16564 if (info->y_align != y_align)
16566 info->y_align = y_align;
16568 clutter_actor_queue_relayout (self);
16570 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16575 * clutter_actor_get_y_align:
16576 * @self: a #ClutterActor
16578 * Retrieves the vertical alignment policy set using
16579 * clutter_actor_set_y_align().
16581 * Return value: the vertical alignment policy.
16586 clutter_actor_get_y_align (ClutterActor *self)
16588 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16590 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16594 * clutter_actor_set_margin:
16595 * @self: a #ClutterActor
16596 * @margin: a #ClutterMargin
16598 * Sets all the components of the margin of a #ClutterActor.
16603 clutter_actor_set_margin (ClutterActor *self,
16604 const ClutterMargin *margin)
16606 ClutterLayoutInfo *info;
16610 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16611 g_return_if_fail (margin != NULL);
16613 obj = G_OBJECT (self);
16616 g_object_freeze_notify (obj);
16618 info = _clutter_actor_get_layout_info (self);
16620 if (info->margin.top != margin->top)
16622 info->margin.top = margin->top;
16623 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16627 if (info->margin.right != margin->right)
16629 info->margin.right = margin->right;
16630 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16634 if (info->margin.bottom != margin->bottom)
16636 info->margin.bottom = margin->bottom;
16637 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16641 if (info->margin.left != margin->left)
16643 info->margin.left = margin->left;
16644 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16649 clutter_actor_queue_relayout (self);
16651 g_object_thaw_notify (obj);
16655 * clutter_actor_get_margin:
16656 * @self: a #ClutterActor
16657 * @margin: (out caller-allocates): return location for a #ClutterMargin
16659 * Retrieves all the components of the margin of a #ClutterActor.
16664 clutter_actor_get_margin (ClutterActor *self,
16665 ClutterMargin *margin)
16667 const ClutterLayoutInfo *info;
16669 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16670 g_return_if_fail (margin != NULL);
16672 info = _clutter_actor_get_layout_info_or_defaults (self);
16674 *margin = info->margin;
16678 * clutter_actor_set_margin_top:
16679 * @self: a #ClutterActor
16680 * @margin: the top margin
16682 * Sets the margin from the top of a #ClutterActor.
16687 clutter_actor_set_margin_top (ClutterActor *self,
16690 ClutterLayoutInfo *info;
16692 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16693 g_return_if_fail (margin >= 0.f);
16695 info = _clutter_actor_get_layout_info (self);
16697 if (info->margin.top == margin)
16700 info->margin.top = margin;
16702 clutter_actor_queue_relayout (self);
16704 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16708 * clutter_actor_get_margin_top:
16709 * @self: a #ClutterActor
16711 * Retrieves the top margin of a #ClutterActor.
16713 * Return value: the top margin
16718 clutter_actor_get_margin_top (ClutterActor *self)
16720 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16722 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16726 * clutter_actor_set_margin_bottom:
16727 * @self: a #ClutterActor
16728 * @margin: the bottom margin
16730 * Sets the margin from the bottom of a #ClutterActor.
16735 clutter_actor_set_margin_bottom (ClutterActor *self,
16738 ClutterLayoutInfo *info;
16740 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16741 g_return_if_fail (margin >= 0.f);
16743 info = _clutter_actor_get_layout_info (self);
16745 if (info->margin.bottom == margin)
16748 info->margin.bottom = margin;
16750 clutter_actor_queue_relayout (self);
16752 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16756 * clutter_actor_get_margin_bottom:
16757 * @self: a #ClutterActor
16759 * Retrieves the bottom margin of a #ClutterActor.
16761 * Return value: the bottom margin
16766 clutter_actor_get_margin_bottom (ClutterActor *self)
16768 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16770 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16774 * clutter_actor_set_margin_left:
16775 * @self: a #ClutterActor
16776 * @margin: the left margin
16778 * Sets the margin from the left of a #ClutterActor.
16783 clutter_actor_set_margin_left (ClutterActor *self,
16786 ClutterLayoutInfo *info;
16788 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16789 g_return_if_fail (margin >= 0.f);
16791 info = _clutter_actor_get_layout_info (self);
16793 if (info->margin.left == margin)
16796 info->margin.left = margin;
16798 clutter_actor_queue_relayout (self);
16800 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16804 * clutter_actor_get_margin_left:
16805 * @self: a #ClutterActor
16807 * Retrieves the left margin of a #ClutterActor.
16809 * Return value: the left margin
16814 clutter_actor_get_margin_left (ClutterActor *self)
16816 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16818 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16822 * clutter_actor_set_margin_right:
16823 * @self: a #ClutterActor
16824 * @margin: the right margin
16826 * Sets the margin from the right of a #ClutterActor.
16831 clutter_actor_set_margin_right (ClutterActor *self,
16834 ClutterLayoutInfo *info;
16836 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16837 g_return_if_fail (margin >= 0.f);
16839 info = _clutter_actor_get_layout_info (self);
16841 if (info->margin.right == margin)
16844 info->margin.right = margin;
16846 clutter_actor_queue_relayout (self);
16848 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16852 * clutter_actor_get_margin_right:
16853 * @self: a #ClutterActor
16855 * Retrieves the right margin of a #ClutterActor.
16857 * Return value: the right margin
16862 clutter_actor_get_margin_right (ClutterActor *self)
16864 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16866 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16870 clutter_actor_set_background_color_internal (ClutterActor *self,
16871 const ClutterColor *color)
16873 ClutterActorPrivate *priv = self->priv;
16876 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16879 obj = G_OBJECT (self);
16881 priv->bg_color = *color;
16882 priv->bg_color_set = TRUE;
16884 clutter_actor_queue_redraw (self);
16886 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16887 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16891 * clutter_actor_set_background_color:
16892 * @self: a #ClutterActor
16893 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16896 * Sets the background color of a #ClutterActor.
16898 * The background color will be used to cover the whole allocation of the
16899 * actor. The default background color of an actor is transparent.
16901 * To check whether an actor has a background color, you can use the
16902 * #ClutterActor:background-color-set actor property.
16904 * The #ClutterActor:background-color property is animatable.
16909 clutter_actor_set_background_color (ClutterActor *self,
16910 const ClutterColor *color)
16912 ClutterActorPrivate *priv;
16914 GParamSpec *bg_color_pspec;
16916 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16918 obj = G_OBJECT (self);
16924 priv->bg_color_set = FALSE;
16925 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16926 clutter_actor_queue_redraw (self);
16930 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16931 if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16933 _clutter_actor_create_transition (self, bg_color_pspec,
16938 _clutter_actor_update_transition (self, bg_color_pspec, color);
16940 clutter_actor_queue_redraw (self);
16944 * clutter_actor_get_background_color:
16945 * @self: a #ClutterActor
16946 * @color: (out caller-allocates): return location for a #ClutterColor
16948 * Retrieves the color set using clutter_actor_set_background_color().
16953 clutter_actor_get_background_color (ClutterActor *self,
16954 ClutterColor *color)
16956 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16957 g_return_if_fail (color != NULL);
16959 *color = self->priv->bg_color;
16963 * clutter_actor_get_previous_sibling:
16964 * @self: a #ClutterActor
16966 * Retrieves the sibling of @self that comes before it in the list
16967 * of children of @self's parent.
16969 * The returned pointer is only valid until the scene graph changes; it
16970 * is not safe to modify the list of children of @self while iterating
16973 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16978 clutter_actor_get_previous_sibling (ClutterActor *self)
16980 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16982 return self->priv->prev_sibling;
16986 * clutter_actor_get_next_sibling:
16987 * @self: a #ClutterActor
16989 * Retrieves the sibling of @self that comes after it in the list
16990 * of children of @self's parent.
16992 * The returned pointer is only valid until the scene graph changes; it
16993 * is not safe to modify the list of children of @self while iterating
16996 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
17001 clutter_actor_get_next_sibling (ClutterActor *self)
17003 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17005 return self->priv->next_sibling;
17009 * clutter_actor_get_first_child:
17010 * @self: a #ClutterActor
17012 * Retrieves the first child of @self.
17014 * The returned pointer is only valid until the scene graph changes; it
17015 * is not safe to modify the list of children of @self while iterating
17018 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
17023 clutter_actor_get_first_child (ClutterActor *self)
17025 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17027 return self->priv->first_child;
17031 * clutter_actor_get_last_child:
17032 * @self: a #ClutterActor
17034 * Retrieves the last child of @self.
17036 * The returned pointer is only valid until the scene graph changes; it
17037 * is not safe to modify the list of children of @self while iterating
17040 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
17045 clutter_actor_get_last_child (ClutterActor *self)
17047 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17049 return self->priv->last_child;
17052 /* easy way to have properly named fields instead of the dummy ones
17053 * we use in the public structure
17055 typedef struct _RealActorIter
17057 ClutterActor *root; /* dummy1 */
17058 ClutterActor *current; /* dummy2 */
17059 gpointer padding_1; /* dummy3 */
17060 gint age; /* dummy4 */
17061 gpointer padding_2; /* dummy5 */
17065 * clutter_actor_iter_init:
17066 * @iter: a #ClutterActorIter
17067 * @root: a #ClutterActor
17069 * Initializes a #ClutterActorIter, which can then be used to iterate
17070 * efficiently over a section of the scene graph, and associates it
17073 * Modifying the scene graph section that contains @root will invalidate
17077 * ClutterActorIter iter;
17078 * ClutterActor *child;
17080 * clutter_actor_iter_init (&iter, container);
17081 * while (clutter_actor_iter_next (&iter, &child))
17083 * /* do something with child */
17090 clutter_actor_iter_init (ClutterActorIter *iter,
17091 ClutterActor *root)
17093 RealActorIter *ri = (RealActorIter *) iter;
17095 g_return_if_fail (iter != NULL);
17096 g_return_if_fail (CLUTTER_IS_ACTOR (root));
17099 ri->current = NULL;
17100 ri->age = root->priv->age;
17104 * clutter_actor_iter_next:
17105 * @iter: a #ClutterActorIter
17106 * @child: (out): return location for a #ClutterActor
17108 * Advances the @iter and retrieves the next child of the root #ClutterActor
17109 * that was used to initialize the #ClutterActorIterator.
17111 * If the iterator can advance, this function returns %TRUE and sets the
17114 * If the iterator cannot advance, this function returns %FALSE, and
17115 * the contents of @child are undefined.
17117 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17122 clutter_actor_iter_next (ClutterActorIter *iter,
17123 ClutterActor **child)
17125 RealActorIter *ri = (RealActorIter *) iter;
17127 g_return_val_if_fail (iter != NULL, FALSE);
17128 g_return_val_if_fail (ri->root != NULL, FALSE);
17129 #ifndef G_DISABLE_ASSERT
17130 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17133 if (ri->current == NULL)
17134 ri->current = ri->root->priv->first_child;
17136 ri->current = ri->current->priv->next_sibling;
17139 *child = ri->current;
17141 return ri->current != NULL;
17145 * clutter_actor_iter_prev:
17146 * @iter: a #ClutterActorIter
17147 * @child: (out): return location for a #ClutterActor
17149 * Advances the @iter and retrieves the previous child of the root
17150 * #ClutterActor that was used to initialize the #ClutterActorIterator.
17152 * If the iterator can advance, this function returns %TRUE and sets the
17155 * If the iterator cannot advance, this function returns %FALSE, and
17156 * the contents of @child are undefined.
17158 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17163 clutter_actor_iter_prev (ClutterActorIter *iter,
17164 ClutterActor **child)
17166 RealActorIter *ri = (RealActorIter *) iter;
17168 g_return_val_if_fail (iter != NULL, FALSE);
17169 g_return_val_if_fail (ri->root != NULL, FALSE);
17170 #ifndef G_DISABLE_ASSERT
17171 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17174 if (ri->current == NULL)
17175 ri->current = ri->root->priv->last_child;
17177 ri->current = ri->current->priv->prev_sibling;
17180 *child = ri->current;
17182 return ri->current != NULL;
17186 * clutter_actor_iter_remove:
17187 * @iter: a #ClutterActorIter
17189 * Safely removes the #ClutterActor currently pointer to by the iterator
17192 * This function can only be called after clutter_actor_iter_next() or
17193 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17194 * than once for the same actor.
17196 * This function will call clutter_actor_remove_child() internally.
17201 clutter_actor_iter_remove (ClutterActorIter *iter)
17203 RealActorIter *ri = (RealActorIter *) iter;
17206 g_return_if_fail (iter != NULL);
17207 g_return_if_fail (ri->root != NULL);
17208 #ifndef G_DISABLE_ASSERT
17209 g_return_if_fail (ri->age == ri->root->priv->age);
17211 g_return_if_fail (ri->current != NULL);
17217 ri->current = cur->priv->prev_sibling;
17219 clutter_actor_remove_child_internal (ri->root, cur,
17220 REMOVE_CHILD_DEFAULT_FLAGS);
17227 * clutter_actor_iter_destroy:
17228 * @iter: a #ClutterActorIter
17230 * Safely destroys the #ClutterActor currently pointer to by the iterator
17233 * This function can only be called after clutter_actor_iter_next() or
17234 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17235 * than once for the same actor.
17237 * This function will call clutter_actor_destroy() internally.
17242 clutter_actor_iter_destroy (ClutterActorIter *iter)
17244 RealActorIter *ri = (RealActorIter *) iter;
17247 g_return_if_fail (iter != NULL);
17248 g_return_if_fail (ri->root != NULL);
17249 #ifndef G_DISABLE_ASSERT
17250 g_return_if_fail (ri->age == ri->root->priv->age);
17252 g_return_if_fail (ri->current != NULL);
17258 ri->current = cur->priv->prev_sibling;
17260 clutter_actor_destroy (cur);
17266 static const ClutterAnimationInfo default_animation_info = {
17267 NULL, /* transitions */
17269 NULL, /* cur_state */
17273 clutter_animation_info_free (gpointer data)
17277 ClutterAnimationInfo *info = data;
17279 if (info->transitions != NULL)
17280 g_hash_table_unref (info->transitions);
17282 if (info->states != NULL)
17283 g_array_unref (info->states);
17285 g_slice_free (ClutterAnimationInfo, info);
17289 const ClutterAnimationInfo *
17290 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17292 const ClutterAnimationInfo *res;
17293 GObject *obj = G_OBJECT (self);
17295 res = g_object_get_qdata (obj, quark_actor_animation_info);
17299 return &default_animation_info;
17302 ClutterAnimationInfo *
17303 _clutter_actor_get_animation_info (ClutterActor *self)
17305 GObject *obj = G_OBJECT (self);
17306 ClutterAnimationInfo *res;
17308 res = g_object_get_qdata (obj, quark_actor_animation_info);
17311 res = g_slice_new (ClutterAnimationInfo);
17313 *res = default_animation_info;
17315 g_object_set_qdata_full (obj, quark_actor_animation_info,
17317 clutter_animation_info_free);
17323 ClutterTransition *
17324 _clutter_actor_get_transition (ClutterActor *actor,
17327 const ClutterAnimationInfo *info;
17329 info = _clutter_actor_get_animation_info_or_defaults (actor);
17331 if (info->transitions == NULL)
17334 return g_hash_table_lookup (info->transitions, pspec->name);
17338 transition_closure_free (gpointer data)
17340 if (G_LIKELY (data != NULL))
17342 TransitionClosure *clos = data;
17343 ClutterTimeline *timeline;
17345 timeline = CLUTTER_TIMELINE (clos->transition);
17347 if (clutter_timeline_is_playing (timeline))
17348 clutter_timeline_stop (timeline);
17350 g_signal_handler_disconnect (clos->transition, clos->completed_id);
17352 g_object_unref (clos->transition);
17353 g_free (clos->name);
17355 g_slice_free (TransitionClosure, clos);
17360 on_transition_stopped (ClutterTransition *transition,
17361 gboolean is_finished,
17362 TransitionClosure *clos)
17364 ClutterActor *actor = clos->actor;
17365 ClutterAnimationInfo *info;
17367 /* reset the caches used by animations */
17368 clutter_actor_store_content_box (actor, NULL);
17373 info = _clutter_actor_get_animation_info (actor);
17375 /* we take a reference here because removing the closure
17376 * will release the reference on the transition, and we
17377 * want the transition to survive the signal emission;
17378 * the master clock will release the last reference at
17379 * the end of the frame processing.
17381 g_object_ref (transition);
17382 g_hash_table_remove (info->transitions, clos->name);
17384 /* if it's the last transition then we clean up */
17385 if (g_hash_table_size (info->transitions) == 0)
17387 g_hash_table_unref (info->transitions);
17388 info->transitions = NULL;
17390 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17391 _clutter_actor_get_debug_name (actor));
17393 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17398 _clutter_actor_update_transition (ClutterActor *actor,
17402 TransitionClosure *clos;
17403 ClutterTimeline *timeline;
17404 ClutterInterval *interval;
17405 const ClutterAnimationInfo *info;
17408 GValue initial = G_VALUE_INIT;
17409 GValue final = G_VALUE_INIT;
17410 char *error = NULL;
17412 info = _clutter_actor_get_animation_info_or_defaults (actor);
17414 if (info->transitions == NULL)
17417 clos = g_hash_table_lookup (info->transitions, pspec->name);
17421 timeline = CLUTTER_TIMELINE (clos->transition);
17423 va_start (var_args, pspec);
17425 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17427 g_value_init (&initial, ptype);
17428 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17432 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17435 g_critical ("%s: %s", G_STRLOC, error);
17440 interval = clutter_transition_get_interval (clos->transition);
17441 clutter_interval_set_initial_value (interval, &initial);
17442 clutter_interval_set_final_value (interval, &final);
17444 /* if we're updating with an easing duration of zero milliseconds,
17445 * we just jump the timeline to the end and let it run its course
17447 if (info->cur_state != NULL &&
17448 info->cur_state->easing_duration != 0)
17450 guint cur_duration = clutter_timeline_get_duration (timeline);
17451 ClutterAnimationMode cur_mode =
17452 clutter_timeline_get_progress_mode (timeline);
17454 if (cur_duration != info->cur_state->easing_duration)
17455 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17457 if (cur_mode != info->cur_state->easing_mode)
17458 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17460 clutter_timeline_rewind (timeline);
17464 guint duration = clutter_timeline_get_duration (timeline);
17466 clutter_timeline_advance (timeline, duration);
17470 g_value_unset (&initial);
17471 g_value_unset (&final);
17477 * _clutter_actor_create_transition:
17478 * @actor: a #ClutterActor
17479 * @pspec: the property used for the transition
17480 * @...: initial and final state
17482 * Creates a #ClutterTransition for the property represented by @pspec.
17484 * Return value: a #ClutterTransition
17486 ClutterTransition *
17487 _clutter_actor_create_transition (ClutterActor *actor,
17491 ClutterAnimationInfo *info;
17492 ClutterTransition *res = NULL;
17493 gboolean call_restore = FALSE;
17494 TransitionClosure *clos;
17497 info = _clutter_actor_get_animation_info (actor);
17499 /* XXX - this will go away in 2.0
17501 * if no state has been pushed, we assume that the easing state is
17502 * in "compatibility mode": all transitions have a duration of 0
17503 * msecs, which means that they happen immediately. in Clutter 2.0
17504 * this will turn into a g_assert(info->states != NULL), as every
17505 * actor will start with a predefined easing state
17507 if (info->states == NULL)
17509 clutter_actor_save_easing_state (actor);
17510 clutter_actor_set_easing_duration (actor, 0);
17511 call_restore = TRUE;
17514 if (info->transitions == NULL)
17515 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17517 transition_closure_free);
17519 va_start (var_args, pspec);
17521 clos = g_hash_table_lookup (info->transitions, pspec->name);
17524 ClutterTimeline *timeline;
17525 ClutterInterval *interval;
17526 GValue initial = G_VALUE_INIT;
17527 GValue final = G_VALUE_INIT;
17531 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17533 G_VALUE_COLLECT_INIT (&initial, ptype,
17538 g_critical ("%s: %s", G_STRLOC, error);
17543 G_VALUE_COLLECT_INIT (&final, ptype,
17549 g_critical ("%s: %s", G_STRLOC, error);
17550 g_value_unset (&initial);
17555 /* if the current easing state has a duration of 0, then we don't
17556 * bother to create the transition, and we just set the final value
17557 * directly on the actor; we don't go through the Animatable
17558 * interface because we know we got here through an animatable
17561 if (info->cur_state->easing_duration == 0)
17563 clutter_actor_set_animatable_property (actor,
17567 g_value_unset (&initial);
17568 g_value_unset (&final);
17573 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17575 g_value_unset (&initial);
17576 g_value_unset (&final);
17578 res = clutter_property_transition_new (pspec->name);
17580 clutter_transition_set_interval (res, interval);
17581 clutter_transition_set_remove_on_complete (res, TRUE);
17583 timeline = CLUTTER_TIMELINE (res);
17584 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17585 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17586 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17588 CLUTTER_NOTE (ANIMATION,
17589 "Created transition for %s:%s (len:%u, mode:%s, delay:%u)",
17590 _clutter_actor_get_debug_name (actor),
17592 info->cur_state->easing_duration,
17593 clutter_get_easing_name_for_mode (info->cur_state->easing_mode),
17594 info->cur_state->easing_delay);
17596 /* this will start the transition as well */
17597 clutter_actor_add_transition (actor, pspec->name, res);
17599 /* the actor now owns the transition */
17600 g_object_unref (res);
17603 res = clos->transition;
17607 clutter_actor_restore_easing_state (actor);
17615 * clutter_actor_add_transition:
17616 * @self: a #ClutterActor
17617 * @name: the name of the transition to add
17618 * @transition: the #ClutterTransition to add
17620 * Adds a @transition to the #ClutterActor's list of animations.
17622 * The @name string is a per-actor unique identifier of the @transition: only
17623 * one #ClutterTransition can be associated to the specified @name.
17625 * The @transition will be started once added.
17627 * This function will take a reference on the @transition.
17629 * This function is usually called implicitly when modifying an animatable
17635 clutter_actor_add_transition (ClutterActor *self,
17637 ClutterTransition *transition)
17639 ClutterTimeline *timeline;
17640 TransitionClosure *clos;
17641 ClutterAnimationInfo *info;
17643 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17644 g_return_if_fail (name != NULL);
17645 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17647 info = _clutter_actor_get_animation_info (self);
17649 if (info->transitions == NULL)
17650 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17652 transition_closure_free);
17654 if (g_hash_table_lookup (info->transitions, name) != NULL)
17656 g_warning ("A transition with name '%s' already exists for "
17659 _clutter_actor_get_debug_name (self));
17663 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17665 timeline = CLUTTER_TIMELINE (transition);
17667 clos = g_slice_new (TransitionClosure);
17668 clos->actor = self;
17669 clos->transition = g_object_ref (transition);
17670 clos->name = g_strdup (name);
17671 clos->completed_id = g_signal_connect (timeline, "stopped",
17672 G_CALLBACK (on_transition_stopped),
17675 CLUTTER_NOTE (ANIMATION,
17676 "Adding transition '%s' [%p] to actor '%s'",
17679 _clutter_actor_get_debug_name (self));
17681 g_hash_table_insert (info->transitions, clos->name, clos);
17682 clutter_timeline_start (timeline);
17686 * clutter_actor_remove_transition:
17687 * @self: a #ClutterActor
17688 * @name: the name of the transition to remove
17690 * Removes the transition stored inside a #ClutterActor using @name
17693 * If the transition is currently in progress, it will be stopped.
17695 * This function releases the reference acquired when the transition
17696 * was added to the #ClutterActor.
17701 clutter_actor_remove_transition (ClutterActor *self,
17704 const ClutterAnimationInfo *info;
17706 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17707 g_return_if_fail (name != NULL);
17709 info = _clutter_actor_get_animation_info_or_defaults (self);
17711 if (info->transitions == NULL)
17714 g_hash_table_remove (info->transitions, name);
17718 * clutter_actor_remove_all_transitions:
17719 * @self: a #ClutterActor
17721 * Removes all transitions associated to @self.
17726 clutter_actor_remove_all_transitions (ClutterActor *self)
17728 const ClutterAnimationInfo *info;
17730 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17732 info = _clutter_actor_get_animation_info_or_defaults (self);
17733 if (info->transitions == NULL)
17736 g_hash_table_remove_all (info->transitions);
17740 * clutter_actor_set_easing_duration:
17741 * @self: a #ClutterActor
17742 * @msecs: the duration of the easing, or %NULL
17744 * Sets the duration of the tweening for animatable properties
17745 * of @self for the current easing state.
17750 clutter_actor_set_easing_duration (ClutterActor *self,
17753 ClutterAnimationInfo *info;
17755 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17757 info = _clutter_actor_get_animation_info (self);
17759 if (info->cur_state == NULL)
17761 g_warning ("You must call clutter_actor_save_easing_state() prior "
17762 "to calling clutter_actor_set_easing_duration().");
17766 if (info->cur_state->easing_duration != msecs)
17767 info->cur_state->easing_duration = msecs;
17771 * clutter_actor_get_easing_duration:
17772 * @self: a #ClutterActor
17774 * Retrieves the duration of the tweening for animatable
17775 * properties of @self for the current easing state.
17777 * Return value: the duration of the tweening, in milliseconds
17782 clutter_actor_get_easing_duration (ClutterActor *self)
17784 const ClutterAnimationInfo *info;
17786 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17788 info = _clutter_actor_get_animation_info_or_defaults (self);
17790 if (info->cur_state != NULL)
17791 return info->cur_state->easing_duration;
17797 * clutter_actor_set_easing_mode:
17798 * @self: a #ClutterActor
17799 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17801 * Sets the easing mode for the tweening of animatable properties
17807 clutter_actor_set_easing_mode (ClutterActor *self,
17808 ClutterAnimationMode mode)
17810 ClutterAnimationInfo *info;
17812 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17813 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17814 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17816 info = _clutter_actor_get_animation_info (self);
17818 if (info->cur_state == NULL)
17820 g_warning ("You must call clutter_actor_save_easing_state() prior "
17821 "to calling clutter_actor_set_easing_mode().");
17825 if (info->cur_state->easing_mode != mode)
17826 info->cur_state->easing_mode = mode;
17830 * clutter_actor_get_easing_mode:
17831 * @self: a #ClutterActor
17833 * Retrieves the easing mode for the tweening of animatable properties
17834 * of @self for the current easing state.
17836 * Return value: an easing mode
17840 ClutterAnimationMode
17841 clutter_actor_get_easing_mode (ClutterActor *self)
17843 const ClutterAnimationInfo *info;
17845 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17847 info = _clutter_actor_get_animation_info_or_defaults (self);
17849 if (info->cur_state != NULL)
17850 return info->cur_state->easing_mode;
17852 return CLUTTER_EASE_OUT_CUBIC;
17856 * clutter_actor_set_easing_delay:
17857 * @self: a #ClutterActor
17858 * @msecs: the delay before the start of the tweening, in milliseconds
17860 * Sets the delay that should be applied before tweening animatable
17866 clutter_actor_set_easing_delay (ClutterActor *self,
17869 ClutterAnimationInfo *info;
17871 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17873 info = _clutter_actor_get_animation_info (self);
17875 if (info->cur_state == NULL)
17877 g_warning ("You must call clutter_actor_save_easing_state() prior "
17878 "to calling clutter_actor_set_easing_delay().");
17882 if (info->cur_state->easing_delay != msecs)
17883 info->cur_state->easing_delay = msecs;
17887 * clutter_actor_get_easing_delay:
17888 * @self: a #ClutterActor
17890 * Retrieves the delay that should be applied when tweening animatable
17893 * Return value: a delay, in milliseconds
17898 clutter_actor_get_easing_delay (ClutterActor *self)
17900 const ClutterAnimationInfo *info;
17902 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17904 info = _clutter_actor_get_animation_info_or_defaults (self);
17906 if (info->cur_state != NULL)
17907 return info->cur_state->easing_delay;
17913 * clutter_actor_get_transition:
17914 * @self: a #ClutterActor
17915 * @name: the name of the transition
17917 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17918 * transition @name.
17920 * Transitions created for animatable properties use the name of the
17921 * property itself, for instance the code below:
17924 * clutter_actor_set_easing_duration (actor, 1000);
17925 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17927 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17928 * g_signal_connect (transition, "stopped",
17929 * G_CALLBACK (on_transition_stopped),
17933 * will call the <function>on_transition_stopped</function> callback when
17934 * the transition is finished.
17936 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17937 * was found to match the passed name; the returned instance is owned
17938 * by Clutter and it should not be freed
17942 ClutterTransition *
17943 clutter_actor_get_transition (ClutterActor *self,
17946 TransitionClosure *clos;
17947 const ClutterAnimationInfo *info;
17949 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17950 g_return_val_if_fail (name != NULL, NULL);
17952 info = _clutter_actor_get_animation_info_or_defaults (self);
17953 if (info->transitions == NULL)
17956 clos = g_hash_table_lookup (info->transitions, name);
17960 return clos->transition;
17964 * clutter_actor_save_easing_state:
17965 * @self: a #ClutterActor
17967 * Saves the current easing state for animatable properties, and creates
17968 * a new state with the default values for easing mode and duration.
17973 clutter_actor_save_easing_state (ClutterActor *self)
17975 ClutterAnimationInfo *info;
17978 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17980 info = _clutter_actor_get_animation_info (self);
17982 if (info->states == NULL)
17983 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17985 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17986 new_state.easing_duration = 250;
17987 new_state.easing_delay = 0;
17989 g_array_append_val (info->states, new_state);
17991 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17995 * clutter_actor_restore_easing_state:
17996 * @self: a #ClutterActor
17998 * Restores the easing state as it was prior to a call to
17999 * clutter_actor_save_easing_state().
18004 clutter_actor_restore_easing_state (ClutterActor *self)
18006 ClutterAnimationInfo *info;
18008 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18010 info = _clutter_actor_get_animation_info (self);
18012 if (info->states == NULL)
18014 g_critical ("The function clutter_actor_restore_easing_state() has "
18015 "called without a previous call to "
18016 "clutter_actor_save_easing_state().");
18020 g_array_remove_index (info->states, info->states->len - 1);
18022 if (info->states->len > 0)
18023 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
18026 g_array_unref (info->states);
18027 info->states = NULL;
18028 info->cur_state = NULL;
18033 * clutter_actor_set_content:
18034 * @self: a #ClutterActor
18035 * @content: (allow-none): a #ClutterContent, or %NULL
18037 * Sets the contents of a #ClutterActor.
18042 clutter_actor_set_content (ClutterActor *self,
18043 ClutterContent *content)
18045 ClutterActorPrivate *priv;
18047 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18048 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
18052 if (priv->content != NULL)
18054 _clutter_content_detached (priv->content, self);
18055 g_clear_object (&priv->content);
18058 priv->content = content;
18060 if (priv->content != NULL)
18062 g_object_ref (priv->content);
18063 _clutter_content_attached (priv->content, self);
18066 /* given that the content is always painted within the allocation,
18067 * we only need to queue a redraw here
18069 clutter_actor_queue_redraw (self);
18071 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
18073 /* if the content gravity is not resize-fill, and the new content has a
18074 * different preferred size than the previous one, then the content box
18075 * may have been changed. since we compute that lazily, we just notify
18076 * here, and let whomever watches :content-box do whatever they need to
18079 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18080 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
18084 * clutter_actor_get_content:
18085 * @self: a #ClutterActor
18087 * Retrieves the contents of @self.
18089 * Return value: (transfer none): a pointer to the #ClutterContent instance,
18090 * or %NULL if none was set
18095 clutter_actor_get_content (ClutterActor *self)
18097 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
18099 return self->priv->content;
18103 * clutter_actor_set_content_gravity:
18104 * @self: a #ClutterActor
18105 * @gravity: the #ClutterContentGravity
18107 * Sets the gravity of the #ClutterContent used by @self.
18109 * See the description of the #ClutterActor:content-gravity property for
18110 * more information.
18112 * The #ClutterActor:content-gravity property is animatable.
18117 clutter_actor_set_content_gravity (ClutterActor *self,
18118 ClutterContentGravity gravity)
18120 ClutterActorPrivate *priv;
18122 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18126 if (priv->content_gravity == gravity)
18129 priv->content_box_valid = FALSE;
18131 if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
18133 ClutterActorBox from_box, to_box;
18135 clutter_actor_get_content_box (self, &from_box);
18137 priv->content_gravity = gravity;
18139 clutter_actor_get_content_box (self, &to_box);
18141 _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
18147 ClutterActorBox to_box;
18149 priv->content_gravity = gravity;
18151 clutter_actor_get_content_box (self, &to_box);
18153 _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
18157 clutter_actor_queue_redraw (self);
18159 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
18163 * clutter_actor_get_content_gravity:
18164 * @self: a #ClutterActor
18166 * Retrieves the content gravity as set using
18167 * clutter_actor_get_content_gravity().
18169 * Return value: the content gravity
18173 ClutterContentGravity
18174 clutter_actor_get_content_gravity (ClutterActor *self)
18176 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
18177 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
18179 return self->priv->content_gravity;
18183 * clutter_actor_get_content_box:
18184 * @self: a #ClutterActor
18185 * @box: (out caller-allocates): the return location for the bounding
18186 * box for the #ClutterContent
18188 * Retrieves the bounding box for the #ClutterContent of @self.
18190 * The bounding box is relative to the actor's allocation.
18192 * If no #ClutterContent is set for @self, or if @self has not been
18193 * allocated yet, then the result is undefined.
18195 * The content box is guaranteed to be, at most, as big as the allocation
18196 * of the #ClutterActor.
18198 * If the #ClutterContent used by the actor has a preferred size, then
18199 * it is possible to modify the content box by using the
18200 * #ClutterActor:content-gravity property.
18205 clutter_actor_get_content_box (ClutterActor *self,
18206 ClutterActorBox *box)
18208 ClutterActorPrivate *priv;
18209 gfloat content_w, content_h;
18210 gfloat alloc_w, alloc_h;
18212 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18213 g_return_if_fail (box != NULL);
18219 box->x2 = priv->allocation.x2 - priv->allocation.x1;
18220 box->y2 = priv->allocation.y2 - priv->allocation.y1;
18222 if (priv->content_box_valid)
18224 *box = priv->content_box;
18228 /* no need to do any more work */
18229 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18232 if (priv->content == NULL)
18235 /* if the content does not have a preferred size then there is
18236 * no point in computing the content box
18238 if (!clutter_content_get_preferred_size (priv->content,
18246 switch (priv->content_gravity)
18248 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18249 box->x2 = box->x1 + MIN (content_w, alloc_w);
18250 box->y2 = box->y1 + MIN (content_h, alloc_h);
18253 case CLUTTER_CONTENT_GRAVITY_TOP:
18254 if (alloc_w > content_w)
18256 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18257 box->x2 = box->x1 + content_w;
18259 box->y2 = box->y1 + MIN (content_h, alloc_h);
18262 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18263 if (alloc_w > content_w)
18265 box->x1 += (alloc_w - content_w);
18266 box->x2 = box->x1 + content_w;
18268 box->y2 = box->y1 + MIN (content_h, alloc_h);
18271 case CLUTTER_CONTENT_GRAVITY_LEFT:
18272 box->x2 = box->x1 + MIN (content_w, alloc_w);
18273 if (alloc_h > content_h)
18275 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18276 box->y2 = box->y1 + content_h;
18280 case CLUTTER_CONTENT_GRAVITY_CENTER:
18281 if (alloc_w > content_w)
18283 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18284 box->x2 = box->x1 + content_w;
18286 if (alloc_h > content_h)
18288 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18289 box->y2 = box->y1 + content_h;
18293 case CLUTTER_CONTENT_GRAVITY_RIGHT:
18294 if (alloc_w > content_w)
18296 box->x1 += (alloc_w - content_w);
18297 box->x2 = box->x1 + content_w;
18299 if (alloc_h > content_h)
18301 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18302 box->y2 = box->y1 + content_h;
18306 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18307 box->x2 = box->x1 + MIN (content_w, alloc_w);
18308 if (alloc_h > content_h)
18310 box->y1 += (alloc_h - content_h);
18311 box->y2 = box->y1 + content_h;
18315 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18316 if (alloc_w > content_w)
18318 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18319 box->x2 = box->x1 + content_w;
18321 if (alloc_h > content_h)
18323 box->y1 += (alloc_h - content_h);
18324 box->y2 = box->y1 + content_h;
18328 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18329 if (alloc_w > content_w)
18331 box->x1 += (alloc_w - content_w);
18332 box->x2 = box->x1 + content_w;
18334 if (alloc_h > content_h)
18336 box->y1 += (alloc_h - content_h);
18337 box->y2 = box->y1 + content_h;
18341 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18342 g_assert_not_reached ();
18345 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18347 double r_c = content_w / content_h;
18351 if ((alloc_w / r_c) > alloc_h)
18356 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18357 box->y2 = box->y1 + (alloc_w / r_c);
18364 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18365 box->x2 = box->x1 + (alloc_h * r_c);
18370 if ((alloc_w / r_c) > alloc_h)
18375 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18376 box->x2 = box->x1 + (alloc_h * r_c);
18383 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18384 box->y2 = box->y1 + (alloc_w / r_c);
18388 CLUTTER_NOTE (LAYOUT,
18389 "r_c: %.3f, r_a: %.3f\t"
18390 "a: [%.2fx%.2f], c: [%.2fx%.2f]\t"
18391 "b: [%.2f, %.2f, %.2f, %.2f]",
18392 r_c, alloc_w / alloc_h,
18394 content_w, content_h,
18395 box->x1, box->y1, box->x2, box->y2);
18402 * clutter_actor_set_content_scaling_filters:
18403 * @self: a #ClutterActor
18404 * @min_filter: the minification filter for the content
18405 * @mag_filter: the magnification filter for the content
18407 * Sets the minification and magnification filter to be applied when
18408 * scaling the #ClutterActor:content of a #ClutterActor.
18410 * The #ClutterActor:minification-filter will be used when reducing
18411 * the size of the content; the #ClutterActor:magnification-filter
18412 * will be used when increasing the size of the content.
18417 clutter_actor_set_content_scaling_filters (ClutterActor *self,
18418 ClutterScalingFilter min_filter,
18419 ClutterScalingFilter mag_filter)
18421 ClutterActorPrivate *priv;
18425 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18428 obj = G_OBJECT (self);
18430 g_object_freeze_notify (obj);
18434 if (priv->min_filter != min_filter)
18436 priv->min_filter = min_filter;
18439 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18442 if (priv->mag_filter != mag_filter)
18444 priv->mag_filter = mag_filter;
18447 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18451 clutter_actor_queue_redraw (self);
18453 g_object_thaw_notify (obj);
18457 * clutter_actor_get_content_scaling_filters:
18458 * @self: a #ClutterActor
18459 * @min_filter: (out) (allow-none): return location for the minification
18461 * @mag_filter: (out) (allow-none): return location for the magnification
18464 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18469 clutter_actor_get_content_scaling_filters (ClutterActor *self,
18470 ClutterScalingFilter *min_filter,
18471 ClutterScalingFilter *mag_filter)
18473 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18475 if (min_filter != NULL)
18476 *min_filter = self->priv->min_filter;
18478 if (mag_filter != NULL)
18479 *mag_filter = self->priv->mag_filter;
18483 * clutter_actor_queue_compute_expand:
18484 * @self: a #ClutterActor
18486 * Invalidates the needs_x_expand and needs_y_expand flags on @self
18487 * and its parents up to the top-level actor.
18489 * This function also queues a relayout if anything changed.
18492 clutter_actor_queue_compute_expand (ClutterActor *self)
18494 ClutterActor *parent;
18497 if (self->priv->needs_compute_expand)
18502 while (parent != NULL)
18504 if (!parent->priv->needs_compute_expand)
18506 parent->priv->needs_compute_expand = TRUE;
18510 parent = parent->priv->parent;
18514 clutter_actor_queue_relayout (self);
18518 * clutter_actor_set_x_expand:
18519 * @self: a #ClutterActor
18520 * @expand: whether the actor should expand horizontally
18522 * Sets whether a #ClutterActor should expand horizontally; this means
18523 * that layout manager should allocate extra space for the actor, if
18526 * Setting an actor to expand will also make all its parent expand, so
18527 * that it's possible to build an actor tree and only set this flag on
18528 * its leaves and not on every single actor.
18533 clutter_actor_set_x_expand (ClutterActor *self,
18536 ClutterLayoutInfo *info;
18538 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18542 info = _clutter_actor_get_layout_info (self);
18543 if (info->x_expand != expand)
18545 info->x_expand = expand;
18547 self->priv->x_expand_set = TRUE;
18549 clutter_actor_queue_compute_expand (self);
18551 g_object_notify_by_pspec (G_OBJECT (self),
18552 obj_props[PROP_X_EXPAND]);
18557 * clutter_actor_get_x_expand:
18558 * @self: a #ClutterActor
18560 * Retrieves the value set with clutter_actor_set_x_expand().
18562 * See also: clutter_actor_needs_expand()
18564 * Return value: %TRUE if the actor has been set to expand
18569 clutter_actor_get_x_expand (ClutterActor *self)
18571 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18573 return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18577 * clutter_actor_set_y_expand:
18578 * @self: a #ClutterActor
18579 * @expand: whether the actor should expand vertically
18581 * Sets whether a #ClutterActor should expand horizontally; this means
18582 * that layout manager should allocate extra space for the actor, if
18585 * Setting an actor to expand will also make all its parent expand, so
18586 * that it's possible to build an actor tree and only set this flag on
18587 * its leaves and not on every single actor.
18592 clutter_actor_set_y_expand (ClutterActor *self,
18595 ClutterLayoutInfo *info;
18597 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18601 info = _clutter_actor_get_layout_info (self);
18602 if (info->y_expand != expand)
18604 info->y_expand = expand;
18606 self->priv->y_expand_set = TRUE;
18608 clutter_actor_queue_compute_expand (self);
18610 g_object_notify_by_pspec (G_OBJECT (self),
18611 obj_props[PROP_Y_EXPAND]);
18616 * clutter_actor_get_y_expand:
18617 * @self: a #ClutterActor
18619 * Retrieves the value set with clutter_actor_set_y_expand().
18621 * See also: clutter_actor_needs_expand()
18623 * Return value: %TRUE if the actor has been set to expand
18628 clutter_actor_get_y_expand (ClutterActor *self)
18630 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18632 return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18636 clutter_actor_compute_expand_recursive (ClutterActor *self,
18637 gboolean *x_expand_p,
18638 gboolean *y_expand_p)
18640 ClutterActorIter iter;
18641 ClutterActor *child;
18642 gboolean x_expand, y_expand;
18644 x_expand = y_expand = FALSE;
18646 /* note that we don't recurse into children if we're already set to expand;
18647 * this avoids traversing the whole actor tree, even if it may lead to some
18648 * child left with the needs_compute_expand flag set.
18650 clutter_actor_iter_init (&iter, self);
18651 while (clutter_actor_iter_next (&iter, &child))
18653 x_expand = x_expand ||
18654 clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL);
18656 y_expand = y_expand ||
18657 clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL);
18660 *x_expand_p = x_expand;
18661 *y_expand_p = y_expand;
18665 clutter_actor_compute_expand (ClutterActor *self)
18667 if (self->priv->needs_compute_expand)
18669 const ClutterLayoutInfo *info;
18670 gboolean x_expand, y_expand;
18672 info = _clutter_actor_get_layout_info_or_defaults (self);
18674 if (self->priv->x_expand_set)
18675 x_expand = info->x_expand;
18679 if (self->priv->y_expand_set)
18680 y_expand = info->y_expand;
18684 /* we don't need to recurse down to the children if the
18685 * actor has been forcibly set to expand
18687 if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18689 if (self->priv->n_children != 0)
18691 gboolean *x_expand_p, *y_expand_p;
18692 gboolean ignored = FALSE;
18694 x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18695 y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18697 clutter_actor_compute_expand_recursive (self,
18703 self->priv->needs_compute_expand = FALSE;
18704 self->priv->needs_x_expand = (x_expand != FALSE);
18705 self->priv->needs_y_expand = (y_expand != FALSE);
18710 * clutter_actor_needs_expand:
18711 * @self: a #ClutterActor
18712 * @orientation: the direction of expansion
18714 * Checks whether an actor, or any of its children, is set to expand
18715 * horizontally or vertically.
18717 * This function should only be called by layout managers that can
18718 * assign extra space to their children.
18720 * If you want to know whether the actor was explicitly set to expand,
18721 * use clutter_actor_get_x_expand() or clutter_actor_get_y_expand().
18723 * Return value: %TRUE if the actor should expand
18728 clutter_actor_needs_expand (ClutterActor *self,
18729 ClutterOrientation orientation)
18731 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18733 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18736 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18739 clutter_actor_compute_expand (self);
18741 switch (orientation)
18743 case CLUTTER_ORIENTATION_HORIZONTAL:
18744 return self->priv->needs_x_expand;
18746 case CLUTTER_ORIENTATION_VERTICAL:
18747 return self->priv->needs_y_expand;
18754 * clutter_actor_set_content_repeat:
18755 * @self: a #ClutterActor
18756 * @repeat: the repeat policy
18758 * Sets the policy for repeating the #ClutterActor:content of a
18759 * #ClutterActor. The behaviour is deferred to the #ClutterContent
18765 clutter_actor_set_content_repeat (ClutterActor *self,
18766 ClutterContentRepeat repeat)
18768 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18770 if (self->priv->content_repeat == repeat)
18773 self->priv->content_repeat = repeat;
18775 clutter_actor_queue_redraw (self);
18779 * clutter_actor_get_content_repeat:
18780 * @self: a #ClutterActor
18782 * Retrieves the repeat policy for a #ClutterActor set by
18783 * clutter_actor_set_content_repeat().
18785 * Return value: the content repeat policy
18789 ClutterContentRepeat
18790 clutter_actor_get_content_repeat (ClutterActor *self)
18792 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_REPEAT_NONE);
18794 return self->priv->content_repeat;