4 * An OpenGL based 'interactive canvas' library.
6 * Authored By Matthew Allum <mallum@openedhand.com>
8 * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9 * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
26 * SECTION:clutter-actor
27 * @short_description: The basic element of the scene graph
29 * The ClutterActor class is the basic element of the scene graph in Clutter,
30 * and it encapsulates the position, size, and transformations of a node in
33 * <refsect2 id="ClutterActor-transformations">
34 * <title>Actor transformations</title>
35 * <para>Each actor can be transformed using methods like
36 * clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37 * in which the transformations are applied is decided by Clutter and it is
38 * the following:</para>
40 * <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41 * <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42 * <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43 * <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44 * <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45 * <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46 * <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
50 * <refsect2 id="ClutterActor-geometry">
51 * <title>Modifying an actor's geometry</title>
52 * <para>Each actor has a bounding box, called #ClutterActor:allocation
53 * which is either set by its parent or explicitly through the
54 * clutter_actor_set_position() and clutter_actor_set_size() methods.
55 * Each actor also has an implicit preferred size.</para>
56 * <para>An actor’s preferred size can be defined by any subclass by
57 * overriding the #ClutterActorClass.get_preferred_width() and the
58 * #ClutterActorClass.get_preferred_height() virtual functions, or it can
59 * be explicitly set by using clutter_actor_set_width() and
60 * clutter_actor_set_height().</para>
61 * <para>An actor’s position can be set explicitly by using
62 * clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63 * relative to the origin of the actor’s parent.</para>
66 * <refsect2 id="ClutterActor-children">
67 * <title>Managing actor children</title>
68 * <para>Each actor can have multiple children, by calling
69 * clutter_actor_add_child() to add a new child actor, and
70 * clutter_actor_remove_child() to remove an existing child. #ClutterActor
71 * will hold a reference on each child actor, which will be released when
72 * the child is removed from its parent, or destroyed using
73 * clutter_actor_destroy().</para>
74 * <informalexample><programlisting>
75 * ClutterActor *actor = clutter_actor_new ();
77 * /* set the bounding box of the actor */
78 * clutter_actor_set_position (actor, 0, 0);
79 * clutter_actor_set_size (actor, 480, 640);
81 * /* set the background color of the actor */
82 * clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
84 * /* set the bounding box of the child, relative to the parent */
85 * ClutterActor *child = clutter_actor_new ();
86 * clutter_actor_set_position (child, 20, 20);
87 * clutter_actor_set_size (child, 80, 240);
89 * /* set the background color of the child */
90 * clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
92 * /* add the child to the actor */
93 * clutter_actor_add_child (actor, child);
94 * </programlisting></informalexample>
95 * <para>Children can be inserted at a given index, or above and below
96 * another child actor. The order of insertion determines the order of the
97 * children when iterating over them. Iterating over children is performed
98 * by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99 * clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100 * also possible to retrieve a list of children by using
101 * clutter_actor_get_children(), as well as retrieving a specific child at a
102 * given index by using clutter_actor_get_child_at_index().</para>
103 * <para>If you need to track additions of children to a #ClutterActor, use
104 * the #ClutterContainer::actor-added signal; similarly, to track removals
105 * of children from a ClutterActor, use the #ClutterContainer::actor-removed
107 * <informalexample><programlisting>
108 * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../examples/basic-actor.c">
109 * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
111 * </programlisting></informalexample>
112 * <figure id="actor-example-image">
113 * <title>Actors</title>
114 * <graphic fileref="actor-example.png" format="PNG"/>
118 * <refsect2 id="ClutterActor-painting">
119 * <title>Painting an actor</title>
120 * <para>There are three ways to paint an actor:</para>
122 * <listitem><para>set a delegate #ClutterContent as the value for the
123 * #ClutterActor:content property of the actor;</para></listitem>
124 * <listitem><para>subclass #ClutterActor and override the
125 * #ClutterActorClass.paint_node() virtual function;</para></listitem>
126 * <listitem><para>subclass #ClutterActor and override the
127 * #ClutterActorClass.paint() virtual function.</para></listitem>
130 * <title>Setting the Content property</title>
131 * <para>A #ClutterContent is a delegate object that takes over the
132 * painting operation of one, or more actors. The #ClutterContent
133 * painting will be performed on top of the #ClutterActor:background-color
134 * of the actor, and before calling the #ClutterActorClass.paint_node()
135 * virtual function.</para>
136 * <informalexample><programlisting>
137 * ClutterActor *actor = clutter_actor_new ();
139 * /* set the bounding box */
140 * clutter_actor_set_position (actor, 50, 50);
141 * clutter_actor_set_size (actor, 100, 100);
143 * /* set the content; the image_content variable is set elsewhere */
144 * clutter_actor_set_content (actor, image_content);
145 * </programlisting></informalexample>
148 * <title>Overriding the paint_node virtual function</title>
149 * <para>The #ClutterActorClass.paint_node() virtual function is invoked
150 * whenever an actor needs to be painted. The implementation of the
151 * virtual function must only paint the contents of the actor itself,
152 * and not the contents of its children, if the actor has any.</para>
153 * <para>The #ClutterPaintNode passed to the virtual function is the
154 * local root of the render tree; any node added to it will be
155 * rendered at the correct position, as defined by the actor's
156 * #ClutterActor:allocation.</para>
157 * <informalexample><programlisting>
159 * my_actor_paint_node (ClutterActor *actor,
160 * ClutterPaintNode *root)
162 * ClutterPaintNode *node;
163 * ClutterActorBox box;
165 * /* where the content of the actor should be painted */
166 * clutter_actor_get_allocation_box (actor, &box);
168 * /* the cogl_texture variable is set elsewhere */
169 * node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170 * CLUTTER_SCALING_FILTER_TRILINEAR,
171 * CLUTTER_SCALING_FILTER_LINEAR);
173 * /* paint the content of the node using the allocation */
174 * clutter_paint_node_add_rectangle (node, &box);
176 * /* add the node, and transfer ownership */
177 * clutter_paint_node_add_child (root, node);
178 * clutter_paint_node_unref (node);
180 * </programlisting></informalexample>
183 * <title>Overriding the paint virtual function</title>
184 * <para>The #ClutterActorClass.paint() virtual function is invoked
185 * when the #ClutterActor::paint signal is emitted, and after the other
186 * signal handlers have been invoked. Overriding the paint virtual
187 * function gives total control to the paint sequence of the actor
188 * itself, including the children of the actor, if any.</para>
189 * <warning><para>It is strongly discouraged to override the
190 * #ClutterActorClass.paint() virtual function, as well as connecting
191 * to the #ClutterActor::paint signal. These hooks into the paint
192 * sequence are considered legacy, and will be removed when the Clutter
193 * API changes.</para></warning>
197 * <refsect2 id="ClutterActor-events">
198 * <title>Handling events on an actor</title>
199 * <para>A #ClutterActor can receive and handle input device events, for
200 * instance pointer events and key events, as long as its
201 * #ClutterActor:reactive property is set to %TRUE.</para>
202 * <para>Once an actor has been determined to be the source of an event,
203 * Clutter will traverse the scene graph from the top-level actor towards the
204 * event source, emitting the #ClutterActor::captured-event signal on each
205 * ancestor until it reaches the source; this phase is also called
206 * <emphasis>the capture phase</emphasis>. If the event propagation was not
207 * stopped, the graph is walked backwards, from the source actor to the
208 * top-level, and the #ClutterActor::event signal, along with other event
209 * signals if needed, is emitted; this phase is also called <emphasis>the
210 * bubble phase</emphasis>. At any point of the signal emission, signal
211 * handlers can stop the propagation through the scene graph by returning
212 * %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213 * returning %CLUTTER_EVENT_PROPAGATE.</para>
216 * <refsect2 id="ClutterActor-animation">
217 * <title>Animation</title>
218 * <para>Animation is a core concept of modern user interfaces; Clutter
219 * provides a complete and powerful animation framework that automatically
220 * tweens the actor's state without requiring direct, frame by frame
221 * manipulation from your application code.</para>
223 * <title>Implicit animations</title>
224 * <para>The implicit animation model of Clutter assumes that all the
225 * changes in an actor state should be gradual and asynchronous; Clutter
226 * will automatically transition an actor's property change between the
227 * current state and the desired one without manual intervention.</para>
228 * <para>By default, in the 1.0 API series, the transition happens with
229 * a duration of zero milliseconds, and the implicit animation is an
230 * opt in feature to retain backwards compatibility. In order to enable
231 * implicit animations, it is necessary to change the easing state of
232 * an actor by using clutter_actor_save_easing_state():</para>
233 * <informalexample><programlisting>
234 * /* assume that the actor is currently positioned at (100, 100) */
235 * clutter_actor_save_easing_state (actor);
236 * clutter_actor_set_position (actor, 500, 500);
237 * clutter_actor_restore_easing_state (actor);
238 * </programlisting></informalexample>
239 * <para>The example above will trigger an implicit animation of the
240 * actor between its current position to a new position.</para>
241 * <para>It is possible to animate multiple properties of an actor
242 * at the same time, and you can animate multiple actors at the same
243 * time as well, for instance:</para>
244 * <informalexample><programlisting>
245 * /* animate the actor's opacity and depth */
246 * clutter_actor_save_easing_state (actor);
247 * clutter_actor_set_opacity (actor, 0);
248 * clutter_actor_set_depth (actor, -100);
249 * clutter_actor_restore_easing_state (actor);
251 * /* animate another actor's opacity */
252 * clutter_actor_save_easing_state (another_actor);
253 * clutter_actor_set_opacity (another_actor, 255);
254 * clutter_actor_set_depth (another_actor, 100);
255 * clutter_actor_restore_easing_state (another_actor);
256 * </programlisting></informalexample>
257 * <para>Implicit animations use a default duration of 250 milliseconds,
258 * and a default easing mode of %CLUTTER_EASE_OUT_CUBIC, unless you call
259 * clutter_actor_set_easing_mode() and clutter_actor_set_easing_duration()
260 * after changing the easing state of the actor.</para>
261 * <para>It is important to note that if you modify the state on an
262 * animatable property while a transition is in flight, the transition's
263 * final value will be updated, as well as its duration and progress
264 * mode by using the current easing state; for instance, in the following
266 * <informalexample><programlisting>
267 * clutter_actor_save_easing_state (actor);
268 * clutter_actor_set_x (actor, 200);
269 * clutter_actor_restore_easing_state (actor);
271 * clutter_actor_save_easing_state (actor);
272 * clutter_actor_set_x (actor, 100);
273 * clutter_actor_restore_easing_state (actor);
274 * </programlisting></informalexample>
275 * <para>the first call to clutter_actor_set_x() will begin a transition
276 * of the #ClutterActor:x property to the value of 200; the second call
277 * to clutter_actor_set_x() will change the transition's final value to
279 * <para>It is possible to retrieve the #ClutterTransition used by the
280 * animatable properties by using clutter_actor_get_transition() and using
281 * the property name as the transition name.</para>
284 * <title>Explicit animations</title>
285 * <para>The explicit animation model supported by Clutter requires that
286 * you create a #ClutterTransition object, and set the initial and
287 * final values. The transition will not start unless you add it to the
288 * #ClutterActor.</para>
289 * <informalexample><programlisting>
290 * ClutterTransition *transition;
292 * transition = clutter_property_transition_new ("opacity");
293 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000);
294 * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
295 * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
296 * clutter_transition_set_from (transition, G_TYPE_UINT, 255);
297 * clutter_transition_set_to (transition, G_TYPE_UINT, 0);
299 * clutter_actor_add_transition (actor, "animate-opacity", transition);
300 * </programlisting></informalexample>
301 * <para>The example above will animate the #ClutterActor:opacity property
302 * of an actor between fully opaque and fully transparent, and back, over
303 * a span of 3 seconds. The animation does not begin until it is added to
305 * <para>The explicit animation API should also be used when using custom
306 * animatable properties for #ClutterAction, #ClutterConstraint, and
307 * #ClutterEffect instances associated to an actor; see the section on
308 * <ulink linkend="ClutterActor-custom-animatable-properties">custom
309 * animatable properties below</ulink> for an example.</para>
310 * <para>Finally, explicit animations are useful for creating animations
311 * that run continuously, for instance:</para>
312 * <informalexample><programlisting>
313 * /* this animation will pulse the actor's opacity continuously */
314 * ClutterTransition *transition;
315 * ClutterInterval *interval;
317 * transition = clutter_property_transition_new ("opacity");
319 * /* we want to animate the opacity between 0 and 255 */
320 * clutter_transition_set_from (transition, G_TYPE_UINT, 0);
321 * clutter_transition_set_to (transition, G_TYPE_UINT, 255);
323 * /* over a one second duration, running an infinite amount of times */
324 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
325 * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
327 * /* we want to fade in and out, so we need to auto-reverse the transition */
328 * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
330 * /* and we want to use an easing function that eases both in and out */
331 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
332 * CLUTTER_EASE_IN_OUT_CUBIC);
334 * /* add the transition to the desired actor; this will
335 * * start the animation.
337 * clutter_actor_add_transition (actor, "opacityAnimation", transition);
338 * </programlisting></informalexample>
342 * <refsect2 id="ClutterActor-subclassing">
343 * <title>Implementing an actor</title>
344 * <para>Careful consideration should be given when deciding to implement
345 * a #ClutterActor sub-class. It is generally recommended to implement a
346 * sub-class of #ClutterActor only for actors that should be used as leaf
347 * nodes of a scene graph.</para>
348 * <para>If your actor should be painted in a custom way, you should
349 * override the #ClutterActor::paint signal class handler. You can either
350 * opt to chain up to the parent class implementation or decide to fully
351 * override the default paint implementation; Clutter will set up the
352 * transformations and clip regions prior to emitting the #ClutterActor::paint
354 * <para>By overriding the #ClutterActorClass.get_preferred_width() and
355 * #ClutterActorClass.get_preferred_height() virtual functions it is
356 * possible to change or provide the preferred size of an actor; similarly,
357 * by overriding the #ClutterActorClass.allocate() virtual function it is
358 * possible to control the layout of the children of an actor. Make sure to
359 * always chain up to the parent implementation of the
360 * #ClutterActorClass.allocate() virtual function.</para>
361 * <para>In general, it is strongly encouraged to use delegation and
362 * composition instead of direct subclassing.</para>
365 * <refsect2 id="ClutterActor-script">
366 * <title>ClutterActor custom properties for #ClutterScript</title>
367 * <para>#ClutterActor defines a custom "rotation" property which
368 * allows a short-hand description of the rotations to be applied
369 * to an actor.</para>
370 * <para>The syntax of the "rotation" property is the following:</para>
374 * { "<axis>" : [ <angle>, [ <center> ] ] }
378 * <para>where the <emphasis>axis</emphasis> is the name of an enumeration
379 * value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
380 * floating point value representing the rotation angle on the given axis,
382 * <para>The <emphasis>center</emphasis> array is optional, and if present
383 * it must contain the center of rotation as described by two coordinates:
384 * Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
386 * <para>#ClutterActor also defines a scriptable "margin" property which
387 * follows the CSS "margin" shorthand.
391 * "margin" : [ <top>, <right>, <bottom> <left> ]
393 * "margin" : [ <top>, <left/right>, <bottom> ]
395 * "margin" : [ <top/bottom>, <left/right> ]
397 * "margin" : [ <top/right/bottom/left> ]
401 * <para>#ClutterActor will also parse every positional and dimensional
402 * property defined as a string through clutter_units_from_string(); you
403 * should read the documentation for the #ClutterUnits parser format for
404 * the valid units and syntax.</para>
407 * <refsect2 id="ClutterActor-custom-animatable-properties">
408 * <title>Custom animatable properties</title>
409 * <para>#ClutterActor allows accessing properties of #ClutterAction,
410 * #ClutterEffect, and #ClutterConstraint instances associated to an actor
411 * instance for animation purposes.</para>
412 * <para>In order to access a specific #ClutterAction or a #ClutterConstraint
413 * property it is necessary to set the #ClutterActorMeta:name property on the
414 * given action or constraint.</para>
415 * <para>The property can be accessed using the following syntax:</para>
418 * @<section>.<meta-name>.<property-name>
421 * <para>The initial <emphasis>@</emphasis> is mandatory.</para>
422 * <para>The <emphasis>section</emphasis> fragment can be one between
423 * "actions", "constraints" and "effects".</para>
424 * <para>The <emphasis>meta-name</emphasis> fragment is the name of the
425 * action or constraint, as specified by the #ClutterActorMeta:name
427 * <para>The <emphasis>property-name</emphasis> fragment is the name of the
428 * action or constraint property to be animated.</para>
429 * <para>The example below animates a #ClutterBindConstraint applied to an
430 * actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
431 * a binding constraint for the <emphasis>origin</emphasis> actor, and in
432 * its initial state is overlapping the actor to which is bound to.</para>
433 * <informalexample><programlisting>
434 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
435 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
436 * clutter_actor_add_constraint (rect, constraint);
438 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
439 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
440 * clutter_actor_add_constraint (rect, constraint);
442 * clutter_actor_set_reactive (origin, TRUE);
444 * g_signal_connect (origin, "button-press-event",
445 * G_CALLBACK (on_button_press),
447 * </programlisting></informalexample>
448 * <para>On button press, the rectangle "slides" from behind the actor to
449 * which is bound to, using the #ClutterBindConstraint:offset property to
450 * achieve the effect:</para>
451 * <informalexample><programlisting>
453 * on_button_press (ClutterActor *origin,
454 * ClutterEvent *event,
455 * ClutterActor *rect)
457 * ClutterTransition *transition;
458 * ClutterInterval *interval;
460 * /* the offset that we want to apply; this will make the actor
461 * * slide in from behind the origin and rest at the right of
462 * * the origin, plus a padding value.
464 * float new_offset = clutter_actor_get_width (origin) + h_padding;
466 * /* the property we wish to animate; the "@constraints" section
467 * * tells Clutter to check inside the constraints associated
468 * * with the actor; the "bind-x" section is the name of the
469 * * constraint; and the "offset" is the name of the property
470 * * on the constraint.
472 * const char *prop = "@constraints.bind-x.offset";
474 * /* create a new transition for the given property */
475 * transition = clutter_property_transition_new (prop);
477 * /* set the easing mode and duration */
478 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
479 * CLUTTER_EASE_OUT_CUBIC);
480 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
482 * /* create the interval with the initial and final values */
483 * interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
484 * clutter_transition_set_interval (transition, interval);
486 * /* add the transition to the actor; this causes the animation
487 * * to start. the name "offsetAnimation" can be used to retrieve
488 * * the transition later.
490 * clutter_actor_add_transition (rect, "offsetAnimation", transition);
492 * /* we handled the event */
493 * return CLUTTER_EVENT_STOP;
495 * </programlisting></informalexample>
500 * CLUTTER_ACTOR_IS_MAPPED:
501 * @a: a #ClutterActor
503 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
505 * The mapped state is set when the actor is visible and all its parents up
506 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
508 * This check can be used to see if an actor is going to be painted, as only
509 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
511 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
512 * not be checked directly; instead, the recommended usage is to connect a
513 * handler on the #GObject::notify signal for the #ClutterActor:mapped
514 * property of #ClutterActor, and check the presence of
515 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
517 * It is also important to note that Clutter may delay the changes of
518 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
519 * limitations, or during the reparenting of an actor, to optimize
520 * unnecessary (and potentially expensive) state changes.
526 * CLUTTER_ACTOR_IS_REALIZED:
527 * @a: a #ClutterActor
529 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
531 * The realized state has an actor-dependant interpretation. If an
532 * actor wants to delay allocating resources until it is attached to a
533 * stage, it may use the realize state to do so. However it is
534 * perfectly acceptable for an actor to allocate Cogl resources before
535 * being realized because there is only one drawing context used by Clutter
536 * so any resources will work on any stage. If an actor is mapped it
537 * must also be realized, but an actor can be realized and unmapped
538 * (this is so hiding an actor temporarily doesn't do an expensive
539 * unrealize/realize).
541 * To be realized an actor must be inside a stage, and all its parents
548 * CLUTTER_ACTOR_IS_VISIBLE:
549 * @a: a #ClutterActor
551 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
552 * Equivalent to the ClutterActor::visible object property.
554 * Note that an actor is only painted onscreen if it's mapped, which
555 * means it's visible, and all its parents are visible, and one of the
556 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
562 * CLUTTER_ACTOR_IS_REACTIVE:
563 * @a: a #ClutterActor
565 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
567 * Only reactive actors will receive event-related signals.
578 #include <gobject/gvaluecollector.h>
580 #include <cogl/cogl.h>
582 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
583 #define CLUTTER_ENABLE_EXPERIMENTAL_API
585 #include "clutter-actor-private.h"
587 #include "clutter-action.h"
588 #include "clutter-actor-meta-private.h"
589 #include "clutter-animatable.h"
590 #include "clutter-color-static.h"
591 #include "clutter-color.h"
592 #include "clutter-constraint.h"
593 #include "clutter-container.h"
594 #include "clutter-content-private.h"
595 #include "clutter-debug.h"
596 #include "clutter-effect-private.h"
597 #include "clutter-enum-types.h"
598 #include "clutter-fixed-layout.h"
599 #include "clutter-flatten-effect.h"
600 #include "clutter-interval.h"
601 #include "clutter-main.h"
602 #include "clutter-marshal.h"
603 #include "clutter-paint-nodes.h"
604 #include "clutter-paint-node-private.h"
605 #include "clutter-paint-volume-private.h"
606 #include "clutter-private.h"
607 #include "clutter-profile.h"
608 #include "clutter-property-transition.h"
609 #include "clutter-scriptable.h"
610 #include "clutter-script-private.h"
611 #include "clutter-stage-private.h"
612 #include "clutter-timeline.h"
613 #include "clutter-transition.h"
614 #include "clutter-units.h"
616 #include "deprecated/clutter-actor.h"
617 #include "deprecated/clutter-behaviour.h"
618 #include "deprecated/clutter-container.h"
620 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
621 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
623 /* Internal enum used to control mapped state update. This is a hint
624 * which indicates when to do something other than just enforce
628 MAP_STATE_CHECK, /* just enforce invariants. */
629 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
630 * used when about to unparent.
632 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
633 * used to set mapped on toplevels.
635 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
636 * used just before unmapping parent.
640 /* 3 entries should be a good compromise, few layout managers
641 * will ask for 3 different preferred size in each allocation cycle */
642 #define N_CACHED_SIZE_REQUESTS 3
644 struct _ClutterActorPrivate
647 ClutterRequestMode request_mode;
649 /* our cached size requests for different width / height */
650 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
651 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
653 /* An age of 0 means the entry is not set */
654 guint cached_height_age;
655 guint cached_width_age;
657 /* the bounding box of the actor, relative to the parent's
660 ClutterActorBox allocation;
661 ClutterAllocationFlags allocation_flags;
663 /* clip, in actor coordinates */
664 cairo_rectangle_t clip;
666 /* the cached transformation matrix; see apply_transform() */
667 CoglMatrix transform;
670 gint opacity_override;
672 ClutterOffscreenRedirect offscreen_redirect;
674 /* This is an internal effect used to implement the
675 offscreen-redirect property */
676 ClutterEffect *flatten_effect;
679 ClutterActor *parent;
680 ClutterActor *prev_sibling;
681 ClutterActor *next_sibling;
682 ClutterActor *first_child;
683 ClutterActor *last_child;
687 /* tracks whenever the children of an actor are changed; the
688 * age is incremented by 1 whenever an actor is added or
689 * removed. the age is not incremented when the first or the
690 * last child pointers are changed, or when grandchildren of
691 * an actor are changed.
695 gchar *name; /* a non-unique name, used for debugging */
696 guint32 id; /* unique id, used for backward compatibility */
698 gint32 pick_id; /* per-stage unique id, used for picking */
700 /* a back-pointer to the Pango context that we can use
701 * to create pre-configured PangoLayout
703 PangoContext *pango_context;
705 /* the text direction configured for this child - either by
706 * application code, or by the actor's parent
708 ClutterTextDirection text_direction;
710 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
714 ClutterMetaGroup *actions;
715 ClutterMetaGroup *constraints;
716 ClutterMetaGroup *effects;
718 /* delegate object used to allocate the children of this actor */
719 ClutterLayoutManager *layout_manager;
721 /* delegate object used to paint the contents of this actor */
722 ClutterContent *content;
724 ClutterActorBox content_box;
725 ClutterContentGravity content_gravity;
726 ClutterScalingFilter min_filter;
727 ClutterScalingFilter mag_filter;
729 /* used when painting, to update the paint volume */
730 ClutterEffect *current_effect;
732 /* This is used to store an effect which needs to be redrawn. A
733 redraw can be queued to start from a particular effect. This is
734 used by parametrised effects that can cache an image of the
735 actor. If a parameter of the effect changes then it only needs to
736 redraw the cached image, not the actual actor. The pointer is
737 only valid if is_dirty == TRUE. If the pointer is NULL then the
738 whole actor is dirty. */
739 ClutterEffect *effect_to_redraw;
741 /* This is used when painting effects to implement the
742 clutter_actor_continue_paint() function. It points to the node in
743 the list of effects that is next in the chain */
744 const GList *next_effect_to_paint;
746 ClutterPaintVolume paint_volume;
748 /* NB: This volume isn't relative to this actor, it is in eye
749 * coordinates so that it can remain valid after the actor changes.
751 ClutterPaintVolume last_paint_volume;
753 ClutterStageQueueRedrawEntry *queue_redraw_entry;
755 ClutterColor bg_color;
759 /* fixed position and sizes */
760 guint position_set : 1;
761 guint min_width_set : 1;
762 guint min_height_set : 1;
763 guint natural_width_set : 1;
764 guint natural_height_set : 1;
765 /* cached request is invalid (implies allocation is too) */
766 guint needs_width_request : 1;
767 /* cached request is invalid (implies allocation is too) */
768 guint needs_height_request : 1;
769 /* cached allocation is invalid (request has changed, probably) */
770 guint needs_allocation : 1;
771 guint show_on_set_parent : 1;
773 guint clip_to_allocation : 1;
774 guint enable_model_view_transform : 1;
775 guint enable_paint_unmapped : 1;
776 guint has_pointer : 1;
777 guint propagated_one_redraw : 1;
778 guint paint_volume_valid : 1;
779 guint last_paint_volume_valid : 1;
780 guint in_clone_paint : 1;
781 guint transform_valid : 1;
782 /* This is TRUE if anything has queued a redraw since we were last
783 painted. In this case effect_to_redraw will point to an effect
784 the redraw was queued from or it will be NULL if the redraw was
785 queued without an effect. */
787 guint bg_color_set : 1;
788 guint content_box_valid : 1;
789 guint x_expand_set : 1;
790 guint y_expand_set : 1;
791 guint needs_compute_expand : 1;
792 guint needs_x_expand : 1;
793 guint needs_y_expand : 1;
802 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
803 * when set they force a size request, when gotten they
804 * get the allocation if the allocation is valid, and the
815 /* Then the rest of these size-related properties are the "actual"
816 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
821 PROP_FIXED_POSITION_SET,
830 PROP_NATURAL_WIDTH_SET,
833 PROP_NATURAL_HEIGHT_SET,
837 /* Allocation properties are read-only */
844 PROP_CLIP_TO_ALLOCATION,
848 PROP_OFFSCREEN_REDIRECT,
861 PROP_ROTATION_ANGLE_X,
862 PROP_ROTATION_ANGLE_Y,
863 PROP_ROTATION_ANGLE_Z,
864 PROP_ROTATION_CENTER_X,
865 PROP_ROTATION_CENTER_Y,
866 PROP_ROTATION_CENTER_Z,
867 /* This property only makes sense for the z rotation because the
868 others would depend on the actor having a size along the
870 PROP_ROTATION_CENTER_Z_GRAVITY,
876 PROP_SHOW_ON_SET_PARENT,
896 PROP_BACKGROUND_COLOR,
897 PROP_BACKGROUND_COLOR_SET,
903 PROP_CONTENT_GRAVITY,
905 PROP_MINIFICATION_FILTER,
906 PROP_MAGNIFICATION_FILTER,
911 static GParamSpec *obj_props[PROP_LAST];
930 BUTTON_RELEASE_EVENT,
938 TRANSITIONS_COMPLETED,
943 static guint actor_signals[LAST_SIGNAL] = { 0, };
945 typedef struct _TransitionClosure
948 ClutterTransition *transition;
953 static void clutter_container_iface_init (ClutterContainerIface *iface);
954 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
955 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
956 static void atk_implementor_iface_init (AtkImplementorIface *iface);
958 /* These setters are all static for now, maybe they should be in the
959 * public API, but they are perhaps obscure enough to leave only as
962 static void clutter_actor_set_min_width (ClutterActor *self,
964 static void clutter_actor_set_min_height (ClutterActor *self,
966 static void clutter_actor_set_natural_width (ClutterActor *self,
967 gfloat natural_width);
968 static void clutter_actor_set_natural_height (ClutterActor *self,
969 gfloat natural_height);
970 static void clutter_actor_set_min_width_set (ClutterActor *self,
971 gboolean use_min_width);
972 static void clutter_actor_set_min_height_set (ClutterActor *self,
973 gboolean use_min_height);
974 static void clutter_actor_set_natural_width_set (ClutterActor *self,
975 gboolean use_natural_width);
976 static void clutter_actor_set_natural_height_set (ClutterActor *self,
977 gboolean use_natural_height);
978 static void clutter_actor_update_map_state (ClutterActor *self,
979 MapStateChange change);
980 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
982 /* Helper routines for managing anchor coords */
983 static void clutter_anchor_coord_get_units (ClutterActor *self,
984 const AnchorCoord *coord,
988 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
993 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
994 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
995 ClutterGravity gravity);
997 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
999 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
1001 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
1002 ClutterActor *ancestor,
1003 CoglMatrix *matrix);
1005 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
1007 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
1009 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
1010 const ClutterColor *color);
1012 static void on_layout_manager_changed (ClutterLayoutManager *manager,
1013 ClutterActor *self);
1015 static inline void clutter_actor_queue_compute_expand (ClutterActor *self);
1017 /* Helper macro which translates by the anchor coord, applies the
1018 given transformation and then translates back */
1019 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
1020 gfloat _tx, _ty, _tz; \
1021 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
1022 cogl_matrix_translate ((m), _tx, _ty, _tz); \
1024 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
1026 static GQuark quark_shader_data = 0;
1027 static GQuark quark_actor_layout_info = 0;
1028 static GQuark quark_actor_transform_info = 0;
1029 static GQuark quark_actor_animation_info = 0;
1031 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1033 G_TYPE_INITIALLY_UNOWNED,
1034 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1035 clutter_container_iface_init)
1036 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1037 clutter_scriptable_iface_init)
1038 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1039 clutter_animatable_iface_init)
1040 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1041 atk_implementor_iface_init));
1044 * clutter_actor_get_debug_name:
1045 * @actor: a #ClutterActor
1047 * Retrieves a printable name of @actor for debugging messages
1049 * Return value: a string with a printable name
1052 _clutter_actor_get_debug_name (ClutterActor *actor)
1054 return actor->priv->name != NULL ? actor->priv->name
1055 : G_OBJECT_TYPE_NAME (actor);
1058 #ifdef CLUTTER_ENABLE_DEBUG
1059 /* XXX - this is for debugging only, remove once working (or leave
1060 * in only in some debug mode). Should leave it for a little while
1061 * until we're confident in the new map/realize/visible handling.
1064 clutter_actor_verify_map_state (ClutterActor *self)
1066 ClutterActorPrivate *priv = self->priv;
1068 if (CLUTTER_ACTOR_IS_REALIZED (self))
1070 /* all bets are off during reparent when we're potentially realized,
1071 * but should not be according to invariants
1073 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1075 if (priv->parent == NULL)
1077 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1081 g_warning ("Realized non-toplevel actor '%s' should "
1083 _clutter_actor_get_debug_name (self));
1085 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1087 g_warning ("Realized actor %s has an unrealized parent %s",
1088 _clutter_actor_get_debug_name (self),
1089 _clutter_actor_get_debug_name (priv->parent));
1094 if (CLUTTER_ACTOR_IS_MAPPED (self))
1096 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1097 g_warning ("Actor '%s' is mapped but not realized",
1098 _clutter_actor_get_debug_name (self));
1100 /* remaining bets are off during reparent when we're potentially
1101 * mapped, but should not be according to invariants
1103 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1105 if (priv->parent == NULL)
1107 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1109 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1110 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1112 g_warning ("Toplevel actor '%s' is mapped "
1114 _clutter_actor_get_debug_name (self));
1119 g_warning ("Mapped actor '%s' should have a parent",
1120 _clutter_actor_get_debug_name (self));
1125 ClutterActor *iter = self;
1127 /* check for the enable_paint_unmapped flag on the actor
1128 * and parents; if the flag is enabled at any point of this
1129 * branch of the scene graph then all the later checks
1132 while (iter != NULL)
1134 if (iter->priv->enable_paint_unmapped)
1137 iter = iter->priv->parent;
1140 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1142 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1144 _clutter_actor_get_debug_name (self),
1145 _clutter_actor_get_debug_name (priv->parent));
1148 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1150 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1152 _clutter_actor_get_debug_name (self),
1153 _clutter_actor_get_debug_name (priv->parent));
1156 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1158 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1159 g_warning ("Actor '%s' is mapped but its non-toplevel "
1160 "parent '%s' is not mapped",
1161 _clutter_actor_get_debug_name (self),
1162 _clutter_actor_get_debug_name (priv->parent));
1169 #endif /* CLUTTER_ENABLE_DEBUG */
1172 clutter_actor_set_mapped (ClutterActor *self,
1175 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1180 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1181 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1185 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1186 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1190 /* this function updates the mapped and realized states according to
1191 * invariants, in the appropriate order.
1194 clutter_actor_update_map_state (ClutterActor *self,
1195 MapStateChange change)
1197 gboolean was_mapped;
1199 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1201 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1203 /* the mapped flag on top-level actors must be set by the
1204 * per-backend implementation because it might be asynchronous.
1206 * That is, the MAPPED flag on toplevels currently tracks the X
1207 * server mapped-ness of the window, while the expected behavior
1208 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1209 * This creates some weird complexity by breaking the invariant
1210 * that if we're visible and all ancestors shown then we are
1211 * also mapped - instead, we are mapped if all ancestors
1212 * _possibly excepting_ the stage are mapped. The stage
1213 * will map/unmap for example when it is minimized or
1214 * moved to another workspace.
1216 * So, the only invariant on the stage is that if visible it
1217 * should be realized, and that it has to be visible to be
1220 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1221 clutter_actor_realize (self);
1225 case MAP_STATE_CHECK:
1228 case MAP_STATE_MAKE_MAPPED:
1229 g_assert (!was_mapped);
1230 clutter_actor_set_mapped (self, TRUE);
1233 case MAP_STATE_MAKE_UNMAPPED:
1234 g_assert (was_mapped);
1235 clutter_actor_set_mapped (self, FALSE);
1238 case MAP_STATE_MAKE_UNREALIZED:
1239 /* we only use MAKE_UNREALIZED in unparent,
1240 * and unparenting a stage isn't possible.
1241 * If someone wants to just unrealize a stage
1242 * then clutter_actor_unrealize() doesn't
1243 * go through this codepath.
1245 g_warning ("Trying to force unrealize stage is not allowed");
1249 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1250 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1251 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1253 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1254 "it is somehow still mapped",
1255 _clutter_actor_get_debug_name (self));
1260 ClutterActorPrivate *priv = self->priv;
1261 ClutterActor *parent = priv->parent;
1262 gboolean should_be_mapped;
1263 gboolean may_be_realized;
1264 gboolean must_be_realized;
1266 should_be_mapped = FALSE;
1267 may_be_realized = TRUE;
1268 must_be_realized = FALSE;
1270 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1272 may_be_realized = FALSE;
1276 /* Maintain invariant that if parent is mapped, and we are
1277 * visible, then we are mapped ... unless parent is a
1278 * stage, in which case we map regardless of parent's map
1279 * state but do require stage to be visible and realized.
1281 * If parent is realized, that does not force us to be
1282 * realized; but if parent is unrealized, that does force
1283 * us to be unrealized.
1285 * The reason we don't force children to realize with
1286 * parents is _clutter_actor_rerealize(); if we require that
1287 * a realized parent means children are realized, then to
1288 * unrealize an actor we would have to unrealize its
1289 * parents, which would end up meaning unrealizing and
1290 * hiding the entire stage. So we allow unrealizing a
1291 * child (as long as that child is not mapped) while that
1292 * child still has a realized parent.
1294 * Also, if we unrealize from leaf nodes to root, and
1295 * realize from root to leaf, the invariants are never
1296 * violated if we allow children to be unrealized
1297 * while parents are realized.
1299 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1300 * to force us to unmap, even though parent is still
1301 * mapped. This is because we're unmapping from leaf nodes
1304 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1305 change != MAP_STATE_MAKE_UNMAPPED)
1307 gboolean parent_is_visible_realized_toplevel;
1309 parent_is_visible_realized_toplevel =
1310 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1311 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1312 CLUTTER_ACTOR_IS_REALIZED (parent));
1314 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1315 parent_is_visible_realized_toplevel)
1317 must_be_realized = TRUE;
1318 should_be_mapped = TRUE;
1322 /* if the actor has been set to be painted even if unmapped
1323 * then we should map it and check for realization as well;
1324 * this is an override for the branch of the scene graph
1325 * which begins with this node
1327 if (priv->enable_paint_unmapped)
1329 if (priv->parent == NULL)
1330 g_warning ("Attempting to map an unparented actor '%s'",
1331 _clutter_actor_get_debug_name (self));
1333 should_be_mapped = TRUE;
1334 must_be_realized = TRUE;
1337 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1338 may_be_realized = FALSE;
1341 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1344 g_warning ("Attempting to map a child that does not "
1345 "meet the necessary invariants: the actor '%s' "
1347 _clutter_actor_get_debug_name (self));
1349 g_warning ("Attempting to map a child that does not "
1350 "meet the necessary invariants: the actor '%s' "
1351 "is parented to an unmapped actor '%s'",
1352 _clutter_actor_get_debug_name (self),
1353 _clutter_actor_get_debug_name (priv->parent));
1356 /* If in reparent, we temporarily suspend unmap and unrealize.
1358 * We want to go in the order "realize, map" and "unmap, unrealize"
1362 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1363 clutter_actor_set_mapped (self, FALSE);
1366 if (must_be_realized)
1367 clutter_actor_realize (self);
1369 /* if we must be realized then we may be, presumably */
1370 g_assert (!(must_be_realized && !may_be_realized));
1373 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1374 clutter_actor_unrealize_not_hiding (self);
1377 if (should_be_mapped)
1379 if (!must_be_realized)
1380 g_warning ("Somehow we think actor '%s' should be mapped but "
1381 "not realized, which isn't allowed",
1382 _clutter_actor_get_debug_name (self));
1384 /* realization is allowed to fail (though I don't know what
1385 * an app is supposed to do about that - shouldn't it just
1386 * be a g_error? anyway, we have to avoid mapping if this
1389 if (CLUTTER_ACTOR_IS_REALIZED (self))
1390 clutter_actor_set_mapped (self, TRUE);
1394 #ifdef CLUTTER_ENABLE_DEBUG
1395 /* check all invariants were kept */
1396 clutter_actor_verify_map_state (self);
1401 clutter_actor_real_map (ClutterActor *self)
1403 ClutterActorPrivate *priv = self->priv;
1404 ClutterActor *stage, *iter;
1406 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1408 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1409 _clutter_actor_get_debug_name (self));
1411 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1413 stage = _clutter_actor_get_stage_internal (self);
1414 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1416 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1418 _clutter_actor_get_debug_name (self));
1420 /* notify on parent mapped before potentially mapping
1421 * children, so apps see a top-down notification.
1423 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1425 for (iter = self->priv->first_child;
1427 iter = iter->priv->next_sibling)
1429 clutter_actor_map (iter);
1434 * clutter_actor_map:
1435 * @self: A #ClutterActor
1437 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1438 * and realizes its children if they are visible. Does nothing if the
1439 * actor is not visible.
1441 * Calling this function is strongly disencouraged: the default
1442 * implementation of #ClutterActorClass.map() will map all the children
1443 * of an actor when mapping its parent.
1445 * When overriding map, it is mandatory to chain up to the parent
1451 clutter_actor_map (ClutterActor *self)
1453 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1455 if (CLUTTER_ACTOR_IS_MAPPED (self))
1458 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1461 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1465 clutter_actor_real_unmap (ClutterActor *self)
1467 ClutterActorPrivate *priv = self->priv;
1470 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1472 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1473 _clutter_actor_get_debug_name (self));
1475 for (iter = self->priv->first_child;
1477 iter = iter->priv->next_sibling)
1479 clutter_actor_unmap (iter);
1482 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1484 /* clear the contents of the last paint volume, so that hiding + moving +
1485 * showing will not result in the wrong area being repainted
1487 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1488 priv->last_paint_volume_valid = TRUE;
1490 /* notify on parent mapped after potentially unmapping
1491 * children, so apps see a bottom-up notification.
1493 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1495 /* relinquish keyboard focus if we were unmapped while owning it */
1496 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1498 ClutterStage *stage;
1500 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1503 _clutter_stage_release_pick_id (stage, priv->pick_id);
1507 if (stage != NULL &&
1508 clutter_stage_get_key_focus (stage) == self)
1510 clutter_stage_set_key_focus (stage, NULL);
1516 * clutter_actor_unmap:
1517 * @self: A #ClutterActor
1519 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1520 * unmaps its children if they were mapped.
1522 * Calling this function is not encouraged: the default #ClutterActor
1523 * implementation of #ClutterActorClass.unmap() will also unmap any
1524 * eventual children by default when their parent is unmapped.
1526 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1527 * chain up to the parent implementation.
1529 * <note>It is important to note that the implementation of the
1530 * #ClutterActorClass.unmap() virtual function may be called after
1531 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1532 * implementation, but it is guaranteed to be called before the
1533 * #GObjectClass.finalize() implementation.</note>
1538 clutter_actor_unmap (ClutterActor *self)
1540 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1542 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1545 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1549 clutter_actor_real_show (ClutterActor *self)
1551 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1553 ClutterActorPrivate *priv = self->priv;
1555 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1557 /* we notify on the "visible" flag in the clutter_actor_show()
1558 * wrapper so the entire show signal emission completes first
1561 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1563 /* we queue a relayout unless the actor is inside a
1564 * container that explicitly told us not to
1566 if (priv->parent != NULL &&
1567 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1569 /* While an actor is hidden the parent may not have
1570 * allocated/requested so we need to start from scratch
1571 * and avoid the short-circuiting in
1572 * clutter_actor_queue_relayout().
1574 priv->needs_width_request = FALSE;
1575 priv->needs_height_request = FALSE;
1576 priv->needs_allocation = FALSE;
1577 clutter_actor_queue_relayout (self);
1583 set_show_on_set_parent (ClutterActor *self,
1586 ClutterActorPrivate *priv = self->priv;
1588 set_show = !!set_show;
1590 if (priv->show_on_set_parent == set_show)
1593 if (priv->parent == NULL)
1595 priv->show_on_set_parent = set_show;
1596 g_object_notify_by_pspec (G_OBJECT (self),
1597 obj_props[PROP_SHOW_ON_SET_PARENT]);
1602 * clutter_actor_show:
1603 * @self: A #ClutterActor
1605 * Flags an actor to be displayed. An actor that isn't shown will not
1606 * be rendered on the stage.
1608 * Actors are visible by default.
1610 * If this function is called on an actor without a parent, the
1611 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1615 clutter_actor_show (ClutterActor *self)
1617 ClutterActorPrivate *priv;
1619 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1621 /* simple optimization */
1622 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1624 /* we still need to set the :show-on-set-parent property, in
1625 * case show() is called on an unparented actor
1627 set_show_on_set_parent (self, TRUE);
1631 #ifdef CLUTTER_ENABLE_DEBUG
1632 clutter_actor_verify_map_state (self);
1637 g_object_freeze_notify (G_OBJECT (self));
1639 set_show_on_set_parent (self, TRUE);
1641 /* if we're showing a child that needs to expand, or may
1642 * expand, then we need to recompute the expand flags for
1643 * its parent as well
1645 if (priv->needs_compute_expand ||
1646 priv->needs_x_expand ||
1647 priv->needs_y_expand)
1649 clutter_actor_queue_compute_expand (self);
1652 g_signal_emit (self, actor_signals[SHOW], 0);
1653 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1655 if (priv->parent != NULL)
1656 clutter_actor_queue_redraw (priv->parent);
1658 g_object_thaw_notify (G_OBJECT (self));
1662 * clutter_actor_show_all:
1663 * @self: a #ClutterActor
1665 * Calls clutter_actor_show() on all children of an actor (if any).
1669 * Deprecated: 1.10: Actors are visible by default
1672 clutter_actor_show_all (ClutterActor *self)
1674 ClutterActorClass *klass;
1676 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1678 klass = CLUTTER_ACTOR_GET_CLASS (self);
1679 if (klass->show_all)
1680 klass->show_all (self);
1684 clutter_actor_real_hide (ClutterActor *self)
1686 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1688 ClutterActorPrivate *priv = self->priv;
1690 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1692 /* we notify on the "visible" flag in the clutter_actor_hide()
1693 * wrapper so the entire hide signal emission completes first
1696 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1698 /* we queue a relayout unless the actor is inside a
1699 * container that explicitly told us not to
1701 if (priv->parent != NULL &&
1702 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1703 clutter_actor_queue_relayout (priv->parent);
1708 * clutter_actor_hide:
1709 * @self: A #ClutterActor
1711 * Flags an actor to be hidden. A hidden actor will not be
1712 * rendered on the stage.
1714 * Actors are visible by default.
1716 * If this function is called on an actor without a parent, the
1717 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1721 clutter_actor_hide (ClutterActor *self)
1723 ClutterActorPrivate *priv;
1725 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1727 /* simple optimization */
1728 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1730 /* we still need to set the :show-on-set-parent property, in
1731 * case hide() is called on an unparented actor
1733 set_show_on_set_parent (self, FALSE);
1737 #ifdef CLUTTER_ENABLE_DEBUG
1738 clutter_actor_verify_map_state (self);
1743 g_object_freeze_notify (G_OBJECT (self));
1745 set_show_on_set_parent (self, FALSE);
1747 /* if we're hiding a child that needs to expand, or may
1748 * expand, then we need to recompute the expand flags for
1749 * its parent as well
1751 if (priv->needs_compute_expand ||
1752 priv->needs_x_expand ||
1753 priv->needs_y_expand)
1755 clutter_actor_queue_compute_expand (self);
1758 g_signal_emit (self, actor_signals[HIDE], 0);
1759 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1761 if (priv->parent != NULL)
1762 clutter_actor_queue_redraw (priv->parent);
1764 g_object_thaw_notify (G_OBJECT (self));
1768 * clutter_actor_hide_all:
1769 * @self: a #ClutterActor
1771 * Calls clutter_actor_hide() on all child actors (if any).
1775 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1776 * prevent its children from being painted as well.
1779 clutter_actor_hide_all (ClutterActor *self)
1781 ClutterActorClass *klass;
1783 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1785 klass = CLUTTER_ACTOR_GET_CLASS (self);
1786 if (klass->hide_all)
1787 klass->hide_all (self);
1791 * clutter_actor_realize:
1792 * @self: A #ClutterActor
1794 * Realization informs the actor that it is attached to a stage. It
1795 * can use this to allocate resources if it wanted to delay allocation
1796 * until it would be rendered. However it is perfectly acceptable for
1797 * an actor to create resources before being realized because Clutter
1798 * only ever has a single rendering context so that actor is free to
1799 * be moved from one stage to another.
1801 * This function does nothing if the actor is already realized.
1803 * Because a realized actor must have realized parent actors, calling
1804 * clutter_actor_realize() will also realize all parents of the actor.
1806 * This function does not realize child actors, except in the special
1807 * case that realizing the stage, when the stage is visible, will
1808 * suddenly map (and thus realize) the children of the stage.
1811 clutter_actor_realize (ClutterActor *self)
1813 ClutterActorPrivate *priv;
1815 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1819 #ifdef CLUTTER_ENABLE_DEBUG
1820 clutter_actor_verify_map_state (self);
1823 if (CLUTTER_ACTOR_IS_REALIZED (self))
1826 /* To be realized, our parent actors must be realized first.
1827 * This will only succeed if we're inside a toplevel.
1829 if (priv->parent != NULL)
1830 clutter_actor_realize (priv->parent);
1832 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1834 /* toplevels can be realized at any time */
1838 /* "Fail" the realization if parent is missing or unrealized;
1839 * this should really be a g_warning() not some kind of runtime
1840 * failure; how can an app possibly recover? Instead it's a bug
1841 * in the app and the app should get an explanatory warning so
1842 * someone can fix it. But for now it's too hard to fix this
1843 * because e.g. ClutterTexture needs reworking.
1845 if (priv->parent == NULL ||
1846 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1850 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1852 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1853 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1855 g_signal_emit (self, actor_signals[REALIZE], 0);
1857 /* Stage actor is allowed to unset the realized flag again in its
1858 * default signal handler, though that is a pathological situation.
1861 /* If realization "failed" we'll have to update child state. */
1862 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1866 clutter_actor_real_unrealize (ClutterActor *self)
1868 /* we must be unmapped (implying our children are also unmapped) */
1869 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1873 * clutter_actor_unrealize:
1874 * @self: A #ClutterActor
1876 * Unrealization informs the actor that it may be being destroyed or
1877 * moved to another stage. The actor may want to destroy any
1878 * underlying graphics resources at this point. However it is
1879 * perfectly acceptable for it to retain the resources until the actor
1880 * is destroyed because Clutter only ever uses a single rendering
1881 * context and all of the graphics resources are valid on any stage.
1883 * Because mapped actors must be realized, actors may not be
1884 * unrealized if they are mapped. This function hides the actor to be
1885 * sure it isn't mapped, an application-visible side effect that you
1886 * may not be expecting.
1888 * This function should not be called by application code.
1891 clutter_actor_unrealize (ClutterActor *self)
1893 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1894 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1896 /* This function should not really be in the public API, because
1897 * there isn't a good reason to call it. ClutterActor will already
1898 * unrealize things for you when it's important to do so.
1900 * If you were using clutter_actor_unrealize() in a dispose
1901 * implementation, then don't, just chain up to ClutterActor's
1904 * If you were using clutter_actor_unrealize() to implement
1905 * unrealizing children of your container, then don't, ClutterActor
1906 * will already take care of that.
1908 * If you were using clutter_actor_unrealize() to re-realize to
1909 * create your resources in a different way, then use
1910 * _clutter_actor_rerealize() (inside Clutter) or just call your
1911 * code that recreates your resources directly (outside Clutter).
1914 #ifdef CLUTTER_ENABLE_DEBUG
1915 clutter_actor_verify_map_state (self);
1918 clutter_actor_hide (self);
1920 clutter_actor_unrealize_not_hiding (self);
1923 static ClutterActorTraverseVisitFlags
1924 unrealize_actor_before_children_cb (ClutterActor *self,
1928 /* If an actor is already unrealized we know its children have also
1929 * already been unrealized... */
1930 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1931 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1933 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1935 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1938 static ClutterActorTraverseVisitFlags
1939 unrealize_actor_after_children_cb (ClutterActor *self,
1943 /* We want to unset the realized flag only _after_
1944 * child actors are unrealized, to maintain invariants.
1946 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1947 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1948 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1952 * clutter_actor_unrealize_not_hiding:
1953 * @self: A #ClutterActor
1955 * Unrealization informs the actor that it may be being destroyed or
1956 * moved to another stage. The actor may want to destroy any
1957 * underlying graphics resources at this point. However it is
1958 * perfectly acceptable for it to retain the resources until the actor
1959 * is destroyed because Clutter only ever uses a single rendering
1960 * context and all of the graphics resources are valid on any stage.
1962 * Because mapped actors must be realized, actors may not be
1963 * unrealized if they are mapped. You must hide the actor or one of
1964 * its parents before attempting to unrealize.
1966 * This function is separate from clutter_actor_unrealize() because it
1967 * does not automatically hide the actor.
1968 * Actors need not be hidden to be unrealized, they just need to
1969 * be unmapped. In fact we don't want to mess up the application's
1970 * setting of the "visible" flag, so hiding is very undesirable.
1972 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1973 * backward compatibility.
1976 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1978 _clutter_actor_traverse (self,
1979 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1980 unrealize_actor_before_children_cb,
1981 unrealize_actor_after_children_cb,
1986 * _clutter_actor_rerealize:
1987 * @self: A #ClutterActor
1988 * @callback: Function to call while unrealized
1989 * @data: data for callback
1991 * If an actor is already unrealized, this just calls the callback.
1993 * If it is realized, it unrealizes temporarily, calls the callback,
1994 * and then re-realizes the actor.
1996 * As a side effect, leaves all children of the actor unrealized if
1997 * the actor was realized but not showing. This is because when we
1998 * unrealize the actor temporarily we must unrealize its children
1999 * (e.g. children of a stage can't be realized if stage window is
2000 * gone). And we aren't clever enough to save the realization state of
2001 * all children. In most cases this should not matter, because
2002 * the children will automatically realize when they next become mapped.
2005 _clutter_actor_rerealize (ClutterActor *self,
2006 ClutterCallback callback,
2009 gboolean was_mapped;
2010 gboolean was_showing;
2011 gboolean was_realized;
2013 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2015 #ifdef CLUTTER_ENABLE_DEBUG
2016 clutter_actor_verify_map_state (self);
2019 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
2020 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
2021 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
2023 /* Must be unmapped to unrealize. Note we only have to hide this
2024 * actor if it was mapped (if all parents were showing). If actor
2025 * is merely visible (but not mapped), then that's fine, we can
2029 clutter_actor_hide (self);
2031 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
2033 /* unrealize self and all children */
2034 clutter_actor_unrealize_not_hiding (self);
2036 if (callback != NULL)
2038 (* callback) (self, data);
2042 clutter_actor_show (self); /* will realize only if mapping implies it */
2043 else if (was_realized)
2044 clutter_actor_realize (self); /* realize self and all parents */
2048 clutter_actor_real_pick (ClutterActor *self,
2049 const ClutterColor *color)
2051 /* the default implementation is just to paint a rectangle
2052 * with the same size of the actor using the passed color
2054 if (clutter_actor_should_pick_paint (self))
2056 ClutterActorBox box = { 0, };
2057 float width, height;
2059 clutter_actor_get_allocation_box (self, &box);
2061 width = box.x2 - box.x1;
2062 height = box.y2 - box.y1;
2064 cogl_set_source_color4ub (color->red,
2069 cogl_rectangle (0, 0, width, height);
2072 /* XXX - this thoroughly sucks, but we need to maintain compatibility
2073 * with existing container classes that override the pick() virtual
2074 * and chain up to the default implementation - otherwise we'll end up
2075 * painting our children twice.
2077 * this has to go away for 2.0; hopefully along the pick() itself.
2079 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2083 for (iter = self->priv->first_child;
2085 iter = iter->priv->next_sibling)
2086 clutter_actor_paint (iter);
2091 * clutter_actor_should_pick_paint:
2092 * @self: A #ClutterActor
2094 * Should be called inside the implementation of the
2095 * #ClutterActor::pick virtual function in order to check whether
2096 * the actor should paint itself in pick mode or not.
2098 * This function should never be called directly by applications.
2100 * Return value: %TRUE if the actor should paint its silhouette,
2104 clutter_actor_should_pick_paint (ClutterActor *self)
2106 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2108 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2109 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2110 CLUTTER_ACTOR_IS_REACTIVE (self)))
2117 clutter_actor_real_get_preferred_width (ClutterActor *self,
2119 gfloat *min_width_p,
2120 gfloat *natural_width_p)
2122 ClutterActorPrivate *priv = self->priv;
2124 if (priv->n_children != 0 &&
2125 priv->layout_manager != NULL)
2127 ClutterContainer *container = CLUTTER_CONTAINER (self);
2129 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2130 "for the preferred width",
2131 G_OBJECT_TYPE_NAME (priv->layout_manager),
2132 priv->layout_manager);
2134 clutter_layout_manager_get_preferred_width (priv->layout_manager,
2143 /* Default implementation is always 0x0, usually an actor
2144 * using this default is relying on someone to set the
2147 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2152 if (natural_width_p)
2153 *natural_width_p = 0;
2157 clutter_actor_real_get_preferred_height (ClutterActor *self,
2159 gfloat *min_height_p,
2160 gfloat *natural_height_p)
2162 ClutterActorPrivate *priv = self->priv;
2164 if (priv->n_children != 0 &&
2165 priv->layout_manager != NULL)
2167 ClutterContainer *container = CLUTTER_CONTAINER (self);
2169 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2170 "for the preferred height",
2171 G_OBJECT_TYPE_NAME (priv->layout_manager),
2172 priv->layout_manager);
2174 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2182 /* Default implementation is always 0x0, usually an actor
2183 * using this default is relying on someone to set the
2186 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2191 if (natural_height_p)
2192 *natural_height_p = 0;
2196 clutter_actor_store_old_geometry (ClutterActor *self,
2197 ClutterActorBox *box)
2199 *box = self->priv->allocation;
2203 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2204 const ClutterActorBox *old)
2206 ClutterActorPrivate *priv = self->priv;
2207 GObject *obj = G_OBJECT (self);
2209 g_object_freeze_notify (obj);
2211 /* to avoid excessive requisition or allocation cycles we
2212 * use the cached values.
2214 * - if we don't have an allocation we assume that we need
2216 * - if we don't have a width or a height request we notify
2218 * - if we have a valid allocation then we check the old
2219 * bounding box with the current allocation and we notify
2222 if (priv->needs_allocation)
2224 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2225 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2226 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2227 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2228 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2229 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2231 else if (priv->needs_width_request || priv->needs_height_request)
2233 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2234 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2235 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2240 gfloat width, height;
2242 x = priv->allocation.x1;
2243 y = priv->allocation.y1;
2244 width = priv->allocation.x2 - priv->allocation.x1;
2245 height = priv->allocation.y2 - priv->allocation.y1;
2249 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2250 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2255 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2256 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2259 if (width != (old->x2 - old->x1))
2261 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2262 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2265 if (height != (old->y2 - old->y1))
2267 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2268 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2272 g_object_thaw_notify (obj);
2276 * clutter_actor_set_allocation_internal:
2277 * @self: a #ClutterActor
2278 * @box: a #ClutterActorBox
2279 * @flags: allocation flags
2281 * Stores the allocation of @self.
2283 * This function only performs basic storage and property notification.
2285 * This function should be called by clutter_actor_set_allocation()
2286 * and by the default implementation of #ClutterActorClass.allocate().
2288 * Return value: %TRUE if the allocation of the #ClutterActor has been
2289 * changed, and %FALSE otherwise
2291 static inline gboolean
2292 clutter_actor_set_allocation_internal (ClutterActor *self,
2293 const ClutterActorBox *box,
2294 ClutterAllocationFlags flags)
2296 ClutterActorPrivate *priv = self->priv;
2298 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2300 ClutterActorBox old_alloc = { 0, };
2302 obj = G_OBJECT (self);
2304 g_object_freeze_notify (obj);
2306 clutter_actor_store_old_geometry (self, &old_alloc);
2308 x1_changed = priv->allocation.x1 != box->x1;
2309 y1_changed = priv->allocation.y1 != box->y1;
2310 x2_changed = priv->allocation.x2 != box->x2;
2311 y2_changed = priv->allocation.y2 != box->y2;
2313 priv->allocation = *box;
2314 priv->allocation_flags = flags;
2316 /* allocation is authoritative */
2317 priv->needs_width_request = FALSE;
2318 priv->needs_height_request = FALSE;
2319 priv->needs_allocation = FALSE;
2326 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2327 _clutter_actor_get_debug_name (self));
2329 priv->transform_valid = FALSE;
2331 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2333 /* if the allocation changes, so does the content box */
2334 if (priv->content != NULL)
2336 priv->content_box_valid = FALSE;
2337 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2345 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2347 g_object_thaw_notify (obj);
2352 static void clutter_actor_real_allocate (ClutterActor *self,
2353 const ClutterActorBox *box,
2354 ClutterAllocationFlags flags);
2357 clutter_actor_maybe_layout_children (ClutterActor *self,
2358 const ClutterActorBox *allocation,
2359 ClutterAllocationFlags flags)
2361 ClutterActorPrivate *priv = self->priv;
2363 /* this is going to be a bit hard to follow, so let's put an explanation
2366 * we want ClutterActor to have a default layout manager if the actor was
2367 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2369 * we also want any subclass of ClutterActor that does not override the
2370 * ::allocate() virtual function to delegate to a layout manager.
2372 * finally, we want to allow people subclassing ClutterActor and overriding
2373 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2375 * on the other hand, we want existing actor subclasses overriding the
2376 * ::allocate() virtual function and chaining up to the parent's
2377 * implementation to continue working without allocating their children
2378 * twice, or without entering an allocation loop.
2380 * for the first two points, we check if the class of the actor is
2381 * overridding the ::allocate() virtual function; if it isn't, then we
2382 * follow through with checking whether we have children and a layout
2383 * manager, and eventually calling clutter_layout_manager_allocate().
2385 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2386 * allocation flags that we got passed, and if it is present, we continue
2387 * with the check above.
2389 * if neither of these two checks yields a positive result, we just
2390 * assume that the ::allocate() virtual function that resulted in this
2391 * function being called will also allocate the children of the actor.
2394 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2397 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2403 if (priv->n_children != 0 &&
2404 priv->layout_manager != NULL)
2406 ClutterContainer *container = CLUTTER_CONTAINER (self);
2407 ClutterAllocationFlags children_flags;
2408 ClutterActorBox children_box;
2410 /* normalize the box passed to the layout manager */
2411 children_box.x1 = children_box.y1 = 0.f;
2412 children_box.x2 = (allocation->x2 - allocation->x1);
2413 children_box.y2 = (allocation->y2 - allocation->y1);
2415 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2416 * the actor's children, since it refers only to the current
2417 * actor's allocation.
2419 children_flags = flags;
2420 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2422 CLUTTER_NOTE (LAYOUT,
2423 "Allocating %d children of %s "
2424 "at { %.2f, %.2f - %.2f x %.2f } "
2427 _clutter_actor_get_debug_name (self),
2430 (allocation->x2 - allocation->x1),
2431 (allocation->y2 - allocation->y1),
2432 G_OBJECT_TYPE_NAME (priv->layout_manager));
2434 clutter_layout_manager_allocate (priv->layout_manager,
2442 clutter_actor_real_allocate (ClutterActor *self,
2443 const ClutterActorBox *box,
2444 ClutterAllocationFlags flags)
2446 ClutterActorPrivate *priv = self->priv;
2449 g_object_freeze_notify (G_OBJECT (self));
2451 changed = clutter_actor_set_allocation_internal (self, box, flags);
2453 /* we allocate our children before we notify changes in our geometry,
2454 * so that people connecting to properties will be able to get valid
2455 * data out of the sub-tree of the scene graph that has this actor at
2458 clutter_actor_maybe_layout_children (self, box, flags);
2462 ClutterActorBox signal_box = priv->allocation;
2463 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2465 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2470 g_object_thaw_notify (G_OBJECT (self));
2474 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2475 ClutterActor *origin)
2477 /* no point in queuing a redraw on a destroyed actor */
2478 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2481 /* NB: We can't bail out early here if the actor is hidden in case
2482 * the actor bas been cloned. In this case the clone will need to
2483 * receive the signal so it can queue its own redraw.
2486 /* calls klass->queue_redraw in default handler */
2487 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2491 clutter_actor_real_queue_redraw (ClutterActor *self,
2492 ClutterActor *origin)
2494 ClutterActor *parent;
2496 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2497 _clutter_actor_get_debug_name (self),
2498 origin != NULL ? _clutter_actor_get_debug_name (origin)
2501 /* no point in queuing a redraw on a destroyed actor */
2502 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2505 /* If the queue redraw is coming from a child then the actor has
2506 become dirty and any queued effect is no longer valid */
2509 self->priv->is_dirty = TRUE;
2510 self->priv->effect_to_redraw = NULL;
2513 /* If the actor isn't visible, we still had to emit the signal
2514 * to allow for a ClutterClone, but the appearance of the parent
2515 * won't change so we don't have to propagate up the hierarchy.
2517 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2520 /* Although we could determine here that a full stage redraw
2521 * has already been queued and immediately bail out, we actually
2522 * guarantee that we will propagate a queue-redraw signal to our
2523 * parent at least once so that it's possible to implement a
2524 * container that tracks which of its children have queued a
2527 if (self->priv->propagated_one_redraw)
2529 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2530 if (stage != NULL &&
2531 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2535 self->priv->propagated_one_redraw = TRUE;
2537 /* notify parents, if they are all visible eventually we'll
2538 * queue redraw on the stage, which queues the redraw idle.
2540 parent = clutter_actor_get_parent (self);
2543 /* this will go up recursively */
2544 _clutter_actor_signal_queue_redraw (parent, origin);
2549 clutter_actor_real_queue_relayout (ClutterActor *self)
2551 ClutterActorPrivate *priv = self->priv;
2553 /* no point in queueing a redraw on a destroyed actor */
2554 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2557 priv->needs_width_request = TRUE;
2558 priv->needs_height_request = TRUE;
2559 priv->needs_allocation = TRUE;
2561 /* reset the cached size requests */
2562 memset (priv->width_requests, 0,
2563 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2564 memset (priv->height_requests, 0,
2565 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2567 /* We need to go all the way up the hierarchy */
2568 if (priv->parent != NULL)
2569 _clutter_actor_queue_only_relayout (priv->parent);
2573 * clutter_actor_apply_relative_transform_to_point:
2574 * @self: A #ClutterActor
2575 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2576 * default #ClutterStage
2577 * @point: A point as #ClutterVertex
2578 * @vertex: (out caller-allocates): The translated #ClutterVertex
2580 * Transforms @point in coordinates relative to the actor into
2581 * ancestor-relative coordinates using the relevant transform
2582 * stack (i.e. scale, rotation, etc).
2584 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2585 * this case, the coordinates returned will be the coordinates on
2586 * the stage before the projection is applied. This is different from
2587 * the behaviour of clutter_actor_apply_transform_to_point().
2592 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2593 ClutterActor *ancestor,
2594 const ClutterVertex *point,
2595 ClutterVertex *vertex)
2600 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2601 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2602 g_return_if_fail (point != NULL);
2603 g_return_if_fail (vertex != NULL);
2608 if (ancestor == NULL)
2609 ancestor = _clutter_actor_get_stage_internal (self);
2611 if (ancestor == NULL)
2617 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2618 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2622 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2623 const ClutterVertex *vertices_in,
2624 ClutterVertex *vertices_out,
2627 ClutterActor *stage;
2628 CoglMatrix modelview;
2629 CoglMatrix projection;
2632 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2634 stage = _clutter_actor_get_stage_internal (self);
2636 /* We really can't do anything meaningful in this case so don't try
2637 * to do any transform */
2641 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2642 * that gets us to stage coordinates, we want to go all the way to eye
2644 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2646 /* Fetch the projection and viewport */
2647 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2648 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2654 _clutter_util_fully_transform_vertices (&modelview,
2665 * clutter_actor_apply_transform_to_point:
2666 * @self: A #ClutterActor
2667 * @point: A point as #ClutterVertex
2668 * @vertex: (out caller-allocates): The translated #ClutterVertex
2670 * Transforms @point in coordinates relative to the actor
2671 * into screen-relative coordinates with the current actor
2672 * transformation (i.e. scale, rotation, etc)
2677 clutter_actor_apply_transform_to_point (ClutterActor *self,
2678 const ClutterVertex *point,
2679 ClutterVertex *vertex)
2681 g_return_if_fail (point != NULL);
2682 g_return_if_fail (vertex != NULL);
2683 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2687 * _clutter_actor_get_relative_transformation_matrix:
2688 * @self: The actor whose coordinate space you want to transform from.
2689 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2690 * or %NULL if you want to transform all the way to eye coordinates.
2691 * @matrix: A #CoglMatrix to store the transformation
2693 * This gets a transformation @matrix that will transform coordinates from the
2694 * coordinate space of @self into the coordinate space of @ancestor.
2696 * For example if you need a matrix that can transform the local actor
2697 * coordinates of @self into stage coordinates you would pass the actor's stage
2698 * pointer as the @ancestor.
2700 * If you pass %NULL then the transformation will take you all the way through
2701 * to eye coordinates. This can be useful if you want to extract the entire
2702 * modelview transform that Clutter applies before applying the projection
2703 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2704 * using cogl_set_modelview_matrix() for example then you would want a matrix
2705 * that transforms into eye coordinates.
2707 * <note><para>This function explicitly initializes the given @matrix. If you just
2708 * want clutter to multiply a relative transformation with an existing matrix
2709 * you can use clutter_actor_apply_relative_transformation_matrix()
2710 * instead.</para></note>
2713 /* XXX: We should consider caching the stage relative modelview along with
2714 * the actor itself */
2716 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2717 ClutterActor *ancestor,
2720 cogl_matrix_init_identity (matrix);
2722 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2725 /* Project the given @box into stage window coordinates, writing the
2726 * transformed vertices to @verts[]. */
2728 _clutter_actor_transform_and_project_box (ClutterActor *self,
2729 const ClutterActorBox *box,
2730 ClutterVertex verts[])
2732 ClutterVertex box_vertices[4];
2734 box_vertices[0].x = box->x1;
2735 box_vertices[0].y = box->y1;
2736 box_vertices[0].z = 0;
2737 box_vertices[1].x = box->x2;
2738 box_vertices[1].y = box->y1;
2739 box_vertices[1].z = 0;
2740 box_vertices[2].x = box->x1;
2741 box_vertices[2].y = box->y2;
2742 box_vertices[2].z = 0;
2743 box_vertices[3].x = box->x2;
2744 box_vertices[3].y = box->y2;
2745 box_vertices[3].z = 0;
2748 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2752 * clutter_actor_get_allocation_vertices:
2753 * @self: A #ClutterActor
2754 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2755 * against, or %NULL to use the #ClutterStage
2756 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2757 * location for an array of 4 #ClutterVertex in which to store the result
2759 * Calculates the transformed coordinates of the four corners of the
2760 * actor in the plane of @ancestor. The returned vertices relate to
2761 * the #ClutterActorBox coordinates as follows:
2763 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2764 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2765 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2766 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2769 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2770 * this case, the coordinates returned will be the coordinates on
2771 * the stage before the projection is applied. This is different from
2772 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2777 clutter_actor_get_allocation_vertices (ClutterActor *self,
2778 ClutterActor *ancestor,
2779 ClutterVertex verts[])
2781 ClutterActorPrivate *priv;
2782 ClutterActorBox box;
2783 ClutterVertex vertices[4];
2784 CoglMatrix modelview;
2786 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2787 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2789 if (ancestor == NULL)
2790 ancestor = _clutter_actor_get_stage_internal (self);
2792 /* Fallback to a NOP transform if the actor isn't parented under a
2794 if (ancestor == NULL)
2799 /* if the actor needs to be allocated we force a relayout, so that
2800 * we will have valid values to use in the transformations */
2801 if (priv->needs_allocation)
2803 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2805 _clutter_stage_maybe_relayout (stage);
2808 box.x1 = box.y1 = 0;
2809 /* The result isn't really meaningful in this case but at
2810 * least try to do something *vaguely* reasonable... */
2811 clutter_actor_get_size (self, &box.x2, &box.y2);
2815 clutter_actor_get_allocation_box (self, &box);
2817 vertices[0].x = box.x1;
2818 vertices[0].y = box.y1;
2820 vertices[1].x = box.x2;
2821 vertices[1].y = box.y1;
2823 vertices[2].x = box.x1;
2824 vertices[2].y = box.y2;
2826 vertices[3].x = box.x2;
2827 vertices[3].y = box.y2;
2830 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2833 cogl_matrix_transform_points (&modelview,
2835 sizeof (ClutterVertex),
2837 sizeof (ClutterVertex),
2843 * clutter_actor_get_abs_allocation_vertices:
2844 * @self: A #ClutterActor
2845 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2846 * of 4 #ClutterVertex where to store the result.
2848 * Calculates the transformed screen coordinates of the four corners of
2849 * the actor; the returned vertices relate to the #ClutterActorBox
2850 * coordinates as follows:
2852 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2853 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2854 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2855 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2861 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2862 ClutterVertex verts[])
2864 ClutterActorPrivate *priv;
2865 ClutterActorBox actor_space_allocation;
2867 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2871 /* if the actor needs to be allocated we force a relayout, so that
2872 * the actor allocation box will be valid for
2873 * _clutter_actor_transform_and_project_box()
2875 if (priv->needs_allocation)
2877 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2878 /* There's nothing meaningful we can do now */
2882 _clutter_stage_maybe_relayout (stage);
2885 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2886 * own coordinate space... */
2887 actor_space_allocation.x1 = 0;
2888 actor_space_allocation.y1 = 0;
2889 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2890 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2891 _clutter_actor_transform_and_project_box (self,
2892 &actor_space_allocation,
2897 clutter_actor_real_apply_transform (ClutterActor *self,
2900 ClutterActorPrivate *priv = self->priv;
2902 if (!priv->transform_valid)
2904 CoglMatrix *transform = &priv->transform;
2905 const ClutterTransformInfo *info;
2907 info = _clutter_actor_get_transform_info_or_defaults (self);
2909 cogl_matrix_init_identity (transform);
2911 cogl_matrix_translate (transform,
2912 priv->allocation.x1,
2913 priv->allocation.y1,
2917 cogl_matrix_translate (transform, 0, 0, info->depth);
2920 * because the rotation involves translations, we must scale
2921 * before applying the rotations (if we apply the scale after
2922 * the rotations, the translations included in the rotation are
2923 * not scaled and so the entire object will move on the screen
2924 * as a result of rotating it).
2926 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2928 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2929 &info->scale_center,
2930 cogl_matrix_scale (transform,
2937 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2939 cogl_matrix_rotate (transform,
2944 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2946 cogl_matrix_rotate (transform,
2951 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2953 cogl_matrix_rotate (transform,
2957 if (!clutter_anchor_coord_is_zero (&info->anchor))
2961 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2962 cogl_matrix_translate (transform, -x, -y, -z);
2965 priv->transform_valid = TRUE;
2968 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2971 /* Applies the transforms associated with this actor to the given
2974 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2977 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2981 * clutter_actor_apply_relative_transformation_matrix:
2982 * @self: The actor whose coordinate space you want to transform from.
2983 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2984 * or %NULL if you want to transform all the way to eye coordinates.
2985 * @matrix: A #CoglMatrix to apply the transformation too.
2987 * This multiplies a transform with @matrix that will transform coordinates
2988 * from the coordinate space of @self into the coordinate space of @ancestor.
2990 * For example if you need a matrix that can transform the local actor
2991 * coordinates of @self into stage coordinates you would pass the actor's stage
2992 * pointer as the @ancestor.
2994 * If you pass %NULL then the transformation will take you all the way through
2995 * to eye coordinates. This can be useful if you want to extract the entire
2996 * modelview transform that Clutter applies before applying the projection
2997 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2998 * using cogl_set_modelview_matrix() for example then you would want a matrix
2999 * that transforms into eye coordinates.
3001 * <note>This function doesn't initialize the given @matrix, it simply
3002 * multiplies the requested transformation matrix with the existing contents of
3003 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
3004 * before calling this function, or you can use
3005 * clutter_actor_get_relative_transformation_matrix() instead.</note>
3008 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
3009 ClutterActor *ancestor,
3012 ClutterActor *parent;
3014 /* Note we terminate before ever calling stage->apply_transform()
3015 * since that would conceptually be relative to the underlying
3016 * window OpenGL coordinates so we'd need a special @ancestor
3017 * value to represent the fake parent of the stage. */
3018 if (self == ancestor)
3021 parent = clutter_actor_get_parent (self);
3024 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
3027 _clutter_actor_apply_modelview_transform (self, matrix);
3031 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
3032 ClutterPaintVolume *pv,
3034 const CoglColor *color)
3036 static CoglPipeline *outline = NULL;
3037 CoglPrimitive *prim;
3038 ClutterVertex line_ends[12 * 2];
3041 clutter_backend_get_cogl_context (clutter_get_default_backend ());
3042 /* XXX: at some point we'll query this from the stage but we can't
3043 * do that until the osx backend uses Cogl natively. */
3044 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
3046 if (outline == NULL)
3047 outline = cogl_pipeline_new (ctx);
3049 _clutter_paint_volume_complete (pv);
3051 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3054 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3055 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3056 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3057 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3062 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3063 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3064 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3065 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3067 /* Lines connecting front face to back face */
3068 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3069 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3070 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3071 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3074 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3076 (CoglVertexP3 *)line_ends);
3078 cogl_pipeline_set_color (outline, color);
3079 cogl_framebuffer_draw_primitive (fb, outline, prim);
3080 cogl_object_unref (prim);
3084 PangoLayout *layout;
3085 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3086 pango_layout_set_text (layout, label, -1);
3087 cogl_pango_render_layout (layout,
3092 g_object_unref (layout);
3097 _clutter_actor_draw_paint_volume (ClutterActor *self)
3099 ClutterPaintVolume *pv;
3102 pv = _clutter_actor_get_paint_volume_mutable (self);
3105 gfloat width, height;
3106 ClutterPaintVolume fake_pv;
3108 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3109 _clutter_paint_volume_init_static (&fake_pv, stage);
3111 clutter_actor_get_size (self, &width, &height);
3112 clutter_paint_volume_set_width (&fake_pv, width);
3113 clutter_paint_volume_set_height (&fake_pv, height);
3115 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3116 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3117 _clutter_actor_get_debug_name (self),
3120 clutter_paint_volume_free (&fake_pv);
3124 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3125 _clutter_actor_draw_paint_volume_full (self, pv,
3126 _clutter_actor_get_debug_name (self),
3132 _clutter_actor_paint_cull_result (ClutterActor *self,
3134 ClutterCullResult result)
3136 ClutterPaintVolume *pv;
3141 if (result == CLUTTER_CULL_RESULT_IN)
3142 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3143 else if (result == CLUTTER_CULL_RESULT_OUT)
3144 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3146 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3149 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3151 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3152 _clutter_actor_draw_paint_volume_full (self, pv,
3153 _clutter_actor_get_debug_name (self),
3157 PangoLayout *layout;
3159 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3160 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3161 cogl_set_source_color (&color);
3163 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3164 pango_layout_set_text (layout, label, -1);
3165 cogl_pango_render_layout (layout,
3171 g_object_unref (layout);
3175 static int clone_paint_level = 0;
3178 _clutter_actor_push_clone_paint (void)
3180 clone_paint_level++;
3184 _clutter_actor_pop_clone_paint (void)
3186 clone_paint_level--;
3190 in_clone_paint (void)
3192 return clone_paint_level > 0;
3195 /* Returns TRUE if the actor can be ignored */
3196 /* FIXME: we should return a ClutterCullResult, and
3197 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3198 * means there's no point in trying to cull descendants of the current
3201 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3203 ClutterActorPrivate *priv = self->priv;
3204 ClutterActor *stage;
3205 const ClutterPlane *stage_clip;
3207 if (!priv->last_paint_volume_valid)
3209 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3210 "->last_paint_volume_valid == FALSE",
3211 _clutter_actor_get_debug_name (self));
3215 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3218 stage = _clutter_actor_get_stage_internal (self);
3219 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3220 if (G_UNLIKELY (!stage_clip))
3222 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3223 "No stage clip set",
3224 _clutter_actor_get_debug_name (self));
3228 if (cogl_get_draw_framebuffer () !=
3229 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3231 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3232 "Current framebuffer doesn't correspond to stage",
3233 _clutter_actor_get_debug_name (self));
3238 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3243 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3245 ClutterActorPrivate *priv = self->priv;
3246 const ClutterPaintVolume *pv;
3248 if (priv->last_paint_volume_valid)
3250 clutter_paint_volume_free (&priv->last_paint_volume);
3251 priv->last_paint_volume_valid = FALSE;
3254 pv = clutter_actor_get_paint_volume (self);
3257 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3258 "Actor failed to report a paint volume",
3259 _clutter_actor_get_debug_name (self));
3263 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3265 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3266 NULL); /* eye coordinates */
3268 priv->last_paint_volume_valid = TRUE;
3271 static inline gboolean
3272 actor_has_shader_data (ClutterActor *self)
3274 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3278 _clutter_actor_get_pick_id (ClutterActor *self)
3280 if (self->priv->pick_id < 0)
3283 return self->priv->pick_id;
3286 /* This is the same as clutter_actor_add_effect except that it doesn't
3287 queue a redraw and it doesn't notify on the effect property */
3289 _clutter_actor_add_effect_internal (ClutterActor *self,
3290 ClutterEffect *effect)
3292 ClutterActorPrivate *priv = self->priv;
3294 if (priv->effects == NULL)
3296 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3297 priv->effects->actor = self;
3300 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3303 /* This is the same as clutter_actor_remove_effect except that it doesn't
3304 queue a redraw and it doesn't notify on the effect property */
3306 _clutter_actor_remove_effect_internal (ClutterActor *self,
3307 ClutterEffect *effect)
3309 ClutterActorPrivate *priv = self->priv;
3311 if (priv->effects == NULL)
3314 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3316 if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3317 g_clear_object (&priv->effects);
3321 needs_flatten_effect (ClutterActor *self)
3323 ClutterActorPrivate *priv = self->priv;
3325 if (G_UNLIKELY (clutter_paint_debug_flags &
3326 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3329 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3331 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3333 if (clutter_actor_get_paint_opacity (self) < 255 &&
3334 clutter_actor_has_overlaps (self))
3342 add_or_remove_flatten_effect (ClutterActor *self)
3344 ClutterActorPrivate *priv = self->priv;
3346 /* Add or remove the flatten effect depending on the
3347 offscreen-redirect property. */
3348 if (needs_flatten_effect (self))
3350 if (priv->flatten_effect == NULL)
3352 ClutterActorMeta *actor_meta;
3355 priv->flatten_effect = _clutter_flatten_effect_new ();
3356 /* Keep a reference to the effect so that we can queue
3358 g_object_ref_sink (priv->flatten_effect);
3360 /* Set the priority of the effect to high so that it will
3361 always be applied to the actor first. It uses an internal
3362 priority so that it won't be visible to applications */
3363 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3364 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3365 _clutter_actor_meta_set_priority (actor_meta, priority);
3367 /* This will add the effect without queueing a redraw */
3368 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3373 if (priv->flatten_effect != NULL)
3375 /* Destroy the effect so that it will lose its fbo cache of
3377 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3378 g_clear_object (&priv->flatten_effect);
3384 clutter_actor_real_paint (ClutterActor *actor)
3386 ClutterActorPrivate *priv = actor->priv;
3389 for (iter = priv->first_child;
3391 iter = iter->priv->next_sibling)
3393 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3394 _clutter_actor_get_debug_name (iter),
3395 _clutter_actor_get_debug_name (actor),
3396 iter->priv->allocation.x1,
3397 iter->priv->allocation.y1,
3398 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3399 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3401 clutter_actor_paint (iter);
3406 clutter_actor_paint_node (ClutterActor *actor,
3407 ClutterPaintNode *root)
3409 ClutterActorPrivate *priv = actor->priv;
3414 if (priv->bg_color_set &&
3415 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3417 ClutterPaintNode *node;
3418 ClutterColor bg_color;
3419 ClutterActorBox box;
3423 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3424 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3426 bg_color = priv->bg_color;
3427 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3428 * priv->bg_color.alpha
3431 node = clutter_color_node_new (&bg_color);
3432 clutter_paint_node_set_name (node, "backgroundColor");
3433 clutter_paint_node_add_rectangle (node, &box);
3434 clutter_paint_node_add_child (root, node);
3435 clutter_paint_node_unref (node);
3438 if (priv->content != NULL)
3439 _clutter_content_paint_content (priv->content, actor, root);
3441 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3442 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3444 if (clutter_paint_node_get_n_children (root) == 0)
3447 #ifdef CLUTTER_ENABLE_DEBUG
3448 if (CLUTTER_HAS_DEBUG (PAINT))
3450 /* dump the tree only if we have one */
3451 _clutter_paint_node_dump_tree (root);
3453 #endif /* CLUTTER_ENABLE_DEBUG */
3455 _clutter_paint_node_paint (root);
3458 /* XXX: Uncomment this when we disable emitting the paint signal */
3459 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3466 * clutter_actor_paint:
3467 * @self: A #ClutterActor
3469 * Renders the actor to display.
3471 * This function should not be called directly by applications.
3472 * Call clutter_actor_queue_redraw() to queue paints, instead.
3474 * This function is context-aware, and will either cause a
3475 * regular paint or a pick paint.
3477 * This function will emit the #ClutterActor::paint signal or
3478 * the #ClutterActor::pick signal, depending on the context.
3480 * This function does not paint the actor if the actor is set to 0,
3481 * unless it is performing a pick paint.
3484 clutter_actor_paint (ClutterActor *self)
3486 ClutterActorPrivate *priv;
3487 ClutterPickMode pick_mode;
3488 gboolean clip_set = FALSE;
3489 gboolean shader_applied = FALSE;
3491 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3492 "Actor real-paint counter",
3493 "Increments each time any actor is painted",
3494 0 /* no application private data */);
3495 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3496 "Actor pick-paint counter",
3497 "Increments each time any actor is painted "
3499 0 /* no application private data */);
3501 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3503 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3508 pick_mode = _clutter_context_get_pick_mode ();
3510 if (pick_mode == CLUTTER_PICK_NONE)
3511 priv->propagated_one_redraw = FALSE;
3513 /* It's an important optimization that we consider painting of
3514 * actors with 0 opacity to be a NOP... */
3515 if (pick_mode == CLUTTER_PICK_NONE &&
3516 /* ignore top-levels, since they might be transparent */
3517 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3518 /* Use the override opacity if its been set */
3519 ((priv->opacity_override >= 0) ?
3520 priv->opacity_override : priv->opacity) == 0)
3523 /* if we aren't paintable (not in a toplevel with all
3524 * parents paintable) then do nothing.
3526 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3529 /* mark that we are in the paint process */
3530 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3534 if (priv->enable_model_view_transform)
3538 /* XXX: It could be better to cache the modelview with the actor
3539 * instead of progressively building up the transformations on
3540 * the matrix stack every time we paint. */
3541 cogl_get_modelview_matrix (&matrix);
3542 _clutter_actor_apply_modelview_transform (self, &matrix);
3544 #ifdef CLUTTER_ENABLE_DEBUG
3545 /* Catch when out-of-band transforms have been made by actors not as part
3546 * of an apply_transform vfunc... */
3547 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3549 CoglMatrix expected_matrix;
3551 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3554 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3556 GString *buf = g_string_sized_new (1024);
3557 ClutterActor *parent;
3560 while (parent != NULL)
3562 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3564 if (parent->priv->parent != NULL)
3565 g_string_append (buf, "->");
3567 parent = parent->priv->parent;
3570 g_warning ("Unexpected transform found when painting actor "
3571 "\"%s\". This will be caused by one of the actor's "
3572 "ancestors (%s) using the Cogl API directly to transform "
3573 "children instead of using ::apply_transform().",
3574 _clutter_actor_get_debug_name (self),
3577 g_string_free (buf, TRUE);
3580 #endif /* CLUTTER_ENABLE_DEBUG */
3582 cogl_set_modelview_matrix (&matrix);
3587 cogl_clip_push_rectangle (priv->clip.x,
3589 priv->clip.x + priv->clip.width,
3590 priv->clip.y + priv->clip.height);
3593 else if (priv->clip_to_allocation)
3595 gfloat width, height;
3597 width = priv->allocation.x2 - priv->allocation.x1;
3598 height = priv->allocation.y2 - priv->allocation.y1;
3600 cogl_clip_push_rectangle (0, 0, width, height);
3604 if (pick_mode == CLUTTER_PICK_NONE)
3606 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3608 /* We check whether we need to add the flatten effect before
3609 each paint so that we can avoid having a mechanism for
3610 applications to notify when the value of the
3611 has_overlaps virtual changes. */
3612 add_or_remove_flatten_effect (self);
3615 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3617 /* We save the current paint volume so that the next time the
3618 * actor queues a redraw we can constrain the redraw to just
3619 * cover the union of the new bounding box and the old.
3621 * We also fetch the current paint volume to perform culling so
3622 * we can avoid painting actors outside the current clip region.
3624 * If we are painting inside a clone, we should neither update
3625 * the paint volume or use it to cull painting, since the paint
3626 * box represents the location of the source actor on the
3629 * XXX: We are starting to do a lot of vertex transforms on
3630 * the CPU in a typical paint, so at some point we should
3631 * audit these and consider caching some things.
3633 * NB: We don't perform culling while picking at this point because
3634 * clutter-stage.c doesn't setup the clipping planes appropriately.
3636 * NB: We don't want to update the last-paint-volume during picking
3637 * because the last-paint-volume is used to determine the old screen
3638 * space location of an actor that has moved so we can know the
3639 * minimal region to redraw to clear an old view of the actor. If we
3640 * update this during picking then by the time we come around to
3641 * paint then the last-paint-volume would likely represent the new
3642 * actor position not the old.
3644 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3647 /* annoyingly gcc warns if uninitialized even though
3648 * the initialization is redundant :-( */
3649 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3651 if (G_LIKELY ((clutter_paint_debug_flags &
3652 (CLUTTER_DEBUG_DISABLE_CULLING |
3653 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3654 (CLUTTER_DEBUG_DISABLE_CULLING |
3655 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3656 _clutter_actor_update_last_paint_volume (self);
3658 success = cull_actor (self, &result);
3660 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3661 _clutter_actor_paint_cull_result (self, success, result);
3662 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3666 if (priv->effects == NULL)
3668 if (pick_mode == CLUTTER_PICK_NONE &&
3669 actor_has_shader_data (self))
3671 _clutter_actor_shader_pre_paint (self, FALSE);
3672 shader_applied = TRUE;
3675 priv->next_effect_to_paint = NULL;
3678 priv->next_effect_to_paint =
3679 _clutter_meta_group_peek_metas (priv->effects);
3681 clutter_actor_continue_paint (self);
3684 _clutter_actor_shader_post_paint (self);
3686 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3687 pick_mode == CLUTTER_PICK_NONE))
3688 _clutter_actor_draw_paint_volume (self);
3691 /* If we make it here then the actor has run through a complete
3692 paint run including all the effects so it's no longer dirty */
3693 if (pick_mode == CLUTTER_PICK_NONE)
3694 priv->is_dirty = FALSE;
3701 /* paint sequence complete */
3702 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3706 * clutter_actor_continue_paint:
3707 * @self: A #ClutterActor
3709 * Run the next stage of the paint sequence. This function should only
3710 * be called within the implementation of the ‘run’ virtual of a
3711 * #ClutterEffect. It will cause the run method of the next effect to
3712 * be applied, or it will paint the actual actor if the current effect
3713 * is the last effect in the chain.
3718 clutter_actor_continue_paint (ClutterActor *self)
3720 ClutterActorPrivate *priv;
3722 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3723 /* This should only be called from with in the ‘run’ implementation
3724 of a ClutterEffect */
3725 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3729 /* Skip any effects that are disabled */
3730 while (priv->next_effect_to_paint &&
3731 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3732 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3734 /* If this has come from the last effect then we'll just paint the
3736 if (priv->next_effect_to_paint == NULL)
3738 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3740 ClutterPaintNode *dummy;
3742 /* XXX - this will go away in 2.0, when we can get rid of this
3743 * stuff and switch to a pure retained render tree of PaintNodes
3744 * for the entire frame, starting from the Stage; the paint()
3745 * virtual function can then be called directly.
3747 dummy = _clutter_dummy_node_new (self);
3748 clutter_paint_node_set_name (dummy, "Root");
3750 /* XXX - for 1.12, we use the return value of paint_node() to
3751 * decide whether we should emit the ::paint signal.
3753 clutter_actor_paint_node (self, dummy);
3754 clutter_paint_node_unref (dummy);
3756 g_signal_emit (self, actor_signals[PAINT], 0);
3760 ClutterColor col = { 0, };
3762 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3764 /* Actor will then paint silhouette of itself in supplied
3765 * color. See clutter_stage_get_actor_at_pos() for where
3766 * picking is enabled.
3768 g_signal_emit (self, actor_signals[PICK], 0, &col);
3773 ClutterEffect *old_current_effect;
3774 ClutterEffectPaintFlags run_flags = 0;
3776 /* Cache the current effect so that we can put it back before
3778 old_current_effect = priv->current_effect;
3780 priv->current_effect = priv->next_effect_to_paint->data;
3781 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3783 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3787 /* If there's an effect queued with this redraw then all
3788 effects up to that one will be considered dirty. It
3789 is expected the queued effect will paint the cached
3790 image and not call clutter_actor_continue_paint again
3791 (although it should work ok if it does) */
3792 if (priv->effect_to_redraw == NULL ||
3793 priv->current_effect != priv->effect_to_redraw)
3794 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3797 _clutter_effect_paint (priv->current_effect, run_flags);
3801 /* We can't determine when an actor has been modified since
3802 its last pick so lets just assume it has always been
3804 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3806 _clutter_effect_pick (priv->current_effect, run_flags);
3809 priv->current_effect = old_current_effect;
3814 _clutter_actor_stop_transitions (ClutterActor *self)
3816 const ClutterAnimationInfo *info;
3817 GHashTableIter iter;
3820 info = _clutter_actor_get_animation_info_or_defaults (self);
3821 if (info->transitions == NULL)
3824 g_hash_table_iter_init (&iter, info->transitions);
3825 while (g_hash_table_iter_next (&iter, NULL, &value))
3827 TransitionClosure *closure = value;
3828 clutter_timeline_stop (CLUTTER_TIMELINE (closure->transition));
3832 static ClutterActorTraverseVisitFlags
3833 invalidate_queue_redraw_entry (ClutterActor *self,
3837 ClutterActorPrivate *priv = self->priv;
3839 if (priv->queue_redraw_entry != NULL)
3841 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3842 priv->queue_redraw_entry = NULL;
3845 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3849 remove_child (ClutterActor *self,
3850 ClutterActor *child)
3852 ClutterActor *prev_sibling, *next_sibling;
3854 prev_sibling = child->priv->prev_sibling;
3855 next_sibling = child->priv->next_sibling;
3857 if (prev_sibling != NULL)
3858 prev_sibling->priv->next_sibling = next_sibling;
3860 if (next_sibling != NULL)
3861 next_sibling->priv->prev_sibling = prev_sibling;
3863 if (self->priv->first_child == child)
3864 self->priv->first_child = next_sibling;
3866 if (self->priv->last_child == child)
3867 self->priv->last_child = prev_sibling;
3869 child->priv->parent = NULL;
3870 child->priv->prev_sibling = NULL;
3871 child->priv->next_sibling = NULL;
3875 REMOVE_CHILD_DESTROY_META = 1 << 0,
3876 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3877 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3878 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3879 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3880 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3881 REMOVE_CHILD_STOP_TRANSITIONS = 1 << 6,
3883 /* default flags for public API */
3884 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_STOP_TRANSITIONS |
3885 REMOVE_CHILD_DESTROY_META |
3886 REMOVE_CHILD_EMIT_PARENT_SET |
3887 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3888 REMOVE_CHILD_CHECK_STATE |
3889 REMOVE_CHILD_FLUSH_QUEUE |
3890 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3892 /* flags for legacy/deprecated API */
3893 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_STOP_TRANSITIONS |
3894 REMOVE_CHILD_CHECK_STATE |
3895 REMOVE_CHILD_FLUSH_QUEUE |
3896 REMOVE_CHILD_EMIT_PARENT_SET |
3897 REMOVE_CHILD_NOTIFY_FIRST_LAST
3898 } ClutterActorRemoveChildFlags;
3901 * clutter_actor_remove_child_internal:
3902 * @self: a #ClutterActor
3903 * @child: the child of @self that has to be removed
3904 * @flags: control the removal operations
3906 * Removes @child from the list of children of @self.
3909 clutter_actor_remove_child_internal (ClutterActor *self,
3910 ClutterActor *child,
3911 ClutterActorRemoveChildFlags flags)
3913 ClutterActor *old_first, *old_last;
3914 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3915 gboolean flush_queue;
3916 gboolean notify_first_last;
3917 gboolean was_mapped;
3918 gboolean stop_transitions;
3920 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3921 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3922 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3923 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3924 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3925 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3926 stop_transitions = (flags & REMOVE_CHILD_STOP_TRANSITIONS) != 0;
3928 g_object_freeze_notify (G_OBJECT (self));
3930 if (stop_transitions)
3931 _clutter_actor_stop_transitions (child);
3934 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3938 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3940 /* we need to unrealize *before* we set parent_actor to NULL,
3941 * because in an unrealize method actors are dissociating from the
3942 * stage, which means they need to be able to
3943 * clutter_actor_get_stage().
3945 * yhis should unmap and unrealize, unless we're reparenting.
3947 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3954 /* We take this opportunity to invalidate any queue redraw entry
3955 * associated with the actor and descendants since we won't be able to
3956 * determine the appropriate stage after this.
3958 * we do this after we updated the mapped state because actors might
3959 * end up queueing redraws inside their mapped/unmapped virtual
3960 * functions, and if we invalidate the redraw entry we could end up
3961 * with an inconsistent state and weird memory corruption. see
3964 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3965 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3967 _clutter_actor_traverse (child,
3969 invalidate_queue_redraw_entry,
3974 old_first = self->priv->first_child;
3975 old_last = self->priv->last_child;
3977 remove_child (self, child);
3979 self->priv->n_children -= 1;
3981 self->priv->age += 1;
3983 /* if the child that got removed was visible and set to
3984 * expand then we want to reset the parent's state in
3985 * case the child was the only thing that was making it
3988 if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
3989 (child->priv->needs_compute_expand ||
3990 child->priv->needs_x_expand ||
3991 child->priv->needs_y_expand))
3993 clutter_actor_queue_compute_expand (self);
3996 /* clutter_actor_reparent() will emit ::parent-set for us */
3997 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3998 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
4000 /* if the child was mapped then we need to relayout ourselves to account
4001 * for the removed child
4004 clutter_actor_queue_relayout (self);
4006 /* we need to emit the signal before dropping the reference */
4007 if (emit_actor_removed)
4008 g_signal_emit_by_name (self, "actor-removed", child);
4010 if (notify_first_last)
4012 if (old_first != self->priv->first_child)
4013 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
4015 if (old_last != self->priv->last_child)
4016 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
4019 g_object_thaw_notify (G_OBJECT (self));
4021 /* remove the reference we acquired in clutter_actor_add_child() */
4022 g_object_unref (child);
4025 static const ClutterTransformInfo default_transform_info = {
4026 0.0, { 0, }, /* rotation-x */
4027 0.0, { 0, }, /* rotation-y */
4028 0.0, { 0, }, /* rotation-z */
4030 1.0, 1.0, { 0, }, /* scale */
4032 { 0, }, /* anchor */
4038 * _clutter_actor_get_transform_info_or_defaults:
4039 * @self: a #ClutterActor
4041 * Retrieves the ClutterTransformInfo structure associated to an actor.
4043 * If the actor does not have a ClutterTransformInfo structure associated
4044 * to it, then the default structure will be returned.
4046 * This function should only be used for getters.
4048 * Return value: a const pointer to the ClutterTransformInfo structure
4050 const ClutterTransformInfo *
4051 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
4053 ClutterTransformInfo *info;
4055 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4059 return &default_transform_info;
4063 clutter_transform_info_free (gpointer data)
4066 g_slice_free (ClutterTransformInfo, data);
4070 * _clutter_actor_get_transform_info:
4071 * @self: a #ClutterActor
4073 * Retrieves a pointer to the ClutterTransformInfo structure.
4075 * If the actor does not have a ClutterTransformInfo associated to it, one
4076 * will be created and initialized to the default values.
4078 * This function should be used for setters.
4080 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
4083 * Return value: (transfer none): a pointer to the ClutterTransformInfo
4086 ClutterTransformInfo *
4087 _clutter_actor_get_transform_info (ClutterActor *self)
4089 ClutterTransformInfo *info;
4091 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4094 info = g_slice_new (ClutterTransformInfo);
4096 *info = default_transform_info;
4098 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4100 clutter_transform_info_free);
4107 * clutter_actor_set_rotation_angle_internal:
4108 * @self: a #ClutterActor
4109 * @axis: the axis of the angle to change
4110 * @angle: the angle of rotation
4112 * Sets the rotation angle on the given axis without affecting the
4113 * rotation center point.
4116 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
4117 ClutterRotateAxis axis,
4120 GObject *obj = G_OBJECT (self);
4121 ClutterTransformInfo *info;
4123 info = _clutter_actor_get_transform_info (self);
4125 g_object_freeze_notify (obj);
4129 case CLUTTER_X_AXIS:
4130 info->rx_angle = angle;
4131 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4134 case CLUTTER_Y_AXIS:
4135 info->ry_angle = angle;
4136 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4139 case CLUTTER_Z_AXIS:
4140 info->rz_angle = angle;
4141 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4145 self->priv->transform_valid = FALSE;
4147 g_object_thaw_notify (obj);
4149 clutter_actor_queue_redraw (self);
4153 clutter_actor_set_rotation_angle (ClutterActor *self,
4154 ClutterRotateAxis axis,
4157 const ClutterTransformInfo *info;
4158 const double *cur_angle_p = NULL;
4159 GParamSpec *pspec = NULL;
4161 info = _clutter_actor_get_transform_info_or_defaults (self);
4165 case CLUTTER_X_AXIS:
4166 cur_angle_p = &info->rx_angle;
4167 pspec = obj_props[PROP_ROTATION_ANGLE_X];
4170 case CLUTTER_Y_AXIS:
4171 cur_angle_p = &info->ry_angle;
4172 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4175 case CLUTTER_Z_AXIS:
4176 cur_angle_p = &info->rz_angle;
4177 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4181 g_assert (pspec != NULL);
4182 g_assert (cur_angle_p != NULL);
4184 if (_clutter_actor_get_transition (self, pspec) == NULL)
4185 _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4187 _clutter_actor_update_transition (self, pspec, angle);
4189 clutter_actor_queue_redraw (self);
4193 * clutter_actor_set_rotation_center_internal:
4194 * @self: a #ClutterActor
4195 * @axis: the axis of the center to change
4196 * @center: the coordinates of the rotation center
4198 * Sets the rotation center on the given axis without affecting the
4202 clutter_actor_set_rotation_center_internal (ClutterActor *self,
4203 ClutterRotateAxis axis,
4204 const ClutterVertex *center)
4206 GObject *obj = G_OBJECT (self);
4207 ClutterTransformInfo *info;
4208 ClutterVertex v = { 0, 0, 0 };
4210 info = _clutter_actor_get_transform_info (self);
4215 g_object_freeze_notify (obj);
4219 case CLUTTER_X_AXIS:
4220 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4221 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4224 case CLUTTER_Y_AXIS:
4225 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4226 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4229 case CLUTTER_Z_AXIS:
4230 /* if the previously set rotation center was fractional, then
4231 * setting explicit coordinates will have to notify the
4232 * :rotation-center-z-gravity property as well
4234 if (info->rz_center.is_fractional)
4235 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4237 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4238 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4242 self->priv->transform_valid = FALSE;
4244 g_object_thaw_notify (obj);
4246 clutter_actor_queue_redraw (self);
4250 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4254 GObject *obj = G_OBJECT (self);
4255 ClutterTransformInfo *info;
4257 info = _clutter_actor_get_transform_info (self);
4259 if (pspec == obj_props[PROP_SCALE_X])
4260 info->scale_x = factor;
4262 info->scale_y = factor;
4264 self->priv->transform_valid = FALSE;
4265 clutter_actor_queue_redraw (self);
4266 g_object_notify_by_pspec (obj, pspec);
4270 clutter_actor_set_scale_factor (ClutterActor *self,
4271 ClutterRotateAxis axis,
4274 const ClutterTransformInfo *info;
4275 const double *scale_p = NULL;
4276 GParamSpec *pspec = NULL;
4278 info = _clutter_actor_get_transform_info_or_defaults (self);
4282 case CLUTTER_X_AXIS:
4283 pspec = obj_props[PROP_SCALE_X];
4284 scale_p = &info->scale_x;
4287 case CLUTTER_Y_AXIS:
4288 pspec = obj_props[PROP_SCALE_Y];
4289 scale_p = &info->scale_y;
4292 case CLUTTER_Z_AXIS:
4296 g_assert (pspec != NULL);
4297 g_assert (scale_p != NULL);
4299 if (_clutter_actor_get_transition (self, pspec) == NULL)
4300 _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4302 _clutter_actor_update_transition (self, pspec, factor);
4304 clutter_actor_queue_redraw (self);
4308 clutter_actor_set_scale_center (ClutterActor *self,
4309 ClutterRotateAxis axis,
4312 GObject *obj = G_OBJECT (self);
4313 ClutterTransformInfo *info;
4314 gfloat center_x, center_y;
4316 info = _clutter_actor_get_transform_info (self);
4318 g_object_freeze_notify (obj);
4320 /* get the current scale center coordinates */
4321 clutter_anchor_coord_get_units (self, &info->scale_center,
4326 /* we need to notify this too, because setting explicit coordinates will
4327 * change the gravity as a side effect
4329 if (info->scale_center.is_fractional)
4330 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4334 case CLUTTER_X_AXIS:
4335 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4336 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4339 case CLUTTER_Y_AXIS:
4340 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4341 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4345 g_assert_not_reached ();
4348 self->priv->transform_valid = FALSE;
4350 clutter_actor_queue_redraw (self);
4352 g_object_thaw_notify (obj);
4356 clutter_actor_set_scale_gravity (ClutterActor *self,
4357 ClutterGravity gravity)
4359 ClutterTransformInfo *info;
4362 info = _clutter_actor_get_transform_info (self);
4363 obj = G_OBJECT (self);
4365 if (gravity == CLUTTER_GRAVITY_NONE)
4366 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4368 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4370 self->priv->transform_valid = FALSE;
4372 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4373 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4374 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4376 clutter_actor_queue_redraw (self);
4380 clutter_actor_set_anchor_coord (ClutterActor *self,
4381 ClutterRotateAxis axis,
4384 GObject *obj = G_OBJECT (self);
4385 ClutterTransformInfo *info;
4386 gfloat anchor_x, anchor_y;
4388 info = _clutter_actor_get_transform_info (self);
4390 g_object_freeze_notify (obj);
4392 clutter_anchor_coord_get_units (self, &info->anchor,
4397 if (info->anchor.is_fractional)
4398 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4402 case CLUTTER_X_AXIS:
4403 clutter_anchor_coord_set_units (&info->anchor,
4407 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4410 case CLUTTER_Y_AXIS:
4411 clutter_anchor_coord_set_units (&info->anchor,
4415 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4419 g_assert_not_reached ();
4422 self->priv->transform_valid = FALSE;
4424 clutter_actor_queue_redraw (self);
4426 g_object_thaw_notify (obj);
4430 clutter_actor_set_property (GObject *object,
4432 const GValue *value,
4435 ClutterActor *actor = CLUTTER_ACTOR (object);
4436 ClutterActorPrivate *priv = actor->priv;
4441 clutter_actor_set_x (actor, g_value_get_float (value));
4445 clutter_actor_set_y (actor, g_value_get_float (value));
4450 const ClutterPoint *pos = g_value_get_boxed (value);
4453 clutter_actor_set_position (actor, pos->x, pos->y);
4455 clutter_actor_set_fixed_position_set (actor, FALSE);
4460 clutter_actor_set_width (actor, g_value_get_float (value));
4464 clutter_actor_set_height (actor, g_value_get_float (value));
4469 const ClutterSize *size = g_value_get_boxed (value);
4472 clutter_actor_set_size (actor, size->width, size->height);
4474 clutter_actor_set_size (actor, -1, -1);
4479 clutter_actor_set_x (actor, g_value_get_float (value));
4483 clutter_actor_set_y (actor, g_value_get_float (value));
4486 case PROP_FIXED_POSITION_SET:
4487 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4490 case PROP_MIN_WIDTH:
4491 clutter_actor_set_min_width (actor, g_value_get_float (value));
4494 case PROP_MIN_HEIGHT:
4495 clutter_actor_set_min_height (actor, g_value_get_float (value));
4498 case PROP_NATURAL_WIDTH:
4499 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4502 case PROP_NATURAL_HEIGHT:
4503 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4506 case PROP_MIN_WIDTH_SET:
4507 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4510 case PROP_MIN_HEIGHT_SET:
4511 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4514 case PROP_NATURAL_WIDTH_SET:
4515 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4518 case PROP_NATURAL_HEIGHT_SET:
4519 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4522 case PROP_REQUEST_MODE:
4523 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4527 clutter_actor_set_depth (actor, g_value_get_float (value));
4531 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4534 case PROP_OFFSCREEN_REDIRECT:
4535 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4539 clutter_actor_set_name (actor, g_value_get_string (value));
4543 if (g_value_get_boolean (value) == TRUE)
4544 clutter_actor_show (actor);
4546 clutter_actor_hide (actor);
4550 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4551 g_value_get_double (value));
4555 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4556 g_value_get_double (value));
4559 case PROP_SCALE_CENTER_X:
4560 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4561 g_value_get_float (value));
4564 case PROP_SCALE_CENTER_Y:
4565 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4566 g_value_get_float (value));
4569 case PROP_SCALE_GRAVITY:
4570 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4575 const ClutterGeometry *geom = g_value_get_boxed (value);
4577 clutter_actor_set_clip (actor,
4579 geom->width, geom->height);
4583 case PROP_CLIP_TO_ALLOCATION:
4584 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4588 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4591 case PROP_ROTATION_ANGLE_X:
4592 clutter_actor_set_rotation_angle (actor,
4594 g_value_get_double (value));
4597 case PROP_ROTATION_ANGLE_Y:
4598 clutter_actor_set_rotation_angle (actor,
4600 g_value_get_double (value));
4603 case PROP_ROTATION_ANGLE_Z:
4604 clutter_actor_set_rotation_angle (actor,
4606 g_value_get_double (value));
4609 case PROP_ROTATION_CENTER_X:
4610 clutter_actor_set_rotation_center_internal (actor,
4612 g_value_get_boxed (value));
4615 case PROP_ROTATION_CENTER_Y:
4616 clutter_actor_set_rotation_center_internal (actor,
4618 g_value_get_boxed (value));
4621 case PROP_ROTATION_CENTER_Z:
4622 clutter_actor_set_rotation_center_internal (actor,
4624 g_value_get_boxed (value));
4627 case PROP_ROTATION_CENTER_Z_GRAVITY:
4629 const ClutterTransformInfo *info;
4631 info = _clutter_actor_get_transform_info_or_defaults (actor);
4632 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4633 g_value_get_enum (value));
4638 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4639 g_value_get_float (value));
4643 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4644 g_value_get_float (value));
4647 case PROP_ANCHOR_GRAVITY:
4648 clutter_actor_set_anchor_point_from_gravity (actor,
4649 g_value_get_enum (value));
4652 case PROP_SHOW_ON_SET_PARENT:
4653 priv->show_on_set_parent = g_value_get_boolean (value);
4656 case PROP_TEXT_DIRECTION:
4657 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4661 clutter_actor_add_action (actor, g_value_get_object (value));
4664 case PROP_CONSTRAINTS:
4665 clutter_actor_add_constraint (actor, g_value_get_object (value));
4669 clutter_actor_add_effect (actor, g_value_get_object (value));
4672 case PROP_LAYOUT_MANAGER:
4673 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4677 clutter_actor_set_x_expand (actor, g_value_get_boolean (value));
4681 clutter_actor_set_y_expand (actor, g_value_get_boolean (value));
4685 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4689 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4692 case PROP_MARGIN_TOP:
4693 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4696 case PROP_MARGIN_BOTTOM:
4697 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4700 case PROP_MARGIN_LEFT:
4701 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4704 case PROP_MARGIN_RIGHT:
4705 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4708 case PROP_BACKGROUND_COLOR:
4709 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4713 clutter_actor_set_content (actor, g_value_get_object (value));
4716 case PROP_CONTENT_GRAVITY:
4717 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4720 case PROP_MINIFICATION_FILTER:
4721 clutter_actor_set_content_scaling_filters (actor,
4722 g_value_get_enum (value),
4723 actor->priv->mag_filter);
4726 case PROP_MAGNIFICATION_FILTER:
4727 clutter_actor_set_content_scaling_filters (actor,
4728 actor->priv->min_filter,
4729 g_value_get_enum (value));
4733 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4739 clutter_actor_get_property (GObject *object,
4744 ClutterActor *actor = CLUTTER_ACTOR (object);
4745 ClutterActorPrivate *priv = actor->priv;
4750 g_value_set_float (value, clutter_actor_get_x (actor));
4754 g_value_set_float (value, clutter_actor_get_y (actor));
4759 ClutterPoint position;
4761 clutter_point_init (&position,
4762 clutter_actor_get_x (actor),
4763 clutter_actor_get_y (actor));
4764 g_value_set_boxed (value, &position);
4769 g_value_set_float (value, clutter_actor_get_width (actor));
4773 g_value_set_float (value, clutter_actor_get_height (actor));
4780 clutter_size_init (&size,
4781 clutter_actor_get_width (actor),
4782 clutter_actor_get_height (actor));
4783 g_value_set_boxed (value, &size);
4789 const ClutterLayoutInfo *info;
4791 info = _clutter_actor_get_layout_info_or_defaults (actor);
4792 g_value_set_float (value, info->fixed_pos.x);
4798 const ClutterLayoutInfo *info;
4800 info = _clutter_actor_get_layout_info_or_defaults (actor);
4801 g_value_set_float (value, info->fixed_pos.y);
4805 case PROP_FIXED_POSITION_SET:
4806 g_value_set_boolean (value, priv->position_set);
4809 case PROP_MIN_WIDTH:
4811 const ClutterLayoutInfo *info;
4813 info = _clutter_actor_get_layout_info_or_defaults (actor);
4814 g_value_set_float (value, info->minimum.width);
4818 case PROP_MIN_HEIGHT:
4820 const ClutterLayoutInfo *info;
4822 info = _clutter_actor_get_layout_info_or_defaults (actor);
4823 g_value_set_float (value, info->minimum.height);
4827 case PROP_NATURAL_WIDTH:
4829 const ClutterLayoutInfo *info;
4831 info = _clutter_actor_get_layout_info_or_defaults (actor);
4832 g_value_set_float (value, info->natural.width);
4836 case PROP_NATURAL_HEIGHT:
4838 const ClutterLayoutInfo *info;
4840 info = _clutter_actor_get_layout_info_or_defaults (actor);
4841 g_value_set_float (value, info->natural.height);
4845 case PROP_MIN_WIDTH_SET:
4846 g_value_set_boolean (value, priv->min_width_set);
4849 case PROP_MIN_HEIGHT_SET:
4850 g_value_set_boolean (value, priv->min_height_set);
4853 case PROP_NATURAL_WIDTH_SET:
4854 g_value_set_boolean (value, priv->natural_width_set);
4857 case PROP_NATURAL_HEIGHT_SET:
4858 g_value_set_boolean (value, priv->natural_height_set);
4861 case PROP_REQUEST_MODE:
4862 g_value_set_enum (value, priv->request_mode);
4865 case PROP_ALLOCATION:
4866 g_value_set_boxed (value, &priv->allocation);
4870 g_value_set_float (value, clutter_actor_get_depth (actor));
4874 g_value_set_uint (value, priv->opacity);
4877 case PROP_OFFSCREEN_REDIRECT:
4878 g_value_set_enum (value, priv->offscreen_redirect);
4882 g_value_set_string (value, priv->name);
4886 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4890 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4894 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4898 g_value_set_boolean (value, priv->has_clip);
4903 ClutterGeometry clip;
4905 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4906 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4907 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4908 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4910 g_value_set_boxed (value, &clip);
4914 case PROP_CLIP_TO_ALLOCATION:
4915 g_value_set_boolean (value, priv->clip_to_allocation);
4920 const ClutterTransformInfo *info;
4922 info = _clutter_actor_get_transform_info_or_defaults (actor);
4923 g_value_set_double (value, info->scale_x);
4929 const ClutterTransformInfo *info;
4931 info = _clutter_actor_get_transform_info_or_defaults (actor);
4932 g_value_set_double (value, info->scale_y);
4936 case PROP_SCALE_CENTER_X:
4940 clutter_actor_get_scale_center (actor, ¢er, NULL);
4942 g_value_set_float (value, center);
4946 case PROP_SCALE_CENTER_Y:
4950 clutter_actor_get_scale_center (actor, NULL, ¢er);
4952 g_value_set_float (value, center);
4956 case PROP_SCALE_GRAVITY:
4957 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4961 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4964 case PROP_ROTATION_ANGLE_X:
4966 const ClutterTransformInfo *info;
4968 info = _clutter_actor_get_transform_info_or_defaults (actor);
4969 g_value_set_double (value, info->rx_angle);
4973 case PROP_ROTATION_ANGLE_Y:
4975 const ClutterTransformInfo *info;
4977 info = _clutter_actor_get_transform_info_or_defaults (actor);
4978 g_value_set_double (value, info->ry_angle);
4982 case PROP_ROTATION_ANGLE_Z:
4984 const ClutterTransformInfo *info;
4986 info = _clutter_actor_get_transform_info_or_defaults (actor);
4987 g_value_set_double (value, info->rz_angle);
4991 case PROP_ROTATION_CENTER_X:
4993 ClutterVertex center;
4995 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
5000 g_value_set_boxed (value, ¢er);
5004 case PROP_ROTATION_CENTER_Y:
5006 ClutterVertex center;
5008 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
5013 g_value_set_boxed (value, ¢er);
5017 case PROP_ROTATION_CENTER_Z:
5019 ClutterVertex center;
5021 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
5026 g_value_set_boxed (value, ¢er);
5030 case PROP_ROTATION_CENTER_Z_GRAVITY:
5031 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
5036 const ClutterTransformInfo *info;
5039 info = _clutter_actor_get_transform_info_or_defaults (actor);
5040 clutter_anchor_coord_get_units (actor, &info->anchor,
5044 g_value_set_float (value, anchor_x);
5050 const ClutterTransformInfo *info;
5053 info = _clutter_actor_get_transform_info_or_defaults (actor);
5054 clutter_anchor_coord_get_units (actor, &info->anchor,
5058 g_value_set_float (value, anchor_y);
5062 case PROP_ANCHOR_GRAVITY:
5063 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
5066 case PROP_SHOW_ON_SET_PARENT:
5067 g_value_set_boolean (value, priv->show_on_set_parent);
5070 case PROP_TEXT_DIRECTION:
5071 g_value_set_enum (value, priv->text_direction);
5074 case PROP_HAS_POINTER:
5075 g_value_set_boolean (value, priv->has_pointer);
5078 case PROP_LAYOUT_MANAGER:
5079 g_value_set_object (value, priv->layout_manager);
5084 const ClutterLayoutInfo *info;
5086 info = _clutter_actor_get_layout_info_or_defaults (actor);
5087 g_value_set_boolean (value, info->x_expand);
5093 const ClutterLayoutInfo *info;
5095 info = _clutter_actor_get_layout_info_or_defaults (actor);
5096 g_value_set_boolean (value, info->y_expand);
5102 const ClutterLayoutInfo *info;
5104 info = _clutter_actor_get_layout_info_or_defaults (actor);
5105 g_value_set_enum (value, info->x_align);
5111 const ClutterLayoutInfo *info;
5113 info = _clutter_actor_get_layout_info_or_defaults (actor);
5114 g_value_set_enum (value, info->y_align);
5118 case PROP_MARGIN_TOP:
5120 const ClutterLayoutInfo *info;
5122 info = _clutter_actor_get_layout_info_or_defaults (actor);
5123 g_value_set_float (value, info->margin.top);
5127 case PROP_MARGIN_BOTTOM:
5129 const ClutterLayoutInfo *info;
5131 info = _clutter_actor_get_layout_info_or_defaults (actor);
5132 g_value_set_float (value, info->margin.bottom);
5136 case PROP_MARGIN_LEFT:
5138 const ClutterLayoutInfo *info;
5140 info = _clutter_actor_get_layout_info_or_defaults (actor);
5141 g_value_set_float (value, info->margin.left);
5145 case PROP_MARGIN_RIGHT:
5147 const ClutterLayoutInfo *info;
5149 info = _clutter_actor_get_layout_info_or_defaults (actor);
5150 g_value_set_float (value, info->margin.right);
5154 case PROP_BACKGROUND_COLOR_SET:
5155 g_value_set_boolean (value, priv->bg_color_set);
5158 case PROP_BACKGROUND_COLOR:
5159 g_value_set_boxed (value, &priv->bg_color);
5162 case PROP_FIRST_CHILD:
5163 g_value_set_object (value, priv->first_child);
5166 case PROP_LAST_CHILD:
5167 g_value_set_object (value, priv->last_child);
5171 g_value_set_object (value, priv->content);
5174 case PROP_CONTENT_GRAVITY:
5175 g_value_set_enum (value, priv->content_gravity);
5178 case PROP_CONTENT_BOX:
5180 ClutterActorBox box = { 0, };
5182 clutter_actor_get_content_box (actor, &box);
5183 g_value_set_boxed (value, &box);
5187 case PROP_MINIFICATION_FILTER:
5188 g_value_set_enum (value, priv->min_filter);
5191 case PROP_MAGNIFICATION_FILTER:
5192 g_value_set_enum (value, priv->mag_filter);
5196 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5202 clutter_actor_dispose (GObject *object)
5204 ClutterActor *self = CLUTTER_ACTOR (object);
5205 ClutterActorPrivate *priv = self->priv;
5207 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5209 g_type_name (G_OBJECT_TYPE (self)),
5212 g_signal_emit (self, actor_signals[DESTROY], 0);
5214 /* avoid recursing when called from clutter_actor_destroy() */
5215 if (priv->parent != NULL)
5217 ClutterActor *parent = priv->parent;
5219 /* go through the Container implementation unless this
5220 * is an internal child and has been marked as such.
5222 * removing the actor from its parent will reset the
5223 * realized and mapped states.
5225 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5226 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5228 clutter_actor_remove_child_internal (parent, self,
5229 REMOVE_CHILD_LEGACY_FLAGS);
5232 /* parent must be gone at this point */
5233 g_assert (priv->parent == NULL);
5235 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5237 /* can't be mapped or realized with no parent */
5238 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5239 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5242 g_clear_object (&priv->pango_context);
5243 g_clear_object (&priv->actions);
5244 g_clear_object (&priv->constraints);
5245 g_clear_object (&priv->effects);
5246 g_clear_object (&priv->flatten_effect);
5248 if (priv->layout_manager != NULL)
5250 clutter_layout_manager_set_container (priv->layout_manager, NULL);
5251 g_clear_object (&priv->layout_manager);
5254 if (priv->content != NULL)
5256 _clutter_content_detached (priv->content, self);
5257 g_clear_object (&priv->content);
5260 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5264 clutter_actor_finalize (GObject *object)
5266 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5268 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5269 priv->name != NULL ? priv->name : "<none>",
5271 g_type_name (G_OBJECT_TYPE (object)));
5273 _clutter_context_release_id (priv->id);
5275 g_free (priv->name);
5277 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5282 * clutter_actor_get_accessible:
5283 * @self: a #ClutterActor
5285 * Returns the accessible object that describes the actor to an
5286 * assistive technology.
5288 * If no class-specific #AtkObject implementation is available for the
5289 * actor instance in question, it will inherit an #AtkObject
5290 * implementation from the first ancestor class for which such an
5291 * implementation is defined.
5293 * The documentation of the <ulink
5294 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5295 * library contains more information about accessible objects and
5298 * Returns: (transfer none): the #AtkObject associated with @actor
5301 clutter_actor_get_accessible (ClutterActor *self)
5303 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5305 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5309 clutter_actor_real_get_accessible (ClutterActor *actor)
5311 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5315 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5317 AtkObject *accessible;
5319 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5320 if (accessible != NULL)
5321 g_object_ref (accessible);
5327 atk_implementor_iface_init (AtkImplementorIface *iface)
5329 iface->ref_accessible = _clutter_actor_ref_accessible;
5333 clutter_actor_update_default_paint_volume (ClutterActor *self,
5334 ClutterPaintVolume *volume)
5336 ClutterActorPrivate *priv = self->priv;
5337 gboolean res = TRUE;
5339 /* we start from the allocation */
5340 clutter_paint_volume_set_width (volume,
5341 priv->allocation.x2 - priv->allocation.x1);
5342 clutter_paint_volume_set_height (volume,
5343 priv->allocation.y2 - priv->allocation.y1);
5345 /* if the actor has a clip set then we have a pretty definite
5346 * size for the paint volume: the actor cannot possibly paint
5347 * outside the clip region.
5349 if (priv->clip_to_allocation)
5351 /* the allocation has already been set, so we just flip the
5358 ClutterActor *child;
5360 if (priv->has_clip &&
5361 priv->clip.width >= 0 &&
5362 priv->clip.height >= 0)
5364 ClutterVertex origin;
5366 origin.x = priv->clip.x;
5367 origin.y = priv->clip.y;
5370 clutter_paint_volume_set_origin (volume, &origin);
5371 clutter_paint_volume_set_width (volume, priv->clip.width);
5372 clutter_paint_volume_set_height (volume, priv->clip.height);
5377 /* if we don't have children we just bail out here... */
5378 if (priv->n_children == 0)
5381 /* ...but if we have children then we ask for their paint volume in
5382 * our coordinates. if any of our children replies that it doesn't
5383 * have a paint volume, we bail out
5385 for (child = priv->first_child;
5387 child = child->priv->next_sibling)
5389 const ClutterPaintVolume *child_volume;
5391 if (!CLUTTER_ACTOR_IS_MAPPED (child))
5394 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5395 if (child_volume == NULL)
5401 clutter_paint_volume_union (volume, child_volume);
5411 clutter_actor_real_get_paint_volume (ClutterActor *self,
5412 ClutterPaintVolume *volume)
5414 ClutterActorClass *klass;
5417 klass = CLUTTER_ACTOR_GET_CLASS (self);
5419 /* XXX - this thoroughly sucks, but we don't want to penalize users
5420 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5421 * redraw. This should go away in 2.0.
5423 if (klass->paint == clutter_actor_real_paint &&
5424 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5430 /* this is the default return value: we cannot know if a class
5431 * is going to paint outside its allocation, so we take the
5432 * conservative approach.
5437 /* update_default_paint_volume() should only fail if one of the children
5438 * reported an invalid, or no, paint volume
5440 if (!clutter_actor_update_default_paint_volume (self, volume))
5447 * clutter_actor_get_default_paint_volume:
5448 * @self: a #ClutterActor
5450 * Retrieves the default paint volume for @self.
5452 * This function provides the same #ClutterPaintVolume that would be
5453 * computed by the default implementation inside #ClutterActor of the
5454 * #ClutterActorClass.get_paint_volume() virtual function.
5456 * This function should only be used by #ClutterActor subclasses that
5457 * cannot chain up to the parent implementation when computing their
5460 * Return value: (transfer none): a pointer to the default
5461 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5462 * the actor could not compute a valid paint volume. The returned value
5463 * is not guaranteed to be stable across multiple frames, so if you
5464 * want to retain it, you will need to copy it using
5465 * clutter_paint_volume_copy().
5469 const ClutterPaintVolume *
5470 clutter_actor_get_default_paint_volume (ClutterActor *self)
5472 ClutterPaintVolume volume;
5473 ClutterPaintVolume *res;
5475 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5478 _clutter_paint_volume_init_static (&volume, self);
5479 if (clutter_actor_update_default_paint_volume (self, &volume))
5481 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5485 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5486 _clutter_paint_volume_copy_static (&volume, res);
5490 clutter_paint_volume_free (&volume);
5496 clutter_actor_real_has_overlaps (ClutterActor *self)
5498 /* By default we'll assume that all actors need an offscreen redirect to get
5499 * the correct opacity. Actors such as ClutterTexture that would never need
5500 * an offscreen redirect can override this to return FALSE. */
5505 clutter_actor_real_destroy (ClutterActor *actor)
5507 ClutterActorIter iter;
5509 g_object_freeze_notify (G_OBJECT (actor));
5511 clutter_actor_iter_init (&iter, actor);
5512 while (clutter_actor_iter_next (&iter, NULL))
5513 clutter_actor_iter_destroy (&iter);
5515 g_object_thaw_notify (G_OBJECT (actor));
5519 clutter_actor_constructor (GType gtype,
5521 GObjectConstructParam *props)
5523 GObjectClass *gobject_class;
5527 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5528 retval = gobject_class->constructor (gtype, n_props, props);
5529 self = CLUTTER_ACTOR (retval);
5531 if (self->priv->layout_manager == NULL)
5533 ClutterLayoutManager *default_layout;
5535 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5537 default_layout = clutter_fixed_layout_new ();
5538 clutter_actor_set_layout_manager (self, default_layout);
5545 clutter_actor_class_init (ClutterActorClass *klass)
5547 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5549 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5550 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5551 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5552 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5554 object_class->constructor = clutter_actor_constructor;
5555 object_class->set_property = clutter_actor_set_property;
5556 object_class->get_property = clutter_actor_get_property;
5557 object_class->dispose = clutter_actor_dispose;
5558 object_class->finalize = clutter_actor_finalize;
5560 klass->show = clutter_actor_real_show;
5561 klass->show_all = clutter_actor_show;
5562 klass->hide = clutter_actor_real_hide;
5563 klass->hide_all = clutter_actor_hide;
5564 klass->map = clutter_actor_real_map;
5565 klass->unmap = clutter_actor_real_unmap;
5566 klass->unrealize = clutter_actor_real_unrealize;
5567 klass->pick = clutter_actor_real_pick;
5568 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5569 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5570 klass->allocate = clutter_actor_real_allocate;
5571 klass->queue_redraw = clutter_actor_real_queue_redraw;
5572 klass->queue_relayout = clutter_actor_real_queue_relayout;
5573 klass->apply_transform = clutter_actor_real_apply_transform;
5574 klass->get_accessible = clutter_actor_real_get_accessible;
5575 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5576 klass->has_overlaps = clutter_actor_real_has_overlaps;
5577 klass->paint = clutter_actor_real_paint;
5578 klass->destroy = clutter_actor_real_destroy;
5580 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5585 * X coordinate of the actor in pixels. If written, forces a fixed
5586 * position for the actor. If read, returns the fixed position if any,
5587 * otherwise the allocation if available, otherwise 0.
5589 * The #ClutterActor:x property is animatable.
5592 g_param_spec_float ("x",
5594 P_("X coordinate of the actor"),
5595 -G_MAXFLOAT, G_MAXFLOAT,
5598 G_PARAM_STATIC_STRINGS |
5599 CLUTTER_PARAM_ANIMATABLE);
5604 * Y coordinate of the actor in pixels. If written, forces a fixed
5605 * position for the actor. If read, returns the fixed position if
5606 * any, otherwise the allocation if available, otherwise 0.
5608 * The #ClutterActor:y property is animatable.
5611 g_param_spec_float ("y",
5613 P_("Y coordinate of the actor"),
5614 -G_MAXFLOAT, G_MAXFLOAT,
5617 G_PARAM_STATIC_STRINGS |
5618 CLUTTER_PARAM_ANIMATABLE);
5621 * ClutterActor:position:
5623 * The position of the origin of the actor.
5625 * This property is a shorthand for setting and getting the
5626 * #ClutterActor:x and #ClutterActor:y properties at the same
5629 * The #ClutterActor:position property is animatable.
5633 obj_props[PROP_POSITION] =
5634 g_param_spec_boxed ("position",
5636 P_("The position of the origin of the actor"),
5639 G_PARAM_STATIC_STRINGS |
5640 CLUTTER_PARAM_ANIMATABLE);
5643 * ClutterActor:width:
5645 * Width of the actor (in pixels). If written, forces the minimum and
5646 * natural size request of the actor to the given width. If read, returns
5647 * the allocated width if available, otherwise the width request.
5649 * The #ClutterActor:width property is animatable.
5651 obj_props[PROP_WIDTH] =
5652 g_param_spec_float ("width",
5654 P_("Width of the actor"),
5658 G_PARAM_STATIC_STRINGS |
5659 CLUTTER_PARAM_ANIMATABLE);
5662 * ClutterActor:height:
5664 * Height of the actor (in pixels). If written, forces the minimum and
5665 * natural size request of the actor to the given height. If read, returns
5666 * the allocated height if available, otherwise the height request.
5668 * The #ClutterActor:height property is animatable.
5670 obj_props[PROP_HEIGHT] =
5671 g_param_spec_float ("height",
5673 P_("Height of the actor"),
5677 G_PARAM_STATIC_STRINGS |
5678 CLUTTER_PARAM_ANIMATABLE);
5681 * ClutterActor:size:
5683 * The size of the actor.
5685 * This property is a shorthand for setting and getting the
5686 * #ClutterActor:width and #ClutterActor:height at the same time.
5688 * The #ClutterActor:size property is animatable.
5692 obj_props[PROP_SIZE] =
5693 g_param_spec_boxed ("size",
5695 P_("The size of the actor"),
5698 G_PARAM_STATIC_STRINGS |
5699 CLUTTER_PARAM_ANIMATABLE);
5702 * ClutterActor:fixed-x:
5704 * The fixed X position of the actor in pixels.
5706 * Writing this property sets #ClutterActor:fixed-position-set
5707 * property as well, as a side effect
5711 obj_props[PROP_FIXED_X] =
5712 g_param_spec_float ("fixed-x",
5714 P_("Forced X position of the actor"),
5715 -G_MAXFLOAT, G_MAXFLOAT,
5717 CLUTTER_PARAM_READWRITE);
5720 * ClutterActor:fixed-y:
5722 * The fixed Y position of the actor in pixels.
5724 * Writing this property sets the #ClutterActor:fixed-position-set
5725 * property as well, as a side effect
5729 obj_props[PROP_FIXED_Y] =
5730 g_param_spec_float ("fixed-y",
5732 P_("Forced Y position of the actor"),
5733 -G_MAXFLOAT, G_MAXFLOAT,
5735 CLUTTER_PARAM_READWRITE);
5738 * ClutterActor:fixed-position-set:
5740 * This flag controls whether the #ClutterActor:fixed-x and
5741 * #ClutterActor:fixed-y properties are used
5745 obj_props[PROP_FIXED_POSITION_SET] =
5746 g_param_spec_boolean ("fixed-position-set",
5747 P_("Fixed position set"),
5748 P_("Whether to use fixed positioning for the actor"),
5750 CLUTTER_PARAM_READWRITE);
5753 * ClutterActor:min-width:
5755 * A forced minimum width request for the actor, in pixels
5757 * Writing this property sets the #ClutterActor:min-width-set property
5758 * as well, as a side effect.
5760 *This property overrides the usual width request of the actor.
5764 obj_props[PROP_MIN_WIDTH] =
5765 g_param_spec_float ("min-width",
5767 P_("Forced minimum width request for the actor"),
5770 CLUTTER_PARAM_READWRITE);
5773 * ClutterActor:min-height:
5775 * A forced minimum height request for the actor, in pixels
5777 * Writing this property sets the #ClutterActor:min-height-set property
5778 * as well, as a side effect. This property overrides the usual height
5779 * request of the actor.
5783 obj_props[PROP_MIN_HEIGHT] =
5784 g_param_spec_float ("min-height",
5786 P_("Forced minimum height request for the actor"),
5789 CLUTTER_PARAM_READWRITE);
5792 * ClutterActor:natural-width:
5794 * A forced natural width request for the actor, in pixels
5796 * Writing this property sets the #ClutterActor:natural-width-set
5797 * property as well, as a side effect. This property overrides the
5798 * usual width request of the actor
5802 obj_props[PROP_NATURAL_WIDTH] =
5803 g_param_spec_float ("natural-width",
5804 P_("Natural Width"),
5805 P_("Forced natural width request for the actor"),
5808 CLUTTER_PARAM_READWRITE);
5811 * ClutterActor:natural-height:
5813 * A forced natural height request for the actor, in pixels
5815 * Writing this property sets the #ClutterActor:natural-height-set
5816 * property as well, as a side effect. This property overrides the
5817 * usual height request of the actor
5821 obj_props[PROP_NATURAL_HEIGHT] =
5822 g_param_spec_float ("natural-height",
5823 P_("Natural Height"),
5824 P_("Forced natural height request for the actor"),
5827 CLUTTER_PARAM_READWRITE);
5830 * ClutterActor:min-width-set:
5832 * This flag controls whether the #ClutterActor:min-width property
5837 obj_props[PROP_MIN_WIDTH_SET] =
5838 g_param_spec_boolean ("min-width-set",
5839 P_("Minimum width set"),
5840 P_("Whether to use the min-width property"),
5842 CLUTTER_PARAM_READWRITE);
5845 * ClutterActor:min-height-set:
5847 * This flag controls whether the #ClutterActor:min-height property
5852 obj_props[PROP_MIN_HEIGHT_SET] =
5853 g_param_spec_boolean ("min-height-set",
5854 P_("Minimum height set"),
5855 P_("Whether to use the min-height property"),
5857 CLUTTER_PARAM_READWRITE);
5860 * ClutterActor:natural-width-set:
5862 * This flag controls whether the #ClutterActor:natural-width property
5867 obj_props[PROP_NATURAL_WIDTH_SET] =
5868 g_param_spec_boolean ("natural-width-set",
5869 P_("Natural width set"),
5870 P_("Whether to use the natural-width property"),
5872 CLUTTER_PARAM_READWRITE);
5875 * ClutterActor:natural-height-set:
5877 * This flag controls whether the #ClutterActor:natural-height property
5882 obj_props[PROP_NATURAL_HEIGHT_SET] =
5883 g_param_spec_boolean ("natural-height-set",
5884 P_("Natural height set"),
5885 P_("Whether to use the natural-height property"),
5887 CLUTTER_PARAM_READWRITE);
5890 * ClutterActor:allocation:
5892 * The allocation for the actor, in pixels
5894 * This is property is read-only, but you might monitor it to know when an
5895 * actor moves or resizes
5899 obj_props[PROP_ALLOCATION] =
5900 g_param_spec_boxed ("allocation",
5902 P_("The actor's allocation"),
5903 CLUTTER_TYPE_ACTOR_BOX,
5905 G_PARAM_STATIC_STRINGS |
5906 CLUTTER_PARAM_ANIMATABLE);
5909 * ClutterActor:request-mode:
5911 * Request mode for the #ClutterActor. The request mode determines the
5912 * type of geometry management used by the actor, either height for width
5913 * (the default) or width for height.
5915 * For actors implementing height for width, the parent container should get
5916 * the preferred width first, and then the preferred height for that width.
5918 * For actors implementing width for height, the parent container should get
5919 * the preferred height first, and then the preferred width for that height.
5924 * ClutterRequestMode mode;
5925 * gfloat natural_width, min_width;
5926 * gfloat natural_height, min_height;
5928 * mode = clutter_actor_get_request_mode (child);
5929 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5931 * clutter_actor_get_preferred_width (child, -1,
5933 * &natural_width);
5934 * clutter_actor_get_preferred_height (child, natural_width,
5936 * &natural_height);
5940 * clutter_actor_get_preferred_height (child, -1,
5942 * &natural_height);
5943 * clutter_actor_get_preferred_width (child, natural_height,
5945 * &natural_width);
5949 * will retrieve the minimum and natural width and height depending on the
5950 * preferred request mode of the #ClutterActor "child".
5952 * The clutter_actor_get_preferred_size() function will implement this
5957 obj_props[PROP_REQUEST_MODE] =
5958 g_param_spec_enum ("request-mode",
5960 P_("The actor's request mode"),
5961 CLUTTER_TYPE_REQUEST_MODE,
5962 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5963 CLUTTER_PARAM_READWRITE);
5966 * ClutterActor:depth:
5968 * The position of the actor on the Z axis.
5970 * The #ClutterActor:depth property is relative to the parent's
5973 * The #ClutterActor:depth property is animatable.
5977 obj_props[PROP_DEPTH] =
5978 g_param_spec_float ("depth",
5980 P_("Position on the Z axis"),
5981 -G_MAXFLOAT, G_MAXFLOAT,
5984 G_PARAM_STATIC_STRINGS |
5985 CLUTTER_PARAM_ANIMATABLE);
5988 * ClutterActor:opacity:
5990 * Opacity of an actor, between 0 (fully transparent) and
5991 * 255 (fully opaque)
5993 * The #ClutterActor:opacity property is animatable.
5995 obj_props[PROP_OPACITY] =
5996 g_param_spec_uint ("opacity",
5998 P_("Opacity of an actor"),
6002 G_PARAM_STATIC_STRINGS |
6003 CLUTTER_PARAM_ANIMATABLE);
6006 * ClutterActor:offscreen-redirect:
6008 * Determines the conditions in which the actor will be redirected
6009 * to an offscreen framebuffer while being painted. For example this
6010 * can be used to cache an actor in a framebuffer or for improved
6011 * handling of transparent actors. See
6012 * clutter_actor_set_offscreen_redirect() for details.
6016 obj_props[PROP_OFFSCREEN_REDIRECT] =
6017 g_param_spec_flags ("offscreen-redirect",
6018 P_("Offscreen redirect"),
6019 P_("Flags controlling when to flatten the actor into a single image"),
6020 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
6022 CLUTTER_PARAM_READWRITE);
6025 * ClutterActor:visible:
6027 * Whether the actor is set to be visible or not
6029 * See also #ClutterActor:mapped
6031 obj_props[PROP_VISIBLE] =
6032 g_param_spec_boolean ("visible",
6034 P_("Whether the actor is visible or not"),
6036 CLUTTER_PARAM_READWRITE);
6039 * ClutterActor:mapped:
6041 * Whether the actor is mapped (will be painted when the stage
6042 * to which it belongs is mapped)
6046 obj_props[PROP_MAPPED] =
6047 g_param_spec_boolean ("mapped",
6049 P_("Whether the actor will be painted"),
6051 CLUTTER_PARAM_READABLE);
6054 * ClutterActor:realized:
6056 * Whether the actor has been realized
6060 obj_props[PROP_REALIZED] =
6061 g_param_spec_boolean ("realized",
6063 P_("Whether the actor has been realized"),
6065 CLUTTER_PARAM_READABLE);
6068 * ClutterActor:reactive:
6070 * Whether the actor is reactive to events or not
6072 * Only reactive actors will emit event-related signals
6076 obj_props[PROP_REACTIVE] =
6077 g_param_spec_boolean ("reactive",
6079 P_("Whether the actor is reactive to events"),
6081 CLUTTER_PARAM_READWRITE);
6084 * ClutterActor:has-clip:
6086 * Whether the actor has the #ClutterActor:clip property set or not
6088 obj_props[PROP_HAS_CLIP] =
6089 g_param_spec_boolean ("has-clip",
6091 P_("Whether the actor has a clip set"),
6093 CLUTTER_PARAM_READABLE);
6096 * ClutterActor:clip:
6098 * The clip region for the actor, in actor-relative coordinates
6100 * Every part of the actor outside the clip region will not be
6103 obj_props[PROP_CLIP] =
6104 g_param_spec_boxed ("clip",
6106 P_("The clip region for the actor"),
6107 CLUTTER_TYPE_GEOMETRY,
6108 CLUTTER_PARAM_READWRITE);
6111 * ClutterActor:name:
6113 * The name of the actor
6117 obj_props[PROP_NAME] =
6118 g_param_spec_string ("name",
6120 P_("Name of the actor"),
6122 CLUTTER_PARAM_READWRITE);
6125 * ClutterActor:scale-x:
6127 * The horizontal scale of the actor.
6129 * The #ClutterActor:scale-x property is animatable.
6133 obj_props[PROP_SCALE_X] =
6134 g_param_spec_double ("scale-x",
6136 P_("Scale factor on the X axis"),
6140 G_PARAM_STATIC_STRINGS |
6141 CLUTTER_PARAM_ANIMATABLE);
6144 * ClutterActor:scale-y:
6146 * The vertical scale of the actor.
6148 * The #ClutterActor:scale-y property is animatable.
6152 obj_props[PROP_SCALE_Y] =
6153 g_param_spec_double ("scale-y",
6155 P_("Scale factor on the Y axis"),
6159 G_PARAM_STATIC_STRINGS |
6160 CLUTTER_PARAM_ANIMATABLE);
6163 * ClutterActor:scale-center-x:
6165 * The horizontal center point for scaling
6169 obj_props[PROP_SCALE_CENTER_X] =
6170 g_param_spec_float ("scale-center-x",
6171 P_("Scale Center X"),
6172 P_("Horizontal scale center"),
6173 -G_MAXFLOAT, G_MAXFLOAT,
6175 CLUTTER_PARAM_READWRITE);
6178 * ClutterActor:scale-center-y:
6180 * The vertical center point for scaling
6184 obj_props[PROP_SCALE_CENTER_Y] =
6185 g_param_spec_float ("scale-center-y",
6186 P_("Scale Center Y"),
6187 P_("Vertical scale center"),
6188 -G_MAXFLOAT, G_MAXFLOAT,
6190 CLUTTER_PARAM_READWRITE);
6193 * ClutterActor:scale-gravity:
6195 * The center point for scaling expressed as a #ClutterGravity
6199 obj_props[PROP_SCALE_GRAVITY] =
6200 g_param_spec_enum ("scale-gravity",
6201 P_("Scale Gravity"),
6202 P_("The center of scaling"),
6203 CLUTTER_TYPE_GRAVITY,
6204 CLUTTER_GRAVITY_NONE,
6205 CLUTTER_PARAM_READWRITE);
6208 * ClutterActor:rotation-angle-x:
6210 * The rotation angle on the X axis.
6212 * The #ClutterActor:rotation-angle-x property is animatable.
6216 obj_props[PROP_ROTATION_ANGLE_X] =
6217 g_param_spec_double ("rotation-angle-x",
6218 P_("Rotation Angle X"),
6219 P_("The rotation angle on the X axis"),
6220 -G_MAXDOUBLE, G_MAXDOUBLE,
6223 G_PARAM_STATIC_STRINGS |
6224 CLUTTER_PARAM_ANIMATABLE);
6227 * ClutterActor:rotation-angle-y:
6229 * The rotation angle on the Y axis
6231 * The #ClutterActor:rotation-angle-y property is animatable.
6235 obj_props[PROP_ROTATION_ANGLE_Y] =
6236 g_param_spec_double ("rotation-angle-y",
6237 P_("Rotation Angle Y"),
6238 P_("The rotation angle on the Y axis"),
6239 -G_MAXDOUBLE, G_MAXDOUBLE,
6242 G_PARAM_STATIC_STRINGS |
6243 CLUTTER_PARAM_ANIMATABLE);
6246 * ClutterActor:rotation-angle-z:
6248 * The rotation angle on the Z axis
6250 * The #ClutterActor:rotation-angle-z property is animatable.
6254 obj_props[PROP_ROTATION_ANGLE_Z] =
6255 g_param_spec_double ("rotation-angle-z",
6256 P_("Rotation Angle Z"),
6257 P_("The rotation angle on the Z axis"),
6258 -G_MAXDOUBLE, G_MAXDOUBLE,
6261 G_PARAM_STATIC_STRINGS |
6262 CLUTTER_PARAM_ANIMATABLE);
6265 * ClutterActor:rotation-center-x:
6267 * The rotation center on the X axis.
6271 obj_props[PROP_ROTATION_CENTER_X] =
6272 g_param_spec_boxed ("rotation-center-x",
6273 P_("Rotation Center X"),
6274 P_("The rotation center on the X axis"),
6275 CLUTTER_TYPE_VERTEX,
6276 CLUTTER_PARAM_READWRITE);
6279 * ClutterActor:rotation-center-y:
6281 * The rotation center on the Y axis.
6285 obj_props[PROP_ROTATION_CENTER_Y] =
6286 g_param_spec_boxed ("rotation-center-y",
6287 P_("Rotation Center Y"),
6288 P_("The rotation center on the Y axis"),
6289 CLUTTER_TYPE_VERTEX,
6290 CLUTTER_PARAM_READWRITE);
6293 * ClutterActor:rotation-center-z:
6295 * The rotation center on the Z axis.
6299 obj_props[PROP_ROTATION_CENTER_Z] =
6300 g_param_spec_boxed ("rotation-center-z",
6301 P_("Rotation Center Z"),
6302 P_("The rotation center on the Z axis"),
6303 CLUTTER_TYPE_VERTEX,
6304 CLUTTER_PARAM_READWRITE);
6307 * ClutterActor:rotation-center-z-gravity:
6309 * The rotation center on the Z axis expressed as a #ClutterGravity.
6313 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6314 g_param_spec_enum ("rotation-center-z-gravity",
6315 P_("Rotation Center Z Gravity"),
6316 P_("Center point for rotation around the Z axis"),
6317 CLUTTER_TYPE_GRAVITY,
6318 CLUTTER_GRAVITY_NONE,
6319 CLUTTER_PARAM_READWRITE);
6322 * ClutterActor:anchor-x:
6324 * The X coordinate of an actor's anchor point, relative to
6325 * the actor coordinate space, in pixels
6329 obj_props[PROP_ANCHOR_X] =
6330 g_param_spec_float ("anchor-x",
6332 P_("X coordinate of the anchor point"),
6333 -G_MAXFLOAT, G_MAXFLOAT,
6335 CLUTTER_PARAM_READWRITE);
6338 * ClutterActor:anchor-y:
6340 * The Y coordinate of an actor's anchor point, relative to
6341 * the actor coordinate space, in pixels
6345 obj_props[PROP_ANCHOR_Y] =
6346 g_param_spec_float ("anchor-y",
6348 P_("Y coordinate of the anchor point"),
6349 -G_MAXFLOAT, G_MAXFLOAT,
6351 CLUTTER_PARAM_READWRITE);
6354 * ClutterActor:anchor-gravity:
6356 * The anchor point expressed as a #ClutterGravity
6360 obj_props[PROP_ANCHOR_GRAVITY] =
6361 g_param_spec_enum ("anchor-gravity",
6362 P_("Anchor Gravity"),
6363 P_("The anchor point as a ClutterGravity"),
6364 CLUTTER_TYPE_GRAVITY,
6365 CLUTTER_GRAVITY_NONE,
6366 CLUTTER_PARAM_READWRITE);
6369 * ClutterActor:show-on-set-parent:
6371 * If %TRUE, the actor is automatically shown when parented.
6373 * Calling clutter_actor_hide() on an actor which has not been
6374 * parented will set this property to %FALSE as a side effect.
6378 obj_props[PROP_SHOW_ON_SET_PARENT] =
6379 g_param_spec_boolean ("show-on-set-parent",
6380 P_("Show on set parent"),
6381 P_("Whether the actor is shown when parented"),
6383 CLUTTER_PARAM_READWRITE);
6386 * ClutterActor:clip-to-allocation:
6388 * Whether the clip region should track the allocated area
6391 * This property is ignored if a clip area has been explicitly
6392 * set using clutter_actor_set_clip().
6396 obj_props[PROP_CLIP_TO_ALLOCATION] =
6397 g_param_spec_boolean ("clip-to-allocation",
6398 P_("Clip to Allocation"),
6399 P_("Sets the clip region to track the actor's allocation"),
6401 CLUTTER_PARAM_READWRITE);
6404 * ClutterActor:text-direction:
6406 * The direction of the text inside a #ClutterActor.
6410 obj_props[PROP_TEXT_DIRECTION] =
6411 g_param_spec_enum ("text-direction",
6412 P_("Text Direction"),
6413 P_("Direction of the text"),
6414 CLUTTER_TYPE_TEXT_DIRECTION,
6415 CLUTTER_TEXT_DIRECTION_LTR,
6416 CLUTTER_PARAM_READWRITE);
6419 * ClutterActor:has-pointer:
6421 * Whether the actor contains the pointer of a #ClutterInputDevice
6426 obj_props[PROP_HAS_POINTER] =
6427 g_param_spec_boolean ("has-pointer",
6429 P_("Whether the actor contains the pointer of an input device"),
6431 CLUTTER_PARAM_READABLE);
6434 * ClutterActor:actions:
6436 * Adds a #ClutterAction to the actor
6440 obj_props[PROP_ACTIONS] =
6441 g_param_spec_object ("actions",
6443 P_("Adds an action to the actor"),
6444 CLUTTER_TYPE_ACTION,
6445 CLUTTER_PARAM_WRITABLE);
6448 * ClutterActor:constraints:
6450 * Adds a #ClutterConstraint to the actor
6454 obj_props[PROP_CONSTRAINTS] =
6455 g_param_spec_object ("constraints",
6457 P_("Adds a constraint to the actor"),
6458 CLUTTER_TYPE_CONSTRAINT,
6459 CLUTTER_PARAM_WRITABLE);
6462 * ClutterActor:effect:
6464 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6468 obj_props[PROP_EFFECT] =
6469 g_param_spec_object ("effect",
6471 P_("Add an effect to be applied on the actor"),
6472 CLUTTER_TYPE_EFFECT,
6473 CLUTTER_PARAM_WRITABLE);
6476 * ClutterActor:layout-manager:
6478 * A delegate object for controlling the layout of the children of
6483 obj_props[PROP_LAYOUT_MANAGER] =
6484 g_param_spec_object ("layout-manager",
6485 P_("Layout Manager"),
6486 P_("The object controlling the layout of an actor's children"),
6487 CLUTTER_TYPE_LAYOUT_MANAGER,
6488 CLUTTER_PARAM_READWRITE);
6491 * ClutterActor:x-expand:
6493 * Whether a layout manager should assign more space to the actor on
6498 obj_props[PROP_X_EXPAND] =
6499 g_param_spec_boolean ("x-expand",
6501 P_("Whether extra horizontal space should be assigned to the actor"),
6504 G_PARAM_STATIC_STRINGS);
6507 * ClutterActor:y-expand:
6509 * Whether a layout manager should assign more space to the actor on
6514 obj_props[PROP_Y_EXPAND] =
6515 g_param_spec_boolean ("y-expand",
6517 P_("Whether extra vertical space should be assigned to the actor"),
6520 G_PARAM_STATIC_STRINGS);
6523 * ClutterActor:x-align:
6525 * The alignment of an actor on the X axis, if the actor has been given
6526 * extra space for its allocation. See also the #ClutterActor:x-expand
6531 obj_props[PROP_X_ALIGN] =
6532 g_param_spec_enum ("x-align",
6534 P_("The alignment of the actor on the X axis within its allocation"),
6535 CLUTTER_TYPE_ACTOR_ALIGN,
6536 CLUTTER_ACTOR_ALIGN_FILL,
6537 CLUTTER_PARAM_READWRITE);
6540 * ClutterActor:y-align:
6542 * The alignment of an actor on the Y axis, if the actor has been given
6543 * extra space for its allocation.
6547 obj_props[PROP_Y_ALIGN] =
6548 g_param_spec_enum ("y-align",
6550 P_("The alignment of the actor on the Y axis within its allocation"),
6551 CLUTTER_TYPE_ACTOR_ALIGN,
6552 CLUTTER_ACTOR_ALIGN_FILL,
6553 CLUTTER_PARAM_READWRITE);
6556 * ClutterActor:margin-top:
6558 * The margin (in pixels) from the top of the actor.
6560 * This property adds a margin to the actor's preferred size; the margin
6561 * will be automatically taken into account when allocating the actor.
6565 obj_props[PROP_MARGIN_TOP] =
6566 g_param_spec_float ("margin-top",
6568 P_("Extra space at the top"),
6571 CLUTTER_PARAM_READWRITE);
6574 * ClutterActor:margin-bottom:
6576 * The margin (in pixels) from the bottom of the actor.
6578 * This property adds a margin to the actor's preferred size; the margin
6579 * will be automatically taken into account when allocating the actor.
6583 obj_props[PROP_MARGIN_BOTTOM] =
6584 g_param_spec_float ("margin-bottom",
6585 P_("Margin Bottom"),
6586 P_("Extra space at the bottom"),
6589 CLUTTER_PARAM_READWRITE);
6592 * ClutterActor:margin-left:
6594 * The margin (in pixels) from the left of the actor.
6596 * This property adds a margin to the actor's preferred size; the margin
6597 * will be automatically taken into account when allocating the actor.
6601 obj_props[PROP_MARGIN_LEFT] =
6602 g_param_spec_float ("margin-left",
6604 P_("Extra space at the left"),
6607 CLUTTER_PARAM_READWRITE);
6610 * ClutterActor:margin-right:
6612 * The margin (in pixels) from the right of the actor.
6614 * This property adds a margin to the actor's preferred size; the margin
6615 * will be automatically taken into account when allocating the actor.
6619 obj_props[PROP_MARGIN_RIGHT] =
6620 g_param_spec_float ("margin-right",
6622 P_("Extra space at the right"),
6625 CLUTTER_PARAM_READWRITE);
6628 * ClutterActor:background-color-set:
6630 * Whether the #ClutterActor:background-color property has been set.
6634 obj_props[PROP_BACKGROUND_COLOR_SET] =
6635 g_param_spec_boolean ("background-color-set",
6636 P_("Background Color Set"),
6637 P_("Whether the background color is set"),
6639 CLUTTER_PARAM_READABLE);
6642 * ClutterActor:background-color:
6644 * Paints a solid fill of the actor's allocation using the specified
6647 * The #ClutterActor:background-color property is animatable.
6651 obj_props[PROP_BACKGROUND_COLOR] =
6652 clutter_param_spec_color ("background-color",
6653 P_("Background color"),
6654 P_("The actor's background color"),
6655 CLUTTER_COLOR_Transparent,
6657 G_PARAM_STATIC_STRINGS |
6658 CLUTTER_PARAM_ANIMATABLE);
6661 * ClutterActor:first-child:
6663 * The actor's first child.
6667 obj_props[PROP_FIRST_CHILD] =
6668 g_param_spec_object ("first-child",
6670 P_("The actor's first child"),
6672 CLUTTER_PARAM_READABLE);
6675 * ClutterActor:last-child:
6677 * The actor's last child.
6681 obj_props[PROP_LAST_CHILD] =
6682 g_param_spec_object ("last-child",
6684 P_("The actor's last child"),
6686 CLUTTER_PARAM_READABLE);
6689 * ClutterActor:content:
6691 * The #ClutterContent implementation that controls the content
6696 obj_props[PROP_CONTENT] =
6697 g_param_spec_object ("content",
6699 P_("Delegate object for painting the actor's content"),
6700 CLUTTER_TYPE_CONTENT,
6701 CLUTTER_PARAM_READWRITE);
6704 * ClutterActor:content-gravity:
6706 * The alignment that should be honoured by the #ClutterContent
6707 * set with the #ClutterActor:content property.
6709 * Changing the value of this property will change the bounding box of
6710 * the content; you can use the #ClutterActor:content-box property to
6711 * get the position and size of the content within the actor's
6714 * This property is meaningful only for #ClutterContent implementations
6715 * that have a preferred size, and if the preferred size is smaller than
6716 * the actor's allocation.
6718 * The #ClutterActor:content-gravity property is animatable.
6722 obj_props[PROP_CONTENT_GRAVITY] =
6723 g_param_spec_enum ("content-gravity",
6724 P_("Content Gravity"),
6725 P_("Alignment of the actor's content"),
6726 CLUTTER_TYPE_CONTENT_GRAVITY,
6727 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6728 CLUTTER_PARAM_READWRITE);
6731 * ClutterActor:content-box:
6733 * The bounding box for the #ClutterContent used by the actor.
6735 * The value of this property is controlled by the #ClutterActor:allocation
6736 * and #ClutterActor:content-gravity properties of #ClutterActor.
6738 * The bounding box for the content is guaranteed to never exceed the
6739 * allocation's of the actor.
6743 obj_props[PROP_CONTENT_BOX] =
6744 g_param_spec_boxed ("content-box",
6746 P_("The bounding box of the actor's content"),
6747 CLUTTER_TYPE_ACTOR_BOX,
6749 G_PARAM_STATIC_STRINGS |
6750 CLUTTER_PARAM_ANIMATABLE);
6752 obj_props[PROP_MINIFICATION_FILTER] =
6753 g_param_spec_enum ("minification-filter",
6754 P_("Minification Filter"),
6755 P_("The filter used when reducing the size of the content"),
6756 CLUTTER_TYPE_SCALING_FILTER,
6757 CLUTTER_SCALING_FILTER_LINEAR,
6758 CLUTTER_PARAM_READWRITE);
6760 obj_props[PROP_MAGNIFICATION_FILTER] =
6761 g_param_spec_enum ("magnification-filter",
6762 P_("Magnification Filter"),
6763 P_("The filter used when increasing the size of the content"),
6764 CLUTTER_TYPE_SCALING_FILTER,
6765 CLUTTER_SCALING_FILTER_LINEAR,
6766 CLUTTER_PARAM_READWRITE);
6768 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6771 * ClutterActor::destroy:
6772 * @actor: the #ClutterActor which emitted the signal
6774 * The ::destroy signal notifies that all references held on the
6775 * actor which emitted it should be released.
6777 * The ::destroy signal should be used by all holders of a reference
6780 * This signal might result in the finalization of the #ClutterActor
6781 * if all references are released.
6783 * Composite actors and actors implementing the #ClutterContainer
6784 * interface should override the default implementation of the
6785 * class handler of this signal and call clutter_actor_destroy() on
6786 * their children. When overriding the default class handler, it is
6787 * required to chain up to the parent's implementation.
6791 actor_signals[DESTROY] =
6792 g_signal_new (I_("destroy"),
6793 G_TYPE_FROM_CLASS (object_class),
6794 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6795 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6797 _clutter_marshal_VOID__VOID,
6800 * ClutterActor::show:
6801 * @actor: the object which received the signal
6803 * The ::show signal is emitted when an actor is visible and
6804 * rendered on the stage.
6808 actor_signals[SHOW] =
6809 g_signal_new (I_("show"),
6810 G_TYPE_FROM_CLASS (object_class),
6812 G_STRUCT_OFFSET (ClutterActorClass, show),
6814 _clutter_marshal_VOID__VOID,
6817 * ClutterActor::hide:
6818 * @actor: the object which received the signal
6820 * The ::hide signal is emitted when an actor is no longer rendered
6825 actor_signals[HIDE] =
6826 g_signal_new (I_("hide"),
6827 G_TYPE_FROM_CLASS (object_class),
6829 G_STRUCT_OFFSET (ClutterActorClass, hide),
6831 _clutter_marshal_VOID__VOID,
6834 * ClutterActor::parent-set:
6835 * @actor: the object which received the signal
6836 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6838 * This signal is emitted when the parent of the actor changes.
6842 actor_signals[PARENT_SET] =
6843 g_signal_new (I_("parent-set"),
6844 G_TYPE_FROM_CLASS (object_class),
6846 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6848 _clutter_marshal_VOID__OBJECT,
6850 CLUTTER_TYPE_ACTOR);
6853 * ClutterActor::queue-redraw:
6854 * @actor: the actor we're bubbling the redraw request through
6855 * @origin: the actor which initiated the redraw request
6857 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6858 * is called on @origin.
6860 * The default implementation for #ClutterActor chains up to the
6861 * parent actor and queues a redraw on the parent, thus "bubbling"
6862 * the redraw queue up through the actor graph. The default
6863 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6864 * in a main loop idle handler.
6866 * Note that the @origin actor may be the stage, or a container; it
6867 * does not have to be a leaf node in the actor graph.
6869 * Toolkits embedding a #ClutterStage which require a redraw and
6870 * relayout cycle can stop the emission of this signal using the
6871 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6876 * on_redraw_complete (gpointer data)
6878 * ClutterStage *stage = data;
6880 * /* execute the Clutter drawing pipeline */
6881 * clutter_stage_ensure_redraw (stage);
6885 * on_stage_queue_redraw (ClutterStage *stage)
6887 * /* this prevents the default handler to run */
6888 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6890 * /* queue a redraw with the host toolkit and call
6891 * * a function when the redraw has been completed
6893 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6897 * <note><para>This signal is emitted before the Clutter paint
6898 * pipeline is executed. If you want to know when the pipeline has
6899 * been completed you should connect to the ::paint signal on the
6900 * Stage with g_signal_connect_after().</para></note>
6904 actor_signals[QUEUE_REDRAW] =
6905 g_signal_new (I_("queue-redraw"),
6906 G_TYPE_FROM_CLASS (object_class),
6909 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6911 _clutter_marshal_VOID__OBJECT,
6913 CLUTTER_TYPE_ACTOR);
6916 * ClutterActor::queue-relayout:
6917 * @actor: the actor being queued for relayout
6919 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6920 * is called on an actor.
6922 * The default implementation for #ClutterActor chains up to the
6923 * parent actor and queues a relayout on the parent, thus "bubbling"
6924 * the relayout queue up through the actor graph.
6926 * The main purpose of this signal is to allow relayout to be propagated
6927 * properly in the procense of #ClutterClone actors. Applications will
6928 * not normally need to connect to this signal.
6932 actor_signals[QUEUE_RELAYOUT] =
6933 g_signal_new (I_("queue-relayout"),
6934 G_TYPE_FROM_CLASS (object_class),
6937 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6939 _clutter_marshal_VOID__VOID,
6943 * ClutterActor::event:
6944 * @actor: the actor which received the event
6945 * @event: a #ClutterEvent
6947 * The ::event signal is emitted each time an event is received
6948 * by the @actor. This signal will be emitted on every actor,
6949 * following the hierarchy chain, until it reaches the top-level
6950 * container (the #ClutterStage).
6952 * Return value: %TRUE if the event has been handled by the actor,
6953 * or %FALSE to continue the emission.
6957 actor_signals[EVENT] =
6958 g_signal_new (I_("event"),
6959 G_TYPE_FROM_CLASS (object_class),
6961 G_STRUCT_OFFSET (ClutterActorClass, event),
6962 _clutter_boolean_handled_accumulator, NULL,
6963 _clutter_marshal_BOOLEAN__BOXED,
6965 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6967 * ClutterActor::button-press-event:
6968 * @actor: the actor which received the event
6969 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6971 * The ::button-press-event signal is emitted each time a mouse button
6972 * is pressed on @actor.
6974 * Return value: %TRUE if the event has been handled by the actor,
6975 * or %FALSE to continue the emission.
6979 actor_signals[BUTTON_PRESS_EVENT] =
6980 g_signal_new (I_("button-press-event"),
6981 G_TYPE_FROM_CLASS (object_class),
6983 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6984 _clutter_boolean_handled_accumulator, NULL,
6985 _clutter_marshal_BOOLEAN__BOXED,
6987 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6989 * ClutterActor::button-release-event:
6990 * @actor: the actor which received the event
6991 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6993 * The ::button-release-event signal is emitted each time a mouse button
6994 * is released on @actor.
6996 * Return value: %TRUE if the event has been handled by the actor,
6997 * or %FALSE to continue the emission.
7001 actor_signals[BUTTON_RELEASE_EVENT] =
7002 g_signal_new (I_("button-release-event"),
7003 G_TYPE_FROM_CLASS (object_class),
7005 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
7006 _clutter_boolean_handled_accumulator, NULL,
7007 _clutter_marshal_BOOLEAN__BOXED,
7009 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7011 * ClutterActor::scroll-event:
7012 * @actor: the actor which received the event
7013 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
7015 * The ::scroll-event signal is emitted each time the mouse is
7016 * scrolled on @actor
7018 * Return value: %TRUE if the event has been handled by the actor,
7019 * or %FALSE to continue the emission.
7023 actor_signals[SCROLL_EVENT] =
7024 g_signal_new (I_("scroll-event"),
7025 G_TYPE_FROM_CLASS (object_class),
7027 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
7028 _clutter_boolean_handled_accumulator, NULL,
7029 _clutter_marshal_BOOLEAN__BOXED,
7031 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7033 * ClutterActor::key-press-event:
7034 * @actor: the actor which received the event
7035 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7037 * The ::key-press-event signal is emitted each time a keyboard button
7038 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
7040 * Return value: %TRUE if the event has been handled by the actor,
7041 * or %FALSE to continue the emission.
7045 actor_signals[KEY_PRESS_EVENT] =
7046 g_signal_new (I_("key-press-event"),
7047 G_TYPE_FROM_CLASS (object_class),
7049 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
7050 _clutter_boolean_handled_accumulator, NULL,
7051 _clutter_marshal_BOOLEAN__BOXED,
7053 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7055 * ClutterActor::key-release-event:
7056 * @actor: the actor which received the event
7057 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7059 * The ::key-release-event signal is emitted each time a keyboard button
7060 * is released while @actor has key focus (see
7061 * clutter_stage_set_key_focus()).
7063 * Return value: %TRUE if the event has been handled by the actor,
7064 * or %FALSE to continue the emission.
7068 actor_signals[KEY_RELEASE_EVENT] =
7069 g_signal_new (I_("key-release-event"),
7070 G_TYPE_FROM_CLASS (object_class),
7072 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
7073 _clutter_boolean_handled_accumulator, NULL,
7074 _clutter_marshal_BOOLEAN__BOXED,
7076 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7078 * ClutterActor::motion-event:
7079 * @actor: the actor which received the event
7080 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
7082 * The ::motion-event signal is emitted each time the mouse pointer is
7083 * moved over @actor.
7085 * Return value: %TRUE if the event has been handled by the actor,
7086 * or %FALSE to continue the emission.
7090 actor_signals[MOTION_EVENT] =
7091 g_signal_new (I_("motion-event"),
7092 G_TYPE_FROM_CLASS (object_class),
7094 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
7095 _clutter_boolean_handled_accumulator, NULL,
7096 _clutter_marshal_BOOLEAN__BOXED,
7098 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7101 * ClutterActor::key-focus-in:
7102 * @actor: the actor which now has key focus
7104 * The ::key-focus-in signal is emitted when @actor receives key focus.
7108 actor_signals[KEY_FOCUS_IN] =
7109 g_signal_new (I_("key-focus-in"),
7110 G_TYPE_FROM_CLASS (object_class),
7112 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
7114 _clutter_marshal_VOID__VOID,
7118 * ClutterActor::key-focus-out:
7119 * @actor: the actor which now has key focus
7121 * The ::key-focus-out signal is emitted when @actor loses key focus.
7125 actor_signals[KEY_FOCUS_OUT] =
7126 g_signal_new (I_("key-focus-out"),
7127 G_TYPE_FROM_CLASS (object_class),
7129 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
7131 _clutter_marshal_VOID__VOID,
7135 * ClutterActor::enter-event:
7136 * @actor: the actor which the pointer has entered.
7137 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7139 * The ::enter-event signal is emitted when the pointer enters the @actor
7141 * Return value: %TRUE if the event has been handled by the actor,
7142 * or %FALSE to continue the emission.
7146 actor_signals[ENTER_EVENT] =
7147 g_signal_new (I_("enter-event"),
7148 G_TYPE_FROM_CLASS (object_class),
7150 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
7151 _clutter_boolean_handled_accumulator, NULL,
7152 _clutter_marshal_BOOLEAN__BOXED,
7154 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7157 * ClutterActor::leave-event:
7158 * @actor: the actor which the pointer has left
7159 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7161 * The ::leave-event signal is emitted when the pointer leaves the @actor.
7163 * Return value: %TRUE if the event has been handled by the actor,
7164 * or %FALSE to continue the emission.
7168 actor_signals[LEAVE_EVENT] =
7169 g_signal_new (I_("leave-event"),
7170 G_TYPE_FROM_CLASS (object_class),
7172 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7173 _clutter_boolean_handled_accumulator, NULL,
7174 _clutter_marshal_BOOLEAN__BOXED,
7176 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7179 * ClutterActor::captured-event:
7180 * @actor: the actor which received the signal
7181 * @event: a #ClutterEvent
7183 * The ::captured-event signal is emitted when an event is captured
7184 * by Clutter. This signal will be emitted starting from the top-level
7185 * container (the #ClutterStage) to the actor which received the event
7186 * going down the hierarchy. This signal can be used to intercept every
7187 * event before the specialized events (like
7188 * ClutterActor::button-press-event or ::key-released-event) are
7191 * Return value: %TRUE if the event has been handled by the actor,
7192 * or %FALSE to continue the emission.
7196 actor_signals[CAPTURED_EVENT] =
7197 g_signal_new (I_("captured-event"),
7198 G_TYPE_FROM_CLASS (object_class),
7200 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7201 _clutter_boolean_handled_accumulator, NULL,
7202 _clutter_marshal_BOOLEAN__BOXED,
7204 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7207 * ClutterActor::paint:
7208 * @actor: the #ClutterActor that received the signal
7210 * The ::paint signal is emitted each time an actor is being painted.
7212 * Subclasses of #ClutterActor should override the class signal handler
7213 * and paint themselves in that function.
7215 * It is possible to connect a handler to the ::paint signal in order
7216 * to set up some custom aspect of a paint.
7220 actor_signals[PAINT] =
7221 g_signal_new (I_("paint"),
7222 G_TYPE_FROM_CLASS (object_class),
7225 G_STRUCT_OFFSET (ClutterActorClass, paint),
7227 _clutter_marshal_VOID__VOID,
7230 * ClutterActor::realize:
7231 * @actor: the #ClutterActor that received the signal
7233 * The ::realize signal is emitted each time an actor is being
7238 actor_signals[REALIZE] =
7239 g_signal_new (I_("realize"),
7240 G_TYPE_FROM_CLASS (object_class),
7242 G_STRUCT_OFFSET (ClutterActorClass, realize),
7244 _clutter_marshal_VOID__VOID,
7247 * ClutterActor::unrealize:
7248 * @actor: the #ClutterActor that received the signal
7250 * The ::unrealize signal is emitted each time an actor is being
7255 actor_signals[UNREALIZE] =
7256 g_signal_new (I_("unrealize"),
7257 G_TYPE_FROM_CLASS (object_class),
7259 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7261 _clutter_marshal_VOID__VOID,
7265 * ClutterActor::pick:
7266 * @actor: the #ClutterActor that received the signal
7267 * @color: the #ClutterColor to be used when picking
7269 * The ::pick signal is emitted each time an actor is being painted
7270 * in "pick mode". The pick mode is used to identify the actor during
7271 * the event handling phase, or by clutter_stage_get_actor_at_pos().
7272 * The actor should paint its shape using the passed @pick_color.
7274 * Subclasses of #ClutterActor should override the class signal handler
7275 * and paint themselves in that function.
7277 * It is possible to connect a handler to the ::pick signal in order
7278 * to set up some custom aspect of a paint in pick mode.
7282 actor_signals[PICK] =
7283 g_signal_new (I_("pick"),
7284 G_TYPE_FROM_CLASS (object_class),
7286 G_STRUCT_OFFSET (ClutterActorClass, pick),
7288 _clutter_marshal_VOID__BOXED,
7290 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7293 * ClutterActor::allocation-changed:
7294 * @actor: the #ClutterActor that emitted the signal
7295 * @box: a #ClutterActorBox with the new allocation
7296 * @flags: #ClutterAllocationFlags for the allocation
7298 * The ::allocation-changed signal is emitted when the
7299 * #ClutterActor:allocation property changes. Usually, application
7300 * code should just use the notifications for the :allocation property
7301 * but if you want to track the allocation flags as well, for instance
7302 * to know whether the absolute origin of @actor changed, then you might
7303 * want use this signal instead.
7307 actor_signals[ALLOCATION_CHANGED] =
7308 g_signal_new (I_("allocation-changed"),
7309 G_TYPE_FROM_CLASS (object_class),
7313 _clutter_marshal_VOID__BOXED_FLAGS,
7315 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7316 CLUTTER_TYPE_ALLOCATION_FLAGS);
7319 * ClutterActor::transitions-completed:
7320 * @actor: a #ClutterActor
7322 * The ::transitions-completed signal is emitted once all transitions
7323 * involving @actor are complete.
7327 actor_signals[TRANSITIONS_COMPLETED] =
7328 g_signal_new (I_("transitions-completed"),
7329 G_TYPE_FROM_CLASS (object_class),
7333 _clutter_marshal_VOID__VOID,
7338 clutter_actor_init (ClutterActor *self)
7340 ClutterActorPrivate *priv;
7342 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7344 priv->id = _clutter_context_acquire_id (self);
7347 priv->opacity = 0xff;
7348 priv->show_on_set_parent = TRUE;
7350 priv->needs_width_request = TRUE;
7351 priv->needs_height_request = TRUE;
7352 priv->needs_allocation = TRUE;
7354 priv->cached_width_age = 1;
7355 priv->cached_height_age = 1;
7357 priv->opacity_override = -1;
7358 priv->enable_model_view_transform = TRUE;
7360 /* Initialize an empty paint volume to start with */
7361 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7362 priv->last_paint_volume_valid = TRUE;
7364 priv->transform_valid = FALSE;
7366 /* the default is to stretch the content, to match the
7367 * current behaviour of basically all actors. also, it's
7368 * the easiest thing to compute.
7370 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7371 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7372 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7374 /* this flag will be set to TRUE if the actor gets a child
7375 * or if the [xy]-expand flags are explicitly set; until
7376 * then, the actor does not need to expand.
7378 * this also allows us to avoid computing the expand flag
7379 * when building up a scene.
7381 priv->needs_compute_expand = FALSE;
7385 * clutter_actor_new:
7387 * Creates a new #ClutterActor.
7389 * A newly created actor has a floating reference, which will be sunk
7390 * when it is added to another actor.
7392 * Return value: (transfer full): the newly created #ClutterActor
7397 clutter_actor_new (void)
7399 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7403 * clutter_actor_destroy:
7404 * @self: a #ClutterActor
7406 * Destroys an actor. When an actor is destroyed, it will break any
7407 * references it holds to other objects. If the actor is inside a
7408 * container, the actor will be removed.
7410 * When you destroy a container, its children will be destroyed as well.
7412 * Note: you cannot destroy the #ClutterStage returned by
7413 * clutter_stage_get_default().
7416 clutter_actor_destroy (ClutterActor *self)
7418 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7420 g_object_ref (self);
7422 /* avoid recursion while destroying */
7423 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7425 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7427 g_object_run_dispose (G_OBJECT (self));
7429 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7432 g_object_unref (self);
7436 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7437 ClutterPaintVolume *clip)
7439 ClutterActorPrivate *priv = self->priv;
7440 ClutterPaintVolume *pv;
7443 /* Remove queue entry early in the process, otherwise a new
7444 queue_redraw() during signal handling could put back this
7445 object in the stage redraw list (but the entry is freed as
7446 soon as we return from this function, causing a segfault
7449 priv->queue_redraw_entry = NULL;
7451 /* If we've been explicitly passed a clip volume then there's
7452 * nothing more to calculate, but otherwise the only thing we know
7453 * is that the change is constrained to the given actor.
7455 * The idea is that if we know the paint volume for where the actor
7456 * was last drawn (in eye coordinates) and we also have the paint
7457 * volume for where it will be drawn next (in actor coordinates)
7458 * then if we queue a redraw for both these volumes that will cover
7459 * everything that needs to be redrawn to clear the old view and
7460 * show the latest view of the actor.
7462 * Don't clip this redraw if we don't know what position we had for
7463 * the previous redraw since we don't know where to set the clip so
7464 * it will clear the actor as it is currently.
7468 _clutter_actor_set_queue_redraw_clip (self, clip);
7471 else if (G_LIKELY (priv->last_paint_volume_valid))
7473 pv = _clutter_actor_get_paint_volume_mutable (self);
7476 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7478 /* make sure we redraw the actors old position... */
7479 _clutter_actor_set_queue_redraw_clip (stage,
7480 &priv->last_paint_volume);
7481 _clutter_actor_signal_queue_redraw (stage, stage);
7482 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7484 /* XXX: Ideally the redraw signal would take a clip volume
7485 * argument, but that would be an ABI break. Until we can
7486 * break the ABI we pass the argument out-of-band
7489 /* setup the clip for the actors new position... */
7490 _clutter_actor_set_queue_redraw_clip (self, pv);
7499 _clutter_actor_signal_queue_redraw (self, self);
7501 /* Just in case anyone is manually firing redraw signals without
7502 * using the public queue_redraw() API we are careful to ensure that
7503 * our out-of-band clip member is cleared before returning...
7505 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7507 if (G_LIKELY (clipped))
7508 _clutter_actor_set_queue_redraw_clip (self, NULL);
7512 _clutter_actor_get_allocation_clip (ClutterActor *self,
7513 ClutterActorBox *clip)
7515 ClutterActorBox allocation;
7517 /* XXX: we don't care if we get an out of date allocation here
7518 * because clutter_actor_queue_redraw_with_clip knows to ignore
7519 * the clip if the actor's allocation is invalid.
7521 * This is noted because clutter_actor_get_allocation_box does some
7522 * unnecessary work to support buggy code with a comment suggesting
7523 * that it could be changed later which would be good for this use
7526 clutter_actor_get_allocation_box (self, &allocation);
7528 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7529 * actor's own coordinate space but the allocation is in parent
7533 clip->x2 = allocation.x2 - allocation.x1;
7534 clip->y2 = allocation.y2 - allocation.y1;
7538 _clutter_actor_queue_redraw_full (ClutterActor *self,
7539 ClutterRedrawFlags flags,
7540 ClutterPaintVolume *volume,
7541 ClutterEffect *effect)
7543 ClutterActorPrivate *priv = self->priv;
7544 ClutterPaintVolume allocation_pv;
7545 ClutterPaintVolume *pv;
7546 gboolean should_free_pv;
7547 ClutterActor *stage;
7549 /* Here's an outline of the actor queue redraw mechanism:
7551 * The process starts in one of the following two functions which
7552 * are wrappers for this function:
7553 * clutter_actor_queue_redraw
7554 * _clutter_actor_queue_redraw_with_clip
7556 * additionally, an effect can queue a redraw by wrapping this
7557 * function in clutter_effect_queue_rerun
7559 * This functions queues an entry in a list associated with the
7560 * stage which is a list of actors that queued a redraw while
7561 * updating the timelines, performing layouting and processing other
7562 * mainloop sources before the next paint starts.
7564 * We aim to minimize the processing done at this point because
7565 * there is a good chance other events will happen while updating
7566 * the scenegraph that would invalidate any expensive work we might
7567 * otherwise try to do here. For example we don't try and resolve
7568 * the screen space bounding box of an actor at this stage so as to
7569 * minimize how much of the screen redraw because it's possible
7570 * something else will happen which will force a full redraw anyway.
7572 * When all updates are complete and we come to paint the stage then
7573 * we iterate this list and actually emit the "queue-redraw" signals
7574 * for each of the listed actors which will bubble up to the stage
7575 * for each actor and at that point we will transform the actors
7576 * paint volume into screen coordinates to determine the clip region
7577 * for what needs to be redrawn in the next paint.
7579 * Besides minimizing redundant work another reason for this
7580 * deferred design is that it's more likely we will be able to
7581 * determine the paint volume of an actor once we've finished
7582 * updating the scenegraph because its allocation should be up to
7583 * date. NB: If we can't determine an actors paint volume then we
7584 * can't automatically queue a clipped redraw which can make a big
7585 * difference to performance.
7587 * So the control flow goes like this:
7588 * One of clutter_actor_queue_redraw,
7589 * _clutter_actor_queue_redraw_with_clip
7590 * or clutter_effect_queue_rerun
7592 * then control moves to:
7593 * _clutter_stage_queue_actor_redraw
7595 * later during _clutter_stage_do_update, once relayouting is done
7596 * and the scenegraph has been updated we will call:
7597 * _clutter_stage_finish_queue_redraws
7599 * _clutter_stage_finish_queue_redraws will call
7600 * _clutter_actor_finish_queue_redraw for each listed actor.
7601 * Note: actors *are* allowed to queue further redraws during this
7602 * process (considering clone actors or texture_new_from_actor which
7603 * respond to their source queueing a redraw by queuing a redraw
7604 * themselves). We repeat the process until the list is empty.
7606 * This will result in the "queue-redraw" signal being fired for
7607 * each actor which will pass control to the default signal handler:
7608 * clutter_actor_real_queue_redraw
7610 * This will bubble up to the stages handler:
7611 * clutter_stage_real_queue_redraw
7613 * clutter_stage_real_queue_redraw will transform the actors paint
7614 * volume into screen space and add it as a clip region for the next
7618 /* ignore queueing a redraw for actors being destroyed */
7619 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7622 stage = _clutter_actor_get_stage_internal (self);
7624 /* Ignore queueing a redraw for actors not descended from a stage */
7628 /* ignore queueing a redraw on stages that are being destroyed */
7629 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7632 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7634 ClutterActorBox allocation_clip;
7635 ClutterVertex origin;
7637 /* If the actor doesn't have a valid allocation then we will
7638 * queue a full stage redraw. */
7639 if (priv->needs_allocation)
7641 /* NB: NULL denotes an undefined clip which will result in a
7643 _clutter_actor_set_queue_redraw_clip (self, NULL);
7644 _clutter_actor_signal_queue_redraw (self, self);
7648 _clutter_paint_volume_init_static (&allocation_pv, self);
7649 pv = &allocation_pv;
7651 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7653 origin.x = allocation_clip.x1;
7654 origin.y = allocation_clip.y1;
7656 clutter_paint_volume_set_origin (pv, &origin);
7657 clutter_paint_volume_set_width (pv,
7658 allocation_clip.x2 - allocation_clip.x1);
7659 clutter_paint_volume_set_height (pv,
7660 allocation_clip.y2 -
7661 allocation_clip.y1);
7662 should_free_pv = TRUE;
7667 should_free_pv = FALSE;
7670 self->priv->queue_redraw_entry =
7671 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7672 priv->queue_redraw_entry,
7677 clutter_paint_volume_free (pv);
7679 /* If this is the first redraw queued then we can directly use the
7681 if (!priv->is_dirty)
7682 priv->effect_to_redraw = effect;
7683 /* Otherwise we need to merge it with the existing effect parameter */
7684 else if (effect != NULL)
7686 /* If there's already an effect then we need to use whichever is
7687 later in the chain of actors. Otherwise a full redraw has
7688 already been queued on the actor so we need to ignore the
7690 if (priv->effect_to_redraw != NULL)
7692 if (priv->effects == NULL)
7693 g_warning ("Redraw queued with an effect that is "
7694 "not applied to the actor");
7699 for (l = _clutter_meta_group_peek_metas (priv->effects);
7703 if (l->data == priv->effect_to_redraw ||
7705 priv->effect_to_redraw = l->data;
7712 /* If no effect is specified then we need to redraw the whole
7714 priv->effect_to_redraw = NULL;
7717 priv->is_dirty = TRUE;
7721 * clutter_actor_queue_redraw:
7722 * @self: A #ClutterActor
7724 * Queues up a redraw of an actor and any children. The redraw occurs
7725 * once the main loop becomes idle (after the current batch of events
7726 * has been processed, roughly).
7728 * Applications rarely need to call this, as redraws are handled
7729 * automatically by modification functions.
7731 * This function will not do anything if @self is not visible, or
7732 * if the actor is inside an invisible part of the scenegraph.
7734 * Also be aware that painting is a NOP for actors with an opacity of
7737 * When you are implementing a custom actor you must queue a redraw
7738 * whenever some private state changes that will affect painting or
7739 * picking of your actor.
7742 clutter_actor_queue_redraw (ClutterActor *self)
7744 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7746 _clutter_actor_queue_redraw_full (self,
7748 NULL, /* clip volume */
7753 * _clutter_actor_queue_redraw_with_clip:
7754 * @self: A #ClutterActor
7755 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7756 * this queue redraw.
7757 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7758 * redrawn or %NULL if you are just using a @flag to state your
7761 * Queues up a clipped redraw of an actor and any children. The redraw
7762 * occurs once the main loop becomes idle (after the current batch of
7763 * events has been processed, roughly).
7765 * If no flags are given the clip volume is defined by @volume
7766 * specified in actor coordinates and tells Clutter that only content
7767 * within this volume has been changed so Clutter can optionally
7768 * optimize the redraw.
7770 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7771 * should be %NULL and this tells Clutter to use the actor's current
7772 * allocation as a clip box. This flag can only be used for 2D actors,
7773 * because any actor with depth may be projected outside its
7776 * Applications rarely need to call this, as redraws are handled
7777 * automatically by modification functions.
7779 * This function will not do anything if @self is not visible, or if
7780 * the actor is inside an invisible part of the scenegraph.
7782 * Also be aware that painting is a NOP for actors with an opacity of
7785 * When you are implementing a custom actor you must queue a redraw
7786 * whenever some private state changes that will affect painting or
7787 * picking of your actor.
7790 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7791 ClutterRedrawFlags flags,
7792 ClutterPaintVolume *volume)
7794 _clutter_actor_queue_redraw_full (self,
7796 volume, /* clip volume */
7801 _clutter_actor_queue_only_relayout (ClutterActor *self)
7803 ClutterActorPrivate *priv = self->priv;
7805 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7808 if (priv->needs_width_request &&
7809 priv->needs_height_request &&
7810 priv->needs_allocation)
7811 return; /* save some cpu cycles */
7813 #if CLUTTER_ENABLE_DEBUG
7814 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7816 g_warning ("The actor '%s' is currently inside an allocation "
7817 "cycle; calling clutter_actor_queue_relayout() is "
7819 _clutter_actor_get_debug_name (self));
7821 #endif /* CLUTTER_ENABLE_DEBUG */
7823 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7827 * clutter_actor_queue_redraw_with_clip:
7828 * @self: a #ClutterActor
7829 * @clip: (allow-none): a rectangular clip region, or %NULL
7831 * Queues a redraw on @self limited to a specific, actor-relative
7834 * If @clip is %NULL this function is equivalent to
7835 * clutter_actor_queue_redraw().
7840 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7841 const cairo_rectangle_int_t *clip)
7843 ClutterPaintVolume volume;
7844 ClutterVertex origin;
7846 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7850 clutter_actor_queue_redraw (self);
7854 _clutter_paint_volume_init_static (&volume, self);
7860 clutter_paint_volume_set_origin (&volume, &origin);
7861 clutter_paint_volume_set_width (&volume, clip->width);
7862 clutter_paint_volume_set_height (&volume, clip->height);
7864 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7866 clutter_paint_volume_free (&volume);
7870 * clutter_actor_queue_relayout:
7871 * @self: A #ClutterActor
7873 * Indicates that the actor's size request or other layout-affecting
7874 * properties may have changed. This function is used inside #ClutterActor
7875 * subclass implementations, not by applications directly.
7877 * Queueing a new layout automatically queues a redraw as well.
7882 clutter_actor_queue_relayout (ClutterActor *self)
7884 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7886 _clutter_actor_queue_only_relayout (self);
7887 clutter_actor_queue_redraw (self);
7891 * clutter_actor_get_preferred_size:
7892 * @self: a #ClutterActor
7893 * @min_width_p: (out) (allow-none): return location for the minimum
7895 * @min_height_p: (out) (allow-none): return location for the minimum
7897 * @natural_width_p: (out) (allow-none): return location for the natural
7899 * @natural_height_p: (out) (allow-none): return location for the natural
7902 * Computes the preferred minimum and natural size of an actor, taking into
7903 * account the actor's geometry management (either height-for-width
7904 * or width-for-height).
7906 * The width and height used to compute the preferred height and preferred
7907 * width are the actor's natural ones.
7909 * If you need to control the height for the preferred width, or the width for
7910 * the preferred height, you should use clutter_actor_get_preferred_width()
7911 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7912 * geometry management using the #ClutterActor:request-mode property.
7917 clutter_actor_get_preferred_size (ClutterActor *self,
7918 gfloat *min_width_p,
7919 gfloat *min_height_p,
7920 gfloat *natural_width_p,
7921 gfloat *natural_height_p)
7923 ClutterActorPrivate *priv;
7924 gfloat min_width, min_height;
7925 gfloat natural_width, natural_height;
7927 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7931 min_width = min_height = 0;
7932 natural_width = natural_height = 0;
7934 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7936 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7937 clutter_actor_get_preferred_width (self, -1,
7940 clutter_actor_get_preferred_height (self, natural_width,
7946 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7947 clutter_actor_get_preferred_height (self, -1,
7950 clutter_actor_get_preferred_width (self, natural_height,
7956 *min_width_p = min_width;
7959 *min_height_p = min_height;
7961 if (natural_width_p)
7962 *natural_width_p = natural_width;
7964 if (natural_height_p)
7965 *natural_height_p = natural_height;
7970 * @align: a #ClutterActorAlign
7971 * @direction: a #ClutterTextDirection
7973 * Retrieves the correct alignment depending on the text direction
7975 * Return value: the effective alignment
7977 static ClutterActorAlign
7978 effective_align (ClutterActorAlign align,
7979 ClutterTextDirection direction)
7981 ClutterActorAlign res;
7985 case CLUTTER_ACTOR_ALIGN_START:
7986 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7987 ? CLUTTER_ACTOR_ALIGN_END
7988 : CLUTTER_ACTOR_ALIGN_START;
7991 case CLUTTER_ACTOR_ALIGN_END:
7992 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7993 ? CLUTTER_ACTOR_ALIGN_START
7994 : CLUTTER_ACTOR_ALIGN_END;
8006 * _clutter_actor_get_effective_x_align:
8007 * @self: a #ClutterActor
8009 * Retrieves the effective horizontal alignment, taking into
8010 * consideration the text direction of @self.
8012 * Return value: the effective horizontal alignment
8015 _clutter_actor_get_effective_x_align (ClutterActor *self)
8017 return effective_align (clutter_actor_get_x_align (self),
8018 clutter_actor_get_text_direction (self));
8022 adjust_for_margin (float margin_start,
8024 float *minimum_size,
8025 float *natural_size,
8026 float *allocated_start,
8027 float *allocated_end)
8029 *minimum_size -= (margin_start + margin_end);
8030 *natural_size -= (margin_start + margin_end);
8031 *allocated_start += margin_start;
8032 *allocated_end -= margin_end;
8036 adjust_for_alignment (ClutterActorAlign alignment,
8038 float *allocated_start,
8039 float *allocated_end)
8041 float allocated_size = *allocated_end - *allocated_start;
8045 case CLUTTER_ACTOR_ALIGN_FILL:
8049 case CLUTTER_ACTOR_ALIGN_START:
8051 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
8054 case CLUTTER_ACTOR_ALIGN_END:
8055 if (allocated_size > natural_size)
8057 *allocated_start += (allocated_size - natural_size);
8058 *allocated_end = *allocated_start + natural_size;
8062 case CLUTTER_ACTOR_ALIGN_CENTER:
8063 if (allocated_size > natural_size)
8065 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
8066 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
8073 * clutter_actor_adjust_width:
8074 * @self: a #ClutterActor
8075 * @minimum_width: (inout): the actor's preferred minimum width, which
8076 * will be adjusted depending on the margin
8077 * @natural_width: (inout): the actor's preferred natural width, which
8078 * will be adjusted depending on the margin
8079 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
8080 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
8082 * Adjusts the preferred and allocated position and size of an actor,
8083 * depending on the margin and alignment properties.
8086 clutter_actor_adjust_width (ClutterActor *self,
8087 gfloat *minimum_width,
8088 gfloat *natural_width,
8089 gfloat *adjusted_x1,
8090 gfloat *adjusted_x2)
8092 ClutterTextDirection text_dir;
8093 const ClutterLayoutInfo *info;
8095 info = _clutter_actor_get_layout_info_or_defaults (self);
8096 text_dir = clutter_actor_get_text_direction (self);
8098 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
8100 /* this will tweak natural_width to remove the margin, so that
8101 * adjust_for_alignment() will use the correct size
8103 adjust_for_margin (info->margin.left, info->margin.right,
8104 minimum_width, natural_width,
8105 adjusted_x1, adjusted_x2);
8107 adjust_for_alignment (effective_align (info->x_align, text_dir),
8109 adjusted_x1, adjusted_x2);
8113 * clutter_actor_adjust_height:
8114 * @self: a #ClutterActor
8115 * @minimum_height: (inout): the actor's preferred minimum height, which
8116 * will be adjusted depending on the margin
8117 * @natural_height: (inout): the actor's preferred natural height, which
8118 * will be adjusted depending on the margin
8119 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
8120 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
8122 * Adjusts the preferred and allocated position and size of an actor,
8123 * depending on the margin and alignment properties.
8126 clutter_actor_adjust_height (ClutterActor *self,
8127 gfloat *minimum_height,
8128 gfloat *natural_height,
8129 gfloat *adjusted_y1,
8130 gfloat *adjusted_y2)
8132 const ClutterLayoutInfo *info;
8134 info = _clutter_actor_get_layout_info_or_defaults (self);
8136 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
8138 /* this will tweak natural_height to remove the margin, so that
8139 * adjust_for_alignment() will use the correct size
8141 adjust_for_margin (info->margin.top, info->margin.bottom,
8142 minimum_height, natural_height,
8146 /* we don't use effective_align() here, because text direction
8147 * only affects the horizontal axis
8149 adjust_for_alignment (info->y_align,
8156 /* looks for a cached size request for this for_size. If not
8157 * found, returns the oldest entry so it can be overwritten */
8159 _clutter_actor_get_cached_size_request (gfloat for_size,
8160 SizeRequest *cached_size_requests,
8161 SizeRequest **result)
8165 *result = &cached_size_requests[0];
8167 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
8171 sr = &cached_size_requests[i];
8174 sr->for_size == for_size)
8176 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8180 else if (sr->age < (*result)->age)
8186 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8192 * clutter_actor_get_preferred_width:
8193 * @self: A #ClutterActor
8194 * @for_height: available height when computing the preferred width,
8195 * or a negative value to indicate that no height is defined
8196 * @min_width_p: (out) (allow-none): return location for minimum width,
8198 * @natural_width_p: (out) (allow-none): return location for the natural
8201 * Computes the requested minimum and natural widths for an actor,
8202 * optionally depending on the specified height, or if they are
8203 * already computed, returns the cached values.
8205 * An actor may not get its request - depending on the layout
8206 * manager that's in effect.
8208 * A request should not incorporate the actor's scale or anchor point;
8209 * those transformations do not affect layout, only rendering.
8214 clutter_actor_get_preferred_width (ClutterActor *self,
8216 gfloat *min_width_p,
8217 gfloat *natural_width_p)
8219 float request_min_width, request_natural_width;
8220 SizeRequest *cached_size_request;
8221 const ClutterLayoutInfo *info;
8222 ClutterActorPrivate *priv;
8223 gboolean found_in_cache;
8225 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8229 info = _clutter_actor_get_layout_info_or_defaults (self);
8231 /* we shortcircuit the case of a fixed size set using set_width() */
8232 if (priv->min_width_set && priv->natural_width_set)
8234 if (min_width_p != NULL)
8235 *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8237 if (natural_width_p != NULL)
8238 *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8243 /* the remaining cases are:
8245 * - either min_width or natural_width have been set
8246 * - neither min_width or natural_width have been set
8248 * in both cases, we go through the cache (and through the actor in case
8249 * of cache misses) and determine the authoritative value depending on
8253 if (!priv->needs_width_request)
8256 _clutter_actor_get_cached_size_request (for_height,
8257 priv->width_requests,
8258 &cached_size_request);
8262 /* if the actor needs a width request we use the first slot */
8263 found_in_cache = FALSE;
8264 cached_size_request = &priv->width_requests[0];
8267 if (!found_in_cache)
8269 gfloat minimum_width, natural_width;
8270 ClutterActorClass *klass;
8272 minimum_width = natural_width = 0;
8274 /* adjust for the margin */
8275 if (for_height >= 0)
8277 for_height -= (info->margin.top + info->margin.bottom);
8282 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8284 klass = CLUTTER_ACTOR_GET_CLASS (self);
8285 klass->get_preferred_width (self, for_height,
8289 /* adjust for the margin */
8290 minimum_width += (info->margin.left + info->margin.right);
8291 natural_width += (info->margin.left + info->margin.right);
8293 /* Due to accumulated float errors, it's better not to warn
8294 * on this, but just fix it.
8296 if (natural_width < minimum_width)
8297 natural_width = minimum_width;
8299 cached_size_request->min_size = minimum_width;
8300 cached_size_request->natural_size = natural_width;
8301 cached_size_request->for_size = for_height;
8302 cached_size_request->age = priv->cached_width_age;
8304 priv->cached_width_age += 1;
8305 priv->needs_width_request = FALSE;
8308 if (!priv->min_width_set)
8309 request_min_width = cached_size_request->min_size;
8311 request_min_width = info->margin.left
8312 + info->minimum.width
8313 + info->margin.right;
8315 if (!priv->natural_width_set)
8316 request_natural_width = cached_size_request->natural_size;
8318 request_natural_width = info->margin.left
8319 + info->natural.width
8320 + info->margin.right;
8323 *min_width_p = request_min_width;
8325 if (natural_width_p)
8326 *natural_width_p = request_natural_width;
8330 * clutter_actor_get_preferred_height:
8331 * @self: A #ClutterActor
8332 * @for_width: available width to assume in computing desired height,
8333 * or a negative value to indicate that no width is defined
8334 * @min_height_p: (out) (allow-none): return location for minimum height,
8336 * @natural_height_p: (out) (allow-none): return location for natural
8339 * Computes the requested minimum and natural heights for an actor,
8340 * or if they are already computed, returns the cached values.
8342 * An actor may not get its request - depending on the layout
8343 * manager that's in effect.
8345 * A request should not incorporate the actor's scale or anchor point;
8346 * those transformations do not affect layout, only rendering.
8351 clutter_actor_get_preferred_height (ClutterActor *self,
8353 gfloat *min_height_p,
8354 gfloat *natural_height_p)
8356 float request_min_height, request_natural_height;
8357 SizeRequest *cached_size_request;
8358 const ClutterLayoutInfo *info;
8359 ClutterActorPrivate *priv;
8360 gboolean found_in_cache;
8362 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8366 info = _clutter_actor_get_layout_info_or_defaults (self);
8368 /* we shortcircuit the case of a fixed size set using set_height() */
8369 if (priv->min_height_set && priv->natural_height_set)
8371 if (min_height_p != NULL)
8372 *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8374 if (natural_height_p != NULL)
8375 *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8380 /* the remaining cases are:
8382 * - either min_height or natural_height have been set
8383 * - neither min_height or natural_height have been set
8385 * in both cases, we go through the cache (and through the actor in case
8386 * of cache misses) and determine the authoritative value depending on
8390 if (!priv->needs_height_request)
8393 _clutter_actor_get_cached_size_request (for_width,
8394 priv->height_requests,
8395 &cached_size_request);
8399 found_in_cache = FALSE;
8400 cached_size_request = &priv->height_requests[0];
8403 if (!found_in_cache)
8405 gfloat minimum_height, natural_height;
8406 ClutterActorClass *klass;
8408 minimum_height = natural_height = 0;
8410 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8412 /* adjust for margin */
8415 for_width -= (info->margin.left + info->margin.right);
8420 klass = CLUTTER_ACTOR_GET_CLASS (self);
8421 klass->get_preferred_height (self, for_width,
8425 /* adjust for margin */
8426 minimum_height += (info->margin.top + info->margin.bottom);
8427 natural_height += (info->margin.top + info->margin.bottom);
8429 /* Due to accumulated float errors, it's better not to warn
8430 * on this, but just fix it.
8432 if (natural_height < minimum_height)
8433 natural_height = minimum_height;
8435 cached_size_request->min_size = minimum_height;
8436 cached_size_request->natural_size = natural_height;
8437 cached_size_request->for_size = for_width;
8438 cached_size_request->age = priv->cached_height_age;
8440 priv->cached_height_age += 1;
8441 priv->needs_height_request = FALSE;
8444 if (!priv->min_height_set)
8445 request_min_height = cached_size_request->min_size;
8447 request_min_height = info->margin.top
8448 + info->minimum.height
8449 + info->margin.bottom;
8451 if (!priv->natural_height_set)
8452 request_natural_height = cached_size_request->natural_size;
8454 request_natural_height = info->margin.top
8455 + info->natural.height
8456 + info->margin.bottom;
8459 *min_height_p = request_min_height;
8461 if (natural_height_p)
8462 *natural_height_p = request_natural_height;
8466 * clutter_actor_get_allocation_box:
8467 * @self: A #ClutterActor
8468 * @box: (out): the function fills this in with the actor's allocation
8470 * Gets the layout box an actor has been assigned. The allocation can
8471 * only be assumed valid inside a paint() method; anywhere else, it
8472 * may be out-of-date.
8474 * An allocation does not incorporate the actor's scale or anchor point;
8475 * those transformations do not affect layout, only rendering.
8477 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8478 * of functions inside the implementation of the get_preferred_width()
8479 * or get_preferred_height() virtual functions.</note>
8484 clutter_actor_get_allocation_box (ClutterActor *self,
8485 ClutterActorBox *box)
8487 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8489 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8490 * which limits calling get_allocation to inside paint() basically; or
8491 * we can 2) force a layout, which could be expensive if someone calls
8492 * get_allocation somewhere silly; or we can 3) just return the latest
8493 * value, allowing it to be out-of-date, and assume people know what
8496 * The least-surprises approach that keeps existing code working is
8497 * likely to be 2). People can end up doing some inefficient things,
8498 * though, and in general code that requires 2) is probably broken.
8501 /* this implements 2) */
8502 if (G_UNLIKELY (self->priv->needs_allocation))
8504 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8506 /* do not queue a relayout on an unparented actor */
8508 _clutter_stage_maybe_relayout (stage);
8511 /* commenting out the code above and just keeping this assigment
8514 *box = self->priv->allocation;
8518 * clutter_actor_get_allocation_geometry:
8519 * @self: A #ClutterActor
8520 * @geom: (out): allocation geometry in pixels
8522 * Gets the layout box an actor has been assigned. The allocation can
8523 * only be assumed valid inside a paint() method; anywhere else, it
8524 * may be out-of-date.
8526 * An allocation does not incorporate the actor's scale or anchor point;
8527 * those transformations do not affect layout, only rendering.
8529 * The returned rectangle is in pixels.
8534 clutter_actor_get_allocation_geometry (ClutterActor *self,
8535 ClutterGeometry *geom)
8537 ClutterActorBox box;
8539 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8540 g_return_if_fail (geom != NULL);
8542 clutter_actor_get_allocation_box (self, &box);
8544 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8545 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8546 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8547 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8551 clutter_actor_update_constraints (ClutterActor *self,
8552 ClutterActorBox *allocation)
8554 ClutterActorPrivate *priv = self->priv;
8555 const GList *constraints, *l;
8557 if (priv->constraints == NULL)
8560 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8561 for (l = constraints; l != NULL; l = l->next)
8563 ClutterConstraint *constraint = l->data;
8564 ClutterActorMeta *meta = l->data;
8566 if (clutter_actor_meta_get_enabled (meta))
8568 _clutter_constraint_update_allocation (constraint,
8572 CLUTTER_NOTE (LAYOUT,
8573 "Allocation of '%s' after constraint '%s': "
8574 "{ %.2f, %.2f, %.2f, %.2f }",
8575 _clutter_actor_get_debug_name (self),
8576 _clutter_actor_meta_get_debug_name (meta),
8586 * clutter_actor_adjust_allocation:
8587 * @self: a #ClutterActor
8588 * @allocation: (inout): the allocation to adjust
8590 * Adjusts the passed allocation box taking into account the actor's
8591 * layout information, like alignment, expansion, and margin.
8594 clutter_actor_adjust_allocation (ClutterActor *self,
8595 ClutterActorBox *allocation)
8597 ClutterActorBox adj_allocation;
8598 float alloc_width, alloc_height;
8599 float min_width, min_height;
8600 float nat_width, nat_height;
8601 ClutterRequestMode req_mode;
8603 adj_allocation = *allocation;
8605 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8607 /* we want to hit the cache, so we use the public API */
8608 req_mode = clutter_actor_get_request_mode (self);
8610 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8612 clutter_actor_get_preferred_width (self, -1,
8615 clutter_actor_get_preferred_height (self, alloc_width,
8619 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8621 clutter_actor_get_preferred_height (self, -1,
8624 clutter_actor_get_preferred_height (self, alloc_height,
8629 #ifdef CLUTTER_ENABLE_DEBUG
8630 /* warn about underallocations */
8631 if (_clutter_diagnostic_enabled () &&
8632 (floorf (min_width - alloc_width) > 0 ||
8633 floorf (min_height - alloc_height) > 0))
8635 ClutterActor *parent = clutter_actor_get_parent (self);
8637 /* the only actors that are allowed to be underallocated are the Stage,
8638 * as it doesn't have an implicit size, and Actors that specifically
8639 * told us that they want to opt-out from layout control mechanisms
8640 * through the NO_LAYOUT escape hatch.
8642 if (parent != NULL &&
8643 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8645 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8646 "of %.2f x %.2f from its parent actor '%s', but its "
8647 "requested minimum size is of %.2f x %.2f",
8648 _clutter_actor_get_debug_name (self),
8649 alloc_width, alloc_height,
8650 _clutter_actor_get_debug_name (parent),
8651 min_width, min_height);
8656 clutter_actor_adjust_width (self,
8660 &adj_allocation.x2);
8662 clutter_actor_adjust_height (self,
8666 &adj_allocation.y2);
8668 /* we maintain the invariant that an allocation cannot be adjusted
8669 * to be outside the parent-given box
8671 if (adj_allocation.x1 < allocation->x1 ||
8672 adj_allocation.y1 < allocation->y1 ||
8673 adj_allocation.x2 > allocation->x2 ||
8674 adj_allocation.y2 > allocation->y2)
8676 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8677 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8678 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8679 _clutter_actor_get_debug_name (self),
8680 adj_allocation.x1, adj_allocation.y1,
8681 adj_allocation.x2 - adj_allocation.x1,
8682 adj_allocation.y2 - adj_allocation.y1,
8683 allocation->x1, allocation->y1,
8684 allocation->x2 - allocation->x1,
8685 allocation->y2 - allocation->y1);
8689 *allocation = adj_allocation;
8693 clutter_actor_allocate_internal (ClutterActor *self,
8694 const ClutterActorBox *allocation,
8695 ClutterAllocationFlags flags)
8697 ClutterActorClass *klass;
8699 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8701 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8702 _clutter_actor_get_debug_name (self));
8704 klass = CLUTTER_ACTOR_GET_CLASS (self);
8705 klass->allocate (self, allocation, flags);
8707 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8709 clutter_actor_queue_redraw (self);
8713 * clutter_actor_allocate:
8714 * @self: A #ClutterActor
8715 * @box: new allocation of the actor, in parent-relative coordinates
8716 * @flags: flags that control the allocation
8718 * Called by the parent of an actor to assign the actor its size.
8719 * Should never be called by applications (except when implementing
8720 * a container or layout manager).
8722 * Actors can know from their allocation box whether they have moved
8723 * with respect to their parent actor. The @flags parameter describes
8724 * additional information about the allocation, for instance whether
8725 * the parent has moved with respect to the stage, for example because
8726 * a grandparent's origin has moved.
8731 clutter_actor_allocate (ClutterActor *self,
8732 const ClutterActorBox *box,
8733 ClutterAllocationFlags flags)
8735 ClutterActorBox old_allocation, real_allocation;
8736 gboolean origin_changed, child_moved, size_changed;
8737 gboolean stage_allocation_changed;
8738 ClutterActorPrivate *priv;
8740 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8741 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8743 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8744 "which isn't a descendent of the stage!\n",
8745 self, _clutter_actor_get_debug_name (self));
8751 old_allocation = priv->allocation;
8752 real_allocation = *box;
8754 /* constraints are allowed to modify the allocation only here; we do
8755 * this prior to all the other checks so that we can bail out if the
8756 * allocation did not change
8758 clutter_actor_update_constraints (self, &real_allocation);
8760 /* adjust the allocation depending on the align/margin properties */
8761 clutter_actor_adjust_allocation (self, &real_allocation);
8763 if (real_allocation.x2 < real_allocation.x1 ||
8764 real_allocation.y2 < real_allocation.y1)
8766 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8767 _clutter_actor_get_debug_name (self),
8768 real_allocation.x2 - real_allocation.x1,
8769 real_allocation.y2 - real_allocation.y1);
8772 /* we allow 0-sized actors, but not negative-sized ones */
8773 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8774 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8776 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8778 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8779 real_allocation.y1 != old_allocation.y1);
8781 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8782 real_allocation.y2 != old_allocation.y2);
8784 if (origin_changed || child_moved || size_changed)
8785 stage_allocation_changed = TRUE;
8787 stage_allocation_changed = FALSE;
8789 /* If we get an allocation "out of the blue"
8790 * (we did not queue relayout), then we want to
8791 * ignore it. But if we have needs_allocation set,
8792 * we want to guarantee that allocate() virtual
8793 * method is always called, i.e. that queue_relayout()
8794 * always results in an allocate() invocation on
8797 * The optimization here is to avoid re-allocating
8798 * actors that did not queue relayout and were
8801 if (!priv->needs_allocation && !stage_allocation_changed)
8803 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8807 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8808 * clutter_actor_allocate(), it indicates whether the parent has its
8809 * absolute origin moved; when passed in to ClutterActor::allocate()
8810 * virtual method though, it indicates whether the child has its
8811 * absolute origin moved. So we set it when child_moved is TRUE
8814 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8816 /* store the flags here, so that they can be propagated by the
8819 self->priv->allocation_flags = flags;
8821 if (_clutter_actor_get_transition (self, obj_props[PROP_ALLOCATION]) == NULL)
8823 _clutter_actor_create_transition (self, obj_props[PROP_ALLOCATION],
8828 _clutter_actor_update_transition (self, obj_props[PROP_ALLOCATION],
8833 * clutter_actor_set_allocation:
8834 * @self: a #ClutterActor
8835 * @box: a #ClutterActorBox
8836 * @flags: allocation flags
8838 * Stores the allocation of @self as defined by @box.
8840 * This function can only be called from within the implementation of
8841 * the #ClutterActorClass.allocate() virtual function.
8843 * The allocation should have been adjusted to take into account constraints,
8844 * alignment, and margin properties. If you are implementing a #ClutterActor
8845 * subclass that provides its own layout management policy for its children
8846 * instead of using a #ClutterLayoutManager delegate, you should not call
8847 * this function on the children of @self; instead, you should call
8848 * clutter_actor_allocate(), which will adjust the allocation box for
8851 * This function should only be used by subclasses of #ClutterActor
8852 * that wish to store their allocation but cannot chain up to the
8853 * parent's implementation; the default implementation of the
8854 * #ClutterActorClass.allocate() virtual function will call this
8857 * It is important to note that, while chaining up was the recommended
8858 * behaviour for #ClutterActor subclasses prior to the introduction of
8859 * this function, it is recommended to call clutter_actor_set_allocation()
8862 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8863 * to handle the allocation of its children, this function will call
8864 * the clutter_layout_manager_allocate() function only if the
8865 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8866 * expected that the subclass will call clutter_layout_manager_allocate()
8867 * by itself. For instance, the following code:
8871 * my_actor_allocate (ClutterActor *actor,
8872 * const ClutterActorBox *allocation,
8873 * ClutterAllocationFlags flags)
8875 * ClutterActorBox new_alloc;
8876 * ClutterAllocationFlags new_flags;
8878 * adjust_allocation (allocation, &new_alloc);
8880 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8882 * /* this will use the layout manager set on the actor */
8883 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8887 * is equivalent to this:
8891 * my_actor_allocate (ClutterActor *actor,
8892 * const ClutterActorBox *allocation,
8893 * ClutterAllocationFlags flags)
8895 * ClutterLayoutManager *layout;
8896 * ClutterActorBox new_alloc;
8898 * adjust_allocation (allocation, &new_alloc);
8900 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8902 * layout = clutter_actor_get_layout_manager (actor);
8903 * clutter_layout_manager_allocate (layout,
8904 * CLUTTER_CONTAINER (actor),
8913 clutter_actor_set_allocation (ClutterActor *self,
8914 const ClutterActorBox *box,
8915 ClutterAllocationFlags flags)
8917 ClutterActorPrivate *priv;
8920 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8921 g_return_if_fail (box != NULL);
8923 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8925 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8926 "can only be called from within the implementation of "
8927 "the ClutterActor::allocate() virtual function.");
8933 g_object_freeze_notify (G_OBJECT (self));
8935 changed = clutter_actor_set_allocation_internal (self, box, flags);
8937 /* we allocate our children before we notify changes in our geometry,
8938 * so that people connecting to properties will be able to get valid
8939 * data out of the sub-tree of the scene graph that has this actor at
8942 clutter_actor_maybe_layout_children (self, box, flags);
8946 ClutterActorBox signal_box = priv->allocation;
8947 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8949 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8954 g_object_thaw_notify (G_OBJECT (self));
8958 * clutter_actor_set_geometry:
8959 * @self: A #ClutterActor
8960 * @geometry: A #ClutterGeometry
8962 * Sets the actor's fixed position and forces its minimum and natural
8963 * size, in pixels. This means the untransformed actor will have the
8964 * given geometry. This is the same as calling clutter_actor_set_position()
8965 * and clutter_actor_set_size().
8967 * Deprecated: 1.10: Use clutter_actor_set_position() and
8968 * clutter_actor_set_size() instead.
8971 clutter_actor_set_geometry (ClutterActor *self,
8972 const ClutterGeometry *geometry)
8974 g_object_freeze_notify (G_OBJECT (self));
8976 clutter_actor_set_position (self, geometry->x, geometry->y);
8977 clutter_actor_set_size (self, geometry->width, geometry->height);
8979 g_object_thaw_notify (G_OBJECT (self));
8983 * clutter_actor_get_geometry:
8984 * @self: A #ClutterActor
8985 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8987 * Gets the size and position of an actor relative to its parent
8988 * actor. This is the same as calling clutter_actor_get_position() and
8989 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8990 * requested size and position if the actor's allocation is invalid.
8992 * Deprecated: 1.10: Use clutter_actor_get_position() and
8993 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8997 clutter_actor_get_geometry (ClutterActor *self,
8998 ClutterGeometry *geometry)
9000 gfloat x, y, width, height;
9002 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9003 g_return_if_fail (geometry != NULL);
9005 clutter_actor_get_position (self, &x, &y);
9006 clutter_actor_get_size (self, &width, &height);
9008 geometry->x = (int) x;
9009 geometry->y = (int) y;
9010 geometry->width = (int) width;
9011 geometry->height = (int) height;
9015 * clutter_actor_set_position:
9016 * @self: A #ClutterActor
9017 * @x: New left position of actor in pixels.
9018 * @y: New top position of actor in pixels.
9020 * Sets the actor's fixed position in pixels relative to any parent
9023 * If a layout manager is in use, this position will override the
9024 * layout manager and force a fixed position.
9027 clutter_actor_set_position (ClutterActor *self,
9031 ClutterPoint new_position;
9033 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9035 clutter_point_init (&new_position, x, y);
9037 if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
9039 ClutterPoint cur_position;
9041 cur_position.x = clutter_actor_get_x (self);
9042 cur_position.y = clutter_actor_get_y (self);
9044 _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
9049 _clutter_actor_update_transition (self,
9050 obj_props[PROP_POSITION],
9053 clutter_actor_queue_relayout (self);
9057 * clutter_actor_get_fixed_position_set:
9058 * @self: A #ClutterActor
9060 * Checks whether an actor has a fixed position set (and will thus be
9061 * unaffected by any layout manager).
9063 * Return value: %TRUE if the fixed position is set on the actor
9068 clutter_actor_get_fixed_position_set (ClutterActor *self)
9070 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9072 return self->priv->position_set;
9076 * clutter_actor_set_fixed_position_set:
9077 * @self: A #ClutterActor
9078 * @is_set: whether to use fixed position
9080 * Sets whether an actor has a fixed position set (and will thus be
9081 * unaffected by any layout manager).
9086 clutter_actor_set_fixed_position_set (ClutterActor *self,
9089 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9091 if (self->priv->position_set == (is_set != FALSE))
9094 self->priv->position_set = is_set != FALSE;
9095 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9097 clutter_actor_queue_relayout (self);
9101 * clutter_actor_move_by:
9102 * @self: A #ClutterActor
9103 * @dx: Distance to move Actor on X axis.
9104 * @dy: Distance to move Actor on Y axis.
9106 * Moves an actor by the specified distance relative to its current
9107 * position in pixels.
9109 * This function modifies the fixed position of an actor and thus removes
9110 * it from any layout management. Another way to move an actor is with an
9111 * anchor point, see clutter_actor_set_anchor_point().
9116 clutter_actor_move_by (ClutterActor *self,
9120 const ClutterLayoutInfo *info;
9123 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9125 info = _clutter_actor_get_layout_info_or_defaults (self);
9126 x = info->fixed_pos.x;
9127 y = info->fixed_pos.y;
9129 clutter_actor_set_position (self, x + dx, y + dy);
9133 clutter_actor_set_min_width (ClutterActor *self,
9136 ClutterActorPrivate *priv = self->priv;
9137 ClutterActorBox old = { 0, };
9138 ClutterLayoutInfo *info;
9140 /* if we are setting the size on a top-level actor and the
9141 * backend only supports static top-levels (e.g. framebuffers)
9142 * then we ignore the passed value and we override it with
9143 * the stage implementation's preferred size.
9145 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9146 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9149 info = _clutter_actor_get_layout_info (self);
9151 if (priv->min_width_set && min_width == info->minimum.width)
9154 g_object_freeze_notify (G_OBJECT (self));
9156 clutter_actor_store_old_geometry (self, &old);
9158 info->minimum.width = min_width;
9159 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9160 clutter_actor_set_min_width_set (self, TRUE);
9162 clutter_actor_notify_if_geometry_changed (self, &old);
9164 g_object_thaw_notify (G_OBJECT (self));
9166 clutter_actor_queue_relayout (self);
9170 clutter_actor_set_min_height (ClutterActor *self,
9174 ClutterActorPrivate *priv = self->priv;
9175 ClutterActorBox old = { 0, };
9176 ClutterLayoutInfo *info;
9178 /* if we are setting the size on a top-level actor and the
9179 * backend only supports static top-levels (e.g. framebuffers)
9180 * then we ignore the passed value and we override it with
9181 * the stage implementation's preferred size.
9183 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9184 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9187 info = _clutter_actor_get_layout_info (self);
9189 if (priv->min_height_set && min_height == info->minimum.height)
9192 g_object_freeze_notify (G_OBJECT (self));
9194 clutter_actor_store_old_geometry (self, &old);
9196 info->minimum.height = min_height;
9197 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9198 clutter_actor_set_min_height_set (self, TRUE);
9200 clutter_actor_notify_if_geometry_changed (self, &old);
9202 g_object_thaw_notify (G_OBJECT (self));
9204 clutter_actor_queue_relayout (self);
9208 clutter_actor_set_natural_width (ClutterActor *self,
9209 gfloat natural_width)
9211 ClutterActorPrivate *priv = self->priv;
9212 ClutterActorBox old = { 0, };
9213 ClutterLayoutInfo *info;
9215 /* if we are setting the size on a top-level actor and the
9216 * backend only supports static top-levels (e.g. framebuffers)
9217 * then we ignore the passed value and we override it with
9218 * the stage implementation's preferred size.
9220 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9221 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9224 info = _clutter_actor_get_layout_info (self);
9226 if (priv->natural_width_set && natural_width == info->natural.width)
9229 g_object_freeze_notify (G_OBJECT (self));
9231 clutter_actor_store_old_geometry (self, &old);
9233 info->natural.width = natural_width;
9234 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9235 clutter_actor_set_natural_width_set (self, TRUE);
9237 clutter_actor_notify_if_geometry_changed (self, &old);
9239 g_object_thaw_notify (G_OBJECT (self));
9241 clutter_actor_queue_relayout (self);
9245 clutter_actor_set_natural_height (ClutterActor *self,
9246 gfloat natural_height)
9248 ClutterActorPrivate *priv = self->priv;
9249 ClutterActorBox old = { 0, };
9250 ClutterLayoutInfo *info;
9252 /* if we are setting the size on a top-level actor and the
9253 * backend only supports static top-levels (e.g. framebuffers)
9254 * then we ignore the passed value and we override it with
9255 * the stage implementation's preferred size.
9257 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9258 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9261 info = _clutter_actor_get_layout_info (self);
9263 if (priv->natural_height_set && natural_height == info->natural.height)
9266 g_object_freeze_notify (G_OBJECT (self));
9268 clutter_actor_store_old_geometry (self, &old);
9270 info->natural.height = natural_height;
9271 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9272 clutter_actor_set_natural_height_set (self, TRUE);
9274 clutter_actor_notify_if_geometry_changed (self, &old);
9276 g_object_thaw_notify (G_OBJECT (self));
9278 clutter_actor_queue_relayout (self);
9282 clutter_actor_set_min_width_set (ClutterActor *self,
9283 gboolean use_min_width)
9285 ClutterActorPrivate *priv = self->priv;
9286 ClutterActorBox old = { 0, };
9288 if (priv->min_width_set == (use_min_width != FALSE))
9291 clutter_actor_store_old_geometry (self, &old);
9293 priv->min_width_set = use_min_width != FALSE;
9294 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9296 clutter_actor_notify_if_geometry_changed (self, &old);
9298 clutter_actor_queue_relayout (self);
9302 clutter_actor_set_min_height_set (ClutterActor *self,
9303 gboolean use_min_height)
9305 ClutterActorPrivate *priv = self->priv;
9306 ClutterActorBox old = { 0, };
9308 if (priv->min_height_set == (use_min_height != FALSE))
9311 clutter_actor_store_old_geometry (self, &old);
9313 priv->min_height_set = use_min_height != FALSE;
9314 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9316 clutter_actor_notify_if_geometry_changed (self, &old);
9318 clutter_actor_queue_relayout (self);
9322 clutter_actor_set_natural_width_set (ClutterActor *self,
9323 gboolean use_natural_width)
9325 ClutterActorPrivate *priv = self->priv;
9326 ClutterActorBox old = { 0, };
9328 if (priv->natural_width_set == (use_natural_width != FALSE))
9331 clutter_actor_store_old_geometry (self, &old);
9333 priv->natural_width_set = use_natural_width != FALSE;
9334 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9336 clutter_actor_notify_if_geometry_changed (self, &old);
9338 clutter_actor_queue_relayout (self);
9342 clutter_actor_set_natural_height_set (ClutterActor *self,
9343 gboolean use_natural_height)
9345 ClutterActorPrivate *priv = self->priv;
9346 ClutterActorBox old = { 0, };
9348 if (priv->natural_height_set == (use_natural_height != FALSE))
9351 clutter_actor_store_old_geometry (self, &old);
9353 priv->natural_height_set = use_natural_height != FALSE;
9354 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9356 clutter_actor_notify_if_geometry_changed (self, &old);
9358 clutter_actor_queue_relayout (self);
9362 * clutter_actor_set_request_mode:
9363 * @self: a #ClutterActor
9364 * @mode: the request mode
9366 * Sets the geometry request mode of @self.
9368 * The @mode determines the order for invoking
9369 * clutter_actor_get_preferred_width() and
9370 * clutter_actor_get_preferred_height()
9375 clutter_actor_set_request_mode (ClutterActor *self,
9376 ClutterRequestMode mode)
9378 ClutterActorPrivate *priv;
9380 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9384 if (priv->request_mode == mode)
9387 priv->request_mode = mode;
9389 priv->needs_width_request = TRUE;
9390 priv->needs_height_request = TRUE;
9392 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9394 clutter_actor_queue_relayout (self);
9398 * clutter_actor_get_request_mode:
9399 * @self: a #ClutterActor
9401 * Retrieves the geometry request mode of @self
9403 * Return value: the request mode for the actor
9408 clutter_actor_get_request_mode (ClutterActor *self)
9410 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9411 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9413 return self->priv->request_mode;
9416 /* variant of set_width() without checks and without notification
9417 * freeze+thaw, for internal usage only
9420 clutter_actor_set_width_internal (ClutterActor *self,
9425 /* the Stage will use the :min-width to control the minimum
9426 * width to be resized to, so we should not be setting it
9427 * along with the :natural-width
9429 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9430 clutter_actor_set_min_width (self, width);
9432 clutter_actor_set_natural_width (self, width);
9436 /* we only unset the :natural-width for the Stage */
9437 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9438 clutter_actor_set_min_width_set (self, FALSE);
9440 clutter_actor_set_natural_width_set (self, FALSE);
9444 /* variant of set_height() without checks and without notification
9445 * freeze+thaw, for internal usage only
9448 clutter_actor_set_height_internal (ClutterActor *self,
9453 /* see the comment above in set_width_internal() */
9454 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9455 clutter_actor_set_min_height (self, height);
9457 clutter_actor_set_natural_height (self, height);
9461 /* see the comment above in set_width_internal() */
9462 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9463 clutter_actor_set_min_height_set (self, FALSE);
9465 clutter_actor_set_natural_height_set (self, FALSE);
9470 clutter_actor_set_size_internal (ClutterActor *self,
9471 const ClutterSize *size)
9475 clutter_actor_set_width_internal (self, size->width);
9476 clutter_actor_set_height_internal (self, size->height);
9480 clutter_actor_set_width_internal (self, -1);
9481 clutter_actor_set_height_internal (self, -1);
9486 * clutter_actor_set_size:
9487 * @self: A #ClutterActor
9488 * @width: New width of actor in pixels, or -1
9489 * @height: New height of actor in pixels, or -1
9491 * Sets the actor's size request in pixels. This overrides any
9492 * "normal" size request the actor would have. For example
9493 * a text actor might normally request the size of the text;
9494 * this function would force a specific size instead.
9496 * If @width and/or @height are -1 the actor will use its
9497 * "normal" size request instead of overriding it, i.e.
9498 * you can "unset" the size with -1.
9500 * This function sets or unsets both the minimum and natural size.
9503 clutter_actor_set_size (ClutterActor *self,
9507 ClutterSize new_size;
9509 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9511 clutter_size_init (&new_size, width, height);
9513 if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9515 /* minor optimization: if we don't have a duration then we can
9516 * skip the get_size() below, to avoid the chance of going through
9517 * get_preferred_width() and get_preferred_height() just to jump to
9518 * a new desired size
9520 if (clutter_actor_get_easing_duration (self) == 0)
9522 g_object_freeze_notify (G_OBJECT (self));
9524 clutter_actor_set_size_internal (self, &new_size);
9526 g_object_thaw_notify (G_OBJECT (self));
9532 ClutterSize cur_size;
9534 clutter_size_init (&cur_size,
9535 clutter_actor_get_width (self),
9536 clutter_actor_get_height (self));
9538 _clutter_actor_create_transition (self,
9539 obj_props[PROP_SIZE],
9545 _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9547 clutter_actor_queue_relayout (self);
9551 * clutter_actor_get_size:
9552 * @self: A #ClutterActor
9553 * @width: (out) (allow-none): return location for the width, or %NULL.
9554 * @height: (out) (allow-none): return location for the height, or %NULL.
9556 * This function tries to "do what you mean" and return
9557 * the size an actor will have. If the actor has a valid
9558 * allocation, the allocation will be returned; otherwise,
9559 * the actors natural size request will be returned.
9561 * If you care whether you get the request vs. the allocation, you
9562 * should probably call a different function like
9563 * clutter_actor_get_allocation_box() or
9564 * clutter_actor_get_preferred_width().
9569 clutter_actor_get_size (ClutterActor *self,
9573 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9576 *width = clutter_actor_get_width (self);
9579 *height = clutter_actor_get_height (self);
9583 * clutter_actor_get_position:
9584 * @self: a #ClutterActor
9585 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9586 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9588 * This function tries to "do what you mean" and tell you where the
9589 * actor is, prior to any transformations. Retrieves the fixed
9590 * position of an actor in pixels, if one has been set; otherwise, if
9591 * the allocation is valid, returns the actor's allocated position;
9592 * otherwise, returns 0,0.
9594 * The returned position is in pixels.
9599 clutter_actor_get_position (ClutterActor *self,
9603 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9606 *x = clutter_actor_get_x (self);
9609 *y = clutter_actor_get_y (self);
9613 * clutter_actor_get_transformed_position:
9614 * @self: A #ClutterActor
9615 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9616 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9618 * Gets the absolute position of an actor, in pixels relative to the stage.
9623 clutter_actor_get_transformed_position (ClutterActor *self,
9630 v1.x = v1.y = v1.z = 0;
9631 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9641 * clutter_actor_get_transformed_size:
9642 * @self: A #ClutterActor
9643 * @width: (out) (allow-none): return location for the width, or %NULL
9644 * @height: (out) (allow-none): return location for the height, or %NULL
9646 * Gets the absolute size of an actor in pixels, taking into account the
9649 * If the actor has a valid allocation, the allocated size will be used.
9650 * If the actor has not a valid allocation then the preferred size will
9651 * be transformed and returned.
9653 * If you want the transformed allocation, see
9654 * clutter_actor_get_abs_allocation_vertices() instead.
9656 * <note>When the actor (or one of its ancestors) is rotated around the
9657 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9658 * as a generic quadrangle; in that case this function returns the size
9659 * of the smallest rectangle that encapsulates the entire quad. Please
9660 * note that in this case no assumptions can be made about the relative
9661 * position of this envelope to the absolute position of the actor, as
9662 * returned by clutter_actor_get_transformed_position(); if you need this
9663 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9664 * to get the coords of the actual quadrangle.</note>
9669 clutter_actor_get_transformed_size (ClutterActor *self,
9673 ClutterActorPrivate *priv;
9675 gfloat x_min, x_max, y_min, y_max;
9678 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9682 /* if the actor hasn't been allocated yet, get the preferred
9683 * size and transform that
9685 if (priv->needs_allocation)
9687 gfloat natural_width, natural_height;
9688 ClutterActorBox box;
9690 /* Make a fake allocation to transform.
9692 * NB: _clutter_actor_transform_and_project_box expects a box in
9693 * the actor's coordinate space... */
9698 natural_width = natural_height = 0;
9699 clutter_actor_get_preferred_size (self, NULL, NULL,
9703 box.x2 = natural_width;
9704 box.y2 = natural_height;
9706 _clutter_actor_transform_and_project_box (self, &box, v);
9709 clutter_actor_get_abs_allocation_vertices (self, v);
9711 x_min = x_max = v[0].x;
9712 y_min = y_max = v[0].y;
9714 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9730 *width = x_max - x_min;
9733 *height = y_max - y_min;
9737 * clutter_actor_get_width:
9738 * @self: A #ClutterActor
9740 * Retrieves the width of a #ClutterActor.
9742 * If the actor has a valid allocation, this function will return the
9743 * width of the allocated area given to the actor.
9745 * If the actor does not have a valid allocation, this function will
9746 * return the actor's natural width, that is the preferred width of
9749 * If you care whether you get the preferred width or the width that
9750 * has been assigned to the actor, you should probably call a different
9751 * function like clutter_actor_get_allocation_box() to retrieve the
9752 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9755 * If an actor has a fixed width, for instance a width that has been
9756 * assigned using clutter_actor_set_width(), the width returned will
9757 * be the same value.
9759 * Return value: the width of the actor, in pixels
9762 clutter_actor_get_width (ClutterActor *self)
9764 ClutterActorPrivate *priv;
9766 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9770 if (priv->needs_allocation)
9772 gfloat natural_width = 0;
9774 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9775 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9778 gfloat natural_height = 0;
9780 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9781 clutter_actor_get_preferred_width (self, natural_height,
9786 return natural_width;
9789 return priv->allocation.x2 - priv->allocation.x1;
9793 * clutter_actor_get_height:
9794 * @self: A #ClutterActor
9796 * Retrieves the height of a #ClutterActor.
9798 * If the actor has a valid allocation, this function will return the
9799 * height of the allocated area given to the actor.
9801 * If the actor does not have a valid allocation, this function will
9802 * return the actor's natural height, that is the preferred height of
9805 * If you care whether you get the preferred height or the height that
9806 * has been assigned to the actor, you should probably call a different
9807 * function like clutter_actor_get_allocation_box() to retrieve the
9808 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9811 * If an actor has a fixed height, for instance a height that has been
9812 * assigned using clutter_actor_set_height(), the height returned will
9813 * be the same value.
9815 * Return value: the height of the actor, in pixels
9818 clutter_actor_get_height (ClutterActor *self)
9820 ClutterActorPrivate *priv;
9822 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9826 if (priv->needs_allocation)
9828 gfloat natural_height = 0;
9830 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9832 gfloat natural_width = 0;
9834 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9835 clutter_actor_get_preferred_height (self, natural_width,
9836 NULL, &natural_height);
9839 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9841 return natural_height;
9844 return priv->allocation.y2 - priv->allocation.y1;
9848 * clutter_actor_set_width:
9849 * @self: A #ClutterActor
9850 * @width: Requested new width for the actor, in pixels, or -1
9852 * Forces a width on an actor, causing the actor's preferred width
9853 * and height (if any) to be ignored.
9855 * If @width is -1 the actor will use its preferred width request
9856 * instead of overriding it, i.e. you can "unset" the width with -1.
9858 * This function sets both the minimum and natural size of the actor.
9863 clutter_actor_set_width (ClutterActor *self,
9866 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9868 if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9872 /* minor optimization: if we don't have a duration
9873 * then we can skip the get_width() below, to avoid
9874 * the chance of going through get_preferred_width()
9875 * just to jump to a new desired width.
9877 if (clutter_actor_get_easing_duration (self) == 0)
9879 g_object_freeze_notify (G_OBJECT (self));
9881 clutter_actor_set_width_internal (self, width);
9883 g_object_thaw_notify (G_OBJECT (self));
9888 cur_size = clutter_actor_get_width (self);
9890 _clutter_actor_create_transition (self,
9891 obj_props[PROP_WIDTH],
9896 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9900 * clutter_actor_set_height:
9901 * @self: A #ClutterActor
9902 * @height: Requested new height for the actor, in pixels, or -1
9904 * Forces a height on an actor, causing the actor's preferred width
9905 * and height (if any) to be ignored.
9907 * If @height is -1 the actor will use its preferred height instead of
9908 * overriding it, i.e. you can "unset" the height with -1.
9910 * This function sets both the minimum and natural size of the actor.
9915 clutter_actor_set_height (ClutterActor *self,
9918 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9920 if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9924 /* see the comment in clutter_actor_set_width() above */
9925 if (clutter_actor_get_easing_duration (self) == 0)
9927 g_object_freeze_notify (G_OBJECT (self));
9929 clutter_actor_set_height_internal (self, height);
9931 g_object_thaw_notify (G_OBJECT (self));
9936 cur_size = clutter_actor_get_height (self);
9938 _clutter_actor_create_transition (self,
9939 obj_props[PROP_HEIGHT],
9944 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9948 clutter_actor_set_x_internal (ClutterActor *self,
9951 ClutterActorPrivate *priv = self->priv;
9952 ClutterLayoutInfo *linfo;
9953 ClutterActorBox old = { 0, };
9955 linfo = _clutter_actor_get_layout_info (self);
9957 if (priv->position_set && linfo->fixed_pos.x == x)
9960 clutter_actor_store_old_geometry (self, &old);
9962 linfo->fixed_pos.x = x;
9963 clutter_actor_set_fixed_position_set (self, TRUE);
9965 clutter_actor_notify_if_geometry_changed (self, &old);
9967 clutter_actor_queue_relayout (self);
9971 clutter_actor_set_y_internal (ClutterActor *self,
9974 ClutterActorPrivate *priv = self->priv;
9975 ClutterLayoutInfo *linfo;
9976 ClutterActorBox old = { 0, };
9978 linfo = _clutter_actor_get_layout_info (self);
9980 if (priv->position_set && linfo->fixed_pos.y == y)
9983 clutter_actor_store_old_geometry (self, &old);
9985 linfo->fixed_pos.y = y;
9986 clutter_actor_set_fixed_position_set (self, TRUE);
9988 clutter_actor_notify_if_geometry_changed (self, &old);
9990 clutter_actor_queue_relayout (self);
9994 clutter_actor_set_position_internal (ClutterActor *self,
9995 const ClutterPoint *position)
9997 ClutterActorPrivate *priv = self->priv;
9998 ClutterLayoutInfo *linfo;
9999 ClutterActorBox old = { 0, };
10001 linfo = _clutter_actor_get_layout_info (self);
10003 if (priv->position_set &&
10004 clutter_point_equals (position, &linfo->fixed_pos))
10007 clutter_actor_store_old_geometry (self, &old);
10009 if (position != NULL)
10011 linfo->fixed_pos = *position;
10012 clutter_actor_set_fixed_position_set (self, TRUE);
10015 clutter_actor_set_fixed_position_set (self, FALSE);
10017 clutter_actor_notify_if_geometry_changed (self, &old);
10019 clutter_actor_queue_relayout (self);
10023 * clutter_actor_set_x:
10024 * @self: a #ClutterActor
10025 * @x: the actor's position on the X axis
10027 * Sets the actor's X coordinate, relative to its parent, in pixels.
10029 * Overrides any layout manager and forces a fixed position for
10032 * The #ClutterActor:x property is animatable.
10037 clutter_actor_set_x (ClutterActor *self,
10040 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10042 if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
10044 float cur_position = clutter_actor_get_x (self);
10046 _clutter_actor_create_transition (self, obj_props[PROP_X],
10051 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
10055 * clutter_actor_set_y:
10056 * @self: a #ClutterActor
10057 * @y: the actor's position on the Y axis
10059 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
10061 * Overrides any layout manager and forces a fixed position for
10064 * The #ClutterActor:y property is animatable.
10069 clutter_actor_set_y (ClutterActor *self,
10072 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10074 if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
10076 float cur_position = clutter_actor_get_y (self);
10078 _clutter_actor_create_transition (self, obj_props[PROP_Y],
10083 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
10087 * clutter_actor_get_x:
10088 * @self: A #ClutterActor
10090 * Retrieves the X coordinate of a #ClutterActor.
10092 * This function tries to "do what you mean", by returning the
10093 * correct value depending on the actor's state.
10095 * If the actor has a valid allocation, this function will return
10096 * the X coordinate of the origin of the allocation box.
10098 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10099 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10100 * function will return that coordinate.
10102 * If both the allocation and a fixed position are missing, this function
10105 * Return value: the X coordinate, in pixels, ignoring any
10106 * transformation (i.e. scaling, rotation)
10109 clutter_actor_get_x (ClutterActor *self)
10111 ClutterActorPrivate *priv;
10113 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10117 if (priv->needs_allocation)
10119 if (priv->position_set)
10121 const ClutterLayoutInfo *info;
10123 info = _clutter_actor_get_layout_info_or_defaults (self);
10125 return info->fixed_pos.x;
10131 return priv->allocation.x1;
10135 * clutter_actor_get_y:
10136 * @self: A #ClutterActor
10138 * Retrieves the Y coordinate of a #ClutterActor.
10140 * This function tries to "do what you mean", by returning the
10141 * correct value depending on the actor's state.
10143 * If the actor has a valid allocation, this function will return
10144 * the Y coordinate of the origin of the allocation box.
10146 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10147 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10148 * function will return that coordinate.
10150 * If both the allocation and a fixed position are missing, this function
10153 * Return value: the Y coordinate, in pixels, ignoring any
10154 * transformation (i.e. scaling, rotation)
10157 clutter_actor_get_y (ClutterActor *self)
10159 ClutterActorPrivate *priv;
10161 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10165 if (priv->needs_allocation)
10167 if (priv->position_set)
10169 const ClutterLayoutInfo *info;
10171 info = _clutter_actor_get_layout_info_or_defaults (self);
10173 return info->fixed_pos.y;
10179 return priv->allocation.y1;
10183 * clutter_actor_set_scale:
10184 * @self: A #ClutterActor
10185 * @scale_x: double factor to scale actor by horizontally.
10186 * @scale_y: double factor to scale actor by vertically.
10188 * Scales an actor with the given factors. The scaling is relative to
10189 * the scale center and the anchor point. The scale center is
10190 * unchanged by this function and defaults to 0,0.
10192 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10198 clutter_actor_set_scale (ClutterActor *self,
10202 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10204 g_object_freeze_notify (G_OBJECT (self));
10206 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10207 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10209 g_object_thaw_notify (G_OBJECT (self));
10213 * clutter_actor_set_scale_full:
10214 * @self: A #ClutterActor
10215 * @scale_x: double factor to scale actor by horizontally.
10216 * @scale_y: double factor to scale actor by vertically.
10217 * @center_x: X coordinate of the center of the scale.
10218 * @center_y: Y coordinate of the center of the scale
10220 * Scales an actor with the given factors around the given center
10221 * point. The center point is specified in pixels relative to the
10222 * anchor point (usually the top left corner of the actor).
10224 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10230 clutter_actor_set_scale_full (ClutterActor *self,
10236 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10238 g_object_freeze_notify (G_OBJECT (self));
10240 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10241 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10242 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10243 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10245 g_object_thaw_notify (G_OBJECT (self));
10249 * clutter_actor_set_scale_with_gravity:
10250 * @self: A #ClutterActor
10251 * @scale_x: double factor to scale actor by horizontally.
10252 * @scale_y: double factor to scale actor by vertically.
10253 * @gravity: the location of the scale center expressed as a compass
10256 * Scales an actor with the given factors around the given
10257 * center point. The center point is specified as one of the compass
10258 * directions in #ClutterGravity. For example, setting it to north
10259 * will cause the top of the actor to remain unchanged and the rest of
10260 * the actor to expand left, right and downwards.
10262 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10268 clutter_actor_set_scale_with_gravity (ClutterActor *self,
10271 ClutterGravity gravity)
10273 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10275 g_object_freeze_notify (G_OBJECT (self));
10277 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10278 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10279 clutter_actor_set_scale_gravity (self, gravity);
10281 g_object_thaw_notify (G_OBJECT (self));
10285 * clutter_actor_get_scale:
10286 * @self: A #ClutterActor
10287 * @scale_x: (out) (allow-none): Location to store horizonal
10288 * scale factor, or %NULL.
10289 * @scale_y: (out) (allow-none): Location to store vertical
10290 * scale factor, or %NULL.
10292 * Retrieves an actors scale factors.
10297 clutter_actor_get_scale (ClutterActor *self,
10301 const ClutterTransformInfo *info;
10303 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10305 info = _clutter_actor_get_transform_info_or_defaults (self);
10308 *scale_x = info->scale_x;
10311 *scale_y = info->scale_y;
10315 * clutter_actor_get_scale_center:
10316 * @self: A #ClutterActor
10317 * @center_x: (out) (allow-none): Location to store the X position
10318 * of the scale center, or %NULL.
10319 * @center_y: (out) (allow-none): Location to store the Y position
10320 * of the scale center, or %NULL.
10322 * Retrieves the scale center coordinate in pixels relative to the top
10323 * left corner of the actor. If the scale center was specified using a
10324 * #ClutterGravity this will calculate the pixel offset using the
10325 * current size of the actor.
10330 clutter_actor_get_scale_center (ClutterActor *self,
10334 const ClutterTransformInfo *info;
10336 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10338 info = _clutter_actor_get_transform_info_or_defaults (self);
10340 clutter_anchor_coord_get_units (self, &info->scale_center,
10347 * clutter_actor_get_scale_gravity:
10348 * @self: A #ClutterActor
10350 * Retrieves the scale center as a compass direction. If the scale
10351 * center was specified in pixels or units this will return
10352 * %CLUTTER_GRAVITY_NONE.
10354 * Return value: the scale gravity
10359 clutter_actor_get_scale_gravity (ClutterActor *self)
10361 const ClutterTransformInfo *info;
10363 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10365 info = _clutter_actor_get_transform_info_or_defaults (self);
10367 return clutter_anchor_coord_get_gravity (&info->scale_center);
10371 clutter_actor_set_opacity_internal (ClutterActor *self,
10374 ClutterActorPrivate *priv = self->priv;
10376 if (priv->opacity != opacity)
10378 priv->opacity = opacity;
10380 /* Queue a redraw from the flatten effect so that it can use
10381 its cached image if available instead of having to redraw the
10382 actual actor. If it doesn't end up using the FBO then the
10383 effect is still able to continue the paint anyway. If there
10384 is no flatten effect yet then this is equivalent to queueing
10386 _clutter_actor_queue_redraw_full (self,
10389 priv->flatten_effect);
10391 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10396 * clutter_actor_set_opacity:
10397 * @self: A #ClutterActor
10398 * @opacity: New opacity value for the actor.
10400 * Sets the actor's opacity, with zero being completely transparent and
10401 * 255 (0xff) being fully opaque.
10403 * The #ClutterActor:opacity property is animatable.
10406 clutter_actor_set_opacity (ClutterActor *self,
10409 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10411 if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10413 _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10414 self->priv->opacity,
10418 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10422 * clutter_actor_get_paint_opacity_internal:
10423 * @self: a #ClutterActor
10425 * Retrieves the absolute opacity of the actor, as it appears on the stage
10427 * This function does not do type checks
10429 * Return value: the absolute opacity of the actor
10432 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10434 ClutterActorPrivate *priv = self->priv;
10435 ClutterActor *parent;
10437 /* override the top-level opacity to always be 255; even in
10438 * case of ClutterStage:use-alpha being TRUE we want the rest
10439 * of the scene to be painted
10441 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10444 if (priv->opacity_override >= 0)
10445 return priv->opacity_override;
10447 parent = priv->parent;
10449 /* Factor in the actual actors opacity with parents */
10450 if (parent != NULL)
10452 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10454 if (opacity != 0xff)
10455 return (opacity * priv->opacity) / 0xff;
10458 return priv->opacity;
10463 * clutter_actor_get_paint_opacity:
10464 * @self: A #ClutterActor
10466 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10468 * This function traverses the hierarchy chain and composites the opacity of
10469 * the actor with that of its parents.
10471 * This function is intended for subclasses to use in the paint virtual
10472 * function, to paint themselves with the correct opacity.
10474 * Return value: The actor opacity value.
10479 clutter_actor_get_paint_opacity (ClutterActor *self)
10481 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10483 return clutter_actor_get_paint_opacity_internal (self);
10487 * clutter_actor_get_opacity:
10488 * @self: a #ClutterActor
10490 * Retrieves the opacity value of an actor, as set by
10491 * clutter_actor_set_opacity().
10493 * For retrieving the absolute opacity of the actor inside a paint
10494 * virtual function, see clutter_actor_get_paint_opacity().
10496 * Return value: the opacity of the actor
10499 clutter_actor_get_opacity (ClutterActor *self)
10501 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10503 return self->priv->opacity;
10507 * clutter_actor_set_offscreen_redirect:
10508 * @self: A #ClutterActor
10509 * @redirect: New offscreen redirect flags for the actor.
10511 * Defines the circumstances where the actor should be redirected into
10512 * an offscreen image. The offscreen image is used to flatten the
10513 * actor into a single image while painting for two main reasons.
10514 * Firstly, when the actor is painted a second time without any of its
10515 * contents changing it can simply repaint the cached image without
10516 * descending further down the actor hierarchy. Secondly, it will make
10517 * the opacity look correct even if there are overlapping primitives
10520 * Caching the actor could in some cases be a performance win and in
10521 * some cases be a performance lose so it is important to determine
10522 * which value is right for an actor before modifying this value. For
10523 * example, there is never any reason to flatten an actor that is just
10524 * a single texture (such as a #ClutterTexture) because it is
10525 * effectively already cached in an image so the offscreen would be
10526 * redundant. Also if the actor contains primitives that are far apart
10527 * with a large transparent area in the middle (such as a large
10528 * CluterGroup with a small actor in the top left and a small actor in
10529 * the bottom right) then the cached image will contain the entire
10530 * image of the large area and the paint will waste time blending all
10531 * of the transparent pixels in the middle.
10533 * The default method of implementing opacity on a container simply
10534 * forwards on the opacity to all of the children. If the children are
10535 * overlapping then it will appear as if they are two separate glassy
10536 * objects and there will be a break in the color where they
10537 * overlap. By redirecting to an offscreen buffer it will be as if the
10538 * two opaque objects are combined into one and then made transparent
10539 * which is usually what is expected.
10541 * The image below demonstrates the difference between redirecting and
10542 * not. The image shows two Clutter groups, each containing a red and
10543 * a green rectangle which overlap. The opacity on the group is set to
10544 * 128 (which is 50%). When the offscreen redirect is not used, the
10545 * red rectangle can be seen through the blue rectangle as if the two
10546 * rectangles were separately transparent. When the redirect is used
10547 * the group as a whole is transparent instead so the red rectangle is
10548 * not visible where they overlap.
10550 * <figure id="offscreen-redirect">
10551 * <title>Sample of using an offscreen redirect for transparency</title>
10552 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10555 * The default value for this property is 0, so we effectively will
10556 * never redirect an actor offscreen by default. This means that there
10557 * are times that transparent actors may look glassy as described
10558 * above. The reason this is the default is because there is a
10559 * performance trade off between quality and performance here. In many
10560 * cases the default form of glassy opacity looks good enough, but if
10561 * it's not you will need to set the
10562 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10563 * redirection for opacity.
10565 * Custom actors that don't contain any overlapping primitives are
10566 * recommended to override the has_overlaps() virtual to return %FALSE
10567 * for maximum efficiency.
10572 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10573 ClutterOffscreenRedirect redirect)
10575 ClutterActorPrivate *priv;
10577 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10581 if (priv->offscreen_redirect != redirect)
10583 priv->offscreen_redirect = redirect;
10585 /* Queue a redraw from the effect so that it can use its cached
10586 image if available instead of having to redraw the actual
10587 actor. If it doesn't end up using the FBO then the effect is
10588 still able to continue the paint anyway. If there is no
10589 effect then this is equivalent to queuing a full redraw */
10590 _clutter_actor_queue_redraw_full (self,
10593 priv->flatten_effect);
10595 g_object_notify_by_pspec (G_OBJECT (self),
10596 obj_props[PROP_OFFSCREEN_REDIRECT]);
10601 * clutter_actor_get_offscreen_redirect:
10602 * @self: a #ClutterActor
10604 * Retrieves whether to redirect the actor to an offscreen buffer, as
10605 * set by clutter_actor_set_offscreen_redirect().
10607 * Return value: the value of the offscreen-redirect property of the actor
10611 ClutterOffscreenRedirect
10612 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10614 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10616 return self->priv->offscreen_redirect;
10620 * clutter_actor_set_name:
10621 * @self: A #ClutterActor
10622 * @name: Textual tag to apply to actor
10624 * Sets the given name to @self. The name can be used to identify
10628 clutter_actor_set_name (ClutterActor *self,
10631 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10633 g_free (self->priv->name);
10634 self->priv->name = g_strdup (name);
10636 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10640 * clutter_actor_get_name:
10641 * @self: A #ClutterActor
10643 * Retrieves the name of @self.
10645 * Return value: the name of the actor, or %NULL. The returned string is
10646 * owned by the actor and should not be modified or freed.
10649 clutter_actor_get_name (ClutterActor *self)
10651 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10653 return self->priv->name;
10657 * clutter_actor_get_gid:
10658 * @self: A #ClutterActor
10660 * Retrieves the unique id for @self.
10662 * Return value: Globally unique value for this object instance.
10666 * Deprecated: 1.8: The id is not used any longer.
10669 clutter_actor_get_gid (ClutterActor *self)
10671 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10673 return self->priv->id;
10677 clutter_actor_set_depth_internal (ClutterActor *self,
10680 ClutterTransformInfo *info;
10682 info = _clutter_actor_get_transform_info (self);
10684 if (info->depth != depth)
10686 /* Sets Z value - XXX 2.0: should we invert? */
10687 info->depth = depth;
10689 self->priv->transform_valid = FALSE;
10691 /* FIXME - remove this crap; sadly, there are still containers
10692 * in Clutter that depend on this utter brain damage
10694 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10696 clutter_actor_queue_redraw (self);
10698 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10703 * clutter_actor_set_depth:
10704 * @self: a #ClutterActor
10707 * Sets the Z coordinate of @self to @depth.
10709 * The unit used by @depth is dependant on the perspective setup. See
10710 * also clutter_stage_set_perspective().
10713 clutter_actor_set_depth (ClutterActor *self,
10716 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10718 if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10720 const ClutterTransformInfo *info;
10722 info = _clutter_actor_get_transform_info_or_defaults (self);
10724 _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10729 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10731 clutter_actor_queue_redraw (self);
10735 * clutter_actor_get_depth:
10736 * @self: a #ClutterActor
10738 * Retrieves the depth of @self.
10740 * Return value: the depth of the actor
10743 clutter_actor_get_depth (ClutterActor *self)
10745 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10747 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10751 * clutter_actor_set_rotation:
10752 * @self: a #ClutterActor
10753 * @axis: the axis of rotation
10754 * @angle: the angle of rotation
10755 * @x: X coordinate of the rotation center
10756 * @y: Y coordinate of the rotation center
10757 * @z: Z coordinate of the rotation center
10759 * Sets the rotation angle of @self around the given axis.
10761 * The rotation center coordinates used depend on the value of @axis:
10763 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10764 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10765 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10768 * The rotation coordinates are relative to the anchor point of the
10769 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10770 * point is set, the upper left corner is assumed as the origin.
10775 clutter_actor_set_rotation (ClutterActor *self,
10776 ClutterRotateAxis axis,
10784 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10790 g_object_freeze_notify (G_OBJECT (self));
10792 clutter_actor_set_rotation_angle (self, axis, angle);
10793 clutter_actor_set_rotation_center_internal (self, axis, &v);
10795 g_object_thaw_notify (G_OBJECT (self));
10799 * clutter_actor_set_z_rotation_from_gravity:
10800 * @self: a #ClutterActor
10801 * @angle: the angle of rotation
10802 * @gravity: the center point of the rotation
10804 * Sets the rotation angle of @self around the Z axis using the center
10805 * point specified as a compass point. For example to rotate such that
10806 * the center of the actor remains static you can use
10807 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10808 * will move accordingly.
10813 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10815 ClutterGravity gravity)
10817 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10819 if (gravity == CLUTTER_GRAVITY_NONE)
10820 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10823 GObject *obj = G_OBJECT (self);
10824 ClutterTransformInfo *info;
10826 info = _clutter_actor_get_transform_info (self);
10828 g_object_freeze_notify (obj);
10830 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10832 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10833 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10834 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10836 g_object_thaw_notify (obj);
10841 * clutter_actor_get_rotation:
10842 * @self: a #ClutterActor
10843 * @axis: the axis of rotation
10844 * @x: (out): return value for the X coordinate of the center of rotation
10845 * @y: (out): return value for the Y coordinate of the center of rotation
10846 * @z: (out): return value for the Z coordinate of the center of rotation
10848 * Retrieves the angle and center of rotation on the given axis,
10849 * set using clutter_actor_set_rotation().
10851 * Return value: the angle of rotation
10856 clutter_actor_get_rotation (ClutterActor *self,
10857 ClutterRotateAxis axis,
10862 const ClutterTransformInfo *info;
10863 const AnchorCoord *anchor_coord;
10864 gdouble retval = 0;
10866 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10868 info = _clutter_actor_get_transform_info_or_defaults (self);
10872 case CLUTTER_X_AXIS:
10873 anchor_coord = &info->rx_center;
10874 retval = info->rx_angle;
10877 case CLUTTER_Y_AXIS:
10878 anchor_coord = &info->ry_center;
10879 retval = info->ry_angle;
10882 case CLUTTER_Z_AXIS:
10883 anchor_coord = &info->rz_center;
10884 retval = info->rz_angle;
10888 anchor_coord = NULL;
10893 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10899 * clutter_actor_get_z_rotation_gravity:
10900 * @self: A #ClutterActor
10902 * Retrieves the center for the rotation around the Z axis as a
10903 * compass direction. If the center was specified in pixels or units
10904 * this will return %CLUTTER_GRAVITY_NONE.
10906 * Return value: the Z rotation center
10911 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10913 const ClutterTransformInfo *info;
10915 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10917 info = _clutter_actor_get_transform_info_or_defaults (self);
10919 return clutter_anchor_coord_get_gravity (&info->rz_center);
10923 * clutter_actor_set_clip:
10924 * @self: A #ClutterActor
10925 * @xoff: X offset of the clip rectangle
10926 * @yoff: Y offset of the clip rectangle
10927 * @width: Width of the clip rectangle
10928 * @height: Height of the clip rectangle
10930 * Sets clip area for @self. The clip area is always computed from the
10931 * upper left corner of the actor, even if the anchor point is set
10937 clutter_actor_set_clip (ClutterActor *self,
10943 ClutterActorPrivate *priv;
10945 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10949 if (priv->has_clip &&
10950 priv->clip.x == xoff &&
10951 priv->clip.y == yoff &&
10952 priv->clip.width == width &&
10953 priv->clip.height == height)
10956 priv->clip.x = xoff;
10957 priv->clip.y = yoff;
10958 priv->clip.width = width;
10959 priv->clip.height = height;
10961 priv->has_clip = TRUE;
10963 clutter_actor_queue_redraw (self);
10965 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10966 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10970 * clutter_actor_remove_clip:
10971 * @self: A #ClutterActor
10973 * Removes clip area from @self.
10976 clutter_actor_remove_clip (ClutterActor *self)
10978 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10980 if (!self->priv->has_clip)
10983 self->priv->has_clip = FALSE;
10985 clutter_actor_queue_redraw (self);
10987 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10991 * clutter_actor_has_clip:
10992 * @self: a #ClutterActor
10994 * Determines whether the actor has a clip area set or not.
10996 * Return value: %TRUE if the actor has a clip area set.
11001 clutter_actor_has_clip (ClutterActor *self)
11003 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11005 return self->priv->has_clip;
11009 * clutter_actor_get_clip:
11010 * @self: a #ClutterActor
11011 * @xoff: (out) (allow-none): return location for the X offset of
11012 * the clip rectangle, or %NULL
11013 * @yoff: (out) (allow-none): return location for the Y offset of
11014 * the clip rectangle, or %NULL
11015 * @width: (out) (allow-none): return location for the width of
11016 * the clip rectangle, or %NULL
11017 * @height: (out) (allow-none): return location for the height of
11018 * the clip rectangle, or %NULL
11020 * Gets the clip area for @self, if any is set
11025 clutter_actor_get_clip (ClutterActor *self,
11031 ClutterActorPrivate *priv;
11033 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11037 if (!priv->has_clip)
11041 *xoff = priv->clip.x;
11044 *yoff = priv->clip.y;
11047 *width = priv->clip.width;
11049 if (height != NULL)
11050 *height = priv->clip.height;
11054 * clutter_actor_get_children:
11055 * @self: a #ClutterActor
11057 * Retrieves the list of children of @self.
11059 * Return value: (transfer container) (element-type ClutterActor): A newly
11060 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
11066 clutter_actor_get_children (ClutterActor *self)
11068 ClutterActor *iter;
11071 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11073 /* we walk the list backward so that we can use prepend(),
11076 for (iter = self->priv->last_child, res = NULL;
11078 iter = iter->priv->prev_sibling)
11080 res = g_list_prepend (res, iter);
11087 * insert_child_at_depth:
11088 * @self: a #ClutterActor
11089 * @child: a #ClutterActor
11091 * Inserts @child inside the list of children held by @self, using
11092 * the depth as the insertion criteria.
11094 * This sadly makes the insertion not O(1), but we can keep the
11095 * list sorted so that the painters algorithm we use for painting
11096 * the children will work correctly.
11099 insert_child_at_depth (ClutterActor *self,
11100 ClutterActor *child,
11101 gpointer dummy G_GNUC_UNUSED)
11103 ClutterActor *iter;
11106 child->priv->parent = self;
11109 _clutter_actor_get_transform_info_or_defaults (child)->depth;
11111 /* special-case the first child */
11112 if (self->priv->n_children == 0)
11114 self->priv->first_child = child;
11115 self->priv->last_child = child;
11117 child->priv->next_sibling = NULL;
11118 child->priv->prev_sibling = NULL;
11123 /* Find the right place to insert the child so that it will still be
11124 sorted and the child will be after all of the actors at the same
11126 for (iter = self->priv->first_child;
11128 iter = iter->priv->next_sibling)
11133 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11135 if (iter_depth > child_depth)
11141 ClutterActor *tmp = iter->priv->prev_sibling;
11144 tmp->priv->next_sibling = child;
11146 /* Insert the node before the found one */
11147 child->priv->prev_sibling = iter->priv->prev_sibling;
11148 child->priv->next_sibling = iter;
11149 iter->priv->prev_sibling = child;
11153 ClutterActor *tmp = self->priv->last_child;
11156 tmp->priv->next_sibling = child;
11158 /* insert the node at the end of the list */
11159 child->priv->prev_sibling = self->priv->last_child;
11160 child->priv->next_sibling = NULL;
11163 if (child->priv->prev_sibling == NULL)
11164 self->priv->first_child = child;
11166 if (child->priv->next_sibling == NULL)
11167 self->priv->last_child = child;
11171 insert_child_at_index (ClutterActor *self,
11172 ClutterActor *child,
11175 gint index_ = GPOINTER_TO_INT (data_);
11177 child->priv->parent = self;
11181 ClutterActor *tmp = self->priv->first_child;
11184 tmp->priv->prev_sibling = child;
11186 child->priv->prev_sibling = NULL;
11187 child->priv->next_sibling = tmp;
11189 else if (index_ < 0 || index_ >= self->priv->n_children)
11191 ClutterActor *tmp = self->priv->last_child;
11194 tmp->priv->next_sibling = child;
11196 child->priv->prev_sibling = tmp;
11197 child->priv->next_sibling = NULL;
11201 ClutterActor *iter;
11204 for (iter = self->priv->first_child, i = 0;
11206 iter = iter->priv->next_sibling, i += 1)
11210 ClutterActor *tmp = iter->priv->prev_sibling;
11212 child->priv->prev_sibling = tmp;
11213 child->priv->next_sibling = iter;
11215 iter->priv->prev_sibling = child;
11218 tmp->priv->next_sibling = child;
11225 if (child->priv->prev_sibling == NULL)
11226 self->priv->first_child = child;
11228 if (child->priv->next_sibling == NULL)
11229 self->priv->last_child = child;
11233 insert_child_above (ClutterActor *self,
11234 ClutterActor *child,
11237 ClutterActor *sibling = data;
11239 child->priv->parent = self;
11241 if (sibling == NULL)
11242 sibling = self->priv->last_child;
11244 child->priv->prev_sibling = sibling;
11246 if (sibling != NULL)
11248 ClutterActor *tmp = sibling->priv->next_sibling;
11250 child->priv->next_sibling = tmp;
11253 tmp->priv->prev_sibling = child;
11255 sibling->priv->next_sibling = child;
11258 child->priv->next_sibling = NULL;
11260 if (child->priv->prev_sibling == NULL)
11261 self->priv->first_child = child;
11263 if (child->priv->next_sibling == NULL)
11264 self->priv->last_child = child;
11268 insert_child_below (ClutterActor *self,
11269 ClutterActor *child,
11272 ClutterActor *sibling = data;
11274 child->priv->parent = self;
11276 if (sibling == NULL)
11277 sibling = self->priv->first_child;
11279 child->priv->next_sibling = sibling;
11281 if (sibling != NULL)
11283 ClutterActor *tmp = sibling->priv->prev_sibling;
11285 child->priv->prev_sibling = tmp;
11288 tmp->priv->next_sibling = child;
11290 sibling->priv->prev_sibling = child;
11293 child->priv->prev_sibling = NULL;
11295 if (child->priv->prev_sibling == NULL)
11296 self->priv->first_child = child;
11298 if (child->priv->next_sibling == NULL)
11299 self->priv->last_child = child;
11302 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11303 ClutterActor *child,
11307 ADD_CHILD_CREATE_META = 1 << 0,
11308 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
11309 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
11310 ADD_CHILD_CHECK_STATE = 1 << 3,
11311 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
11312 ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11314 /* default flags for public API */
11315 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
11316 ADD_CHILD_EMIT_PARENT_SET |
11317 ADD_CHILD_EMIT_ACTOR_ADDED |
11318 ADD_CHILD_CHECK_STATE |
11319 ADD_CHILD_NOTIFY_FIRST_LAST |
11320 ADD_CHILD_SHOW_ON_SET_PARENT,
11322 /* flags for legacy/deprecated API */
11323 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
11324 ADD_CHILD_CHECK_STATE |
11325 ADD_CHILD_NOTIFY_FIRST_LAST |
11326 ADD_CHILD_SHOW_ON_SET_PARENT
11327 } ClutterActorAddChildFlags;
11330 * clutter_actor_add_child_internal:
11331 * @self: a #ClutterActor
11332 * @child: a #ClutterActor
11333 * @flags: control flags for actions
11334 * @add_func: delegate function
11335 * @data: (closure): data to pass to @add_func
11337 * Adds @child to the list of children of @self.
11339 * The actual insertion inside the list is delegated to @add_func: this
11340 * function will just set up the state, perform basic checks, and emit
11343 * The @flags argument is used to perform additional operations.
11346 clutter_actor_add_child_internal (ClutterActor *self,
11347 ClutterActor *child,
11348 ClutterActorAddChildFlags flags,
11349 ClutterActorAddChildFunc add_func,
11352 ClutterTextDirection text_dir;
11353 gboolean create_meta;
11354 gboolean emit_parent_set, emit_actor_added;
11355 gboolean check_state;
11356 gboolean notify_first_last;
11357 gboolean show_on_set_parent;
11358 ClutterActor *old_first_child, *old_last_child;
11360 if (child->priv->parent != NULL)
11362 g_warning ("The actor '%s' already has a parent, '%s'. You must "
11363 "use clutter_actor_remove_child() first.",
11364 _clutter_actor_get_debug_name (child),
11365 _clutter_actor_get_debug_name (child->priv->parent));
11369 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11371 g_warning ("The actor '%s' is a top-level actor, and cannot be "
11372 "a child of another actor.",
11373 _clutter_actor_get_debug_name (child));
11378 /* XXX - this check disallows calling methods that change the stacking
11379 * order within the destruction sequence, by triggering a critical
11380 * warning first, and leaving the actor in an undefined state, which
11381 * then ends up being caught by an assertion.
11383 * the reproducible sequence is:
11385 * - actor gets destroyed;
11386 * - another actor, linked to the first, will try to change the
11387 * stacking order of the first actor;
11388 * - changing the stacking order is a composite operation composed
11389 * by the following steps:
11390 * 1. ref() the child;
11391 * 2. remove_child_internal(), which removes the reference;
11392 * 3. add_child_internal(), which adds a reference;
11393 * - the state of the actor is not changed between (2) and (3), as
11394 * it could be an expensive recomputation;
11395 * - if (3) bails out, then the actor is in an undefined state, but
11397 * - the destruction sequence terminates, but the actor is unparented
11398 * while its state indicates being parented instead.
11399 * - assertion failure.
11401 * the obvious fix would be to decompose each set_child_*_sibling()
11402 * method into proper remove_child()/add_child(), with state validation;
11403 * this may cause excessive work, though, and trigger a cascade of other
11404 * bugs in code that assumes that a change in the stacking order is an
11405 * atomic operation.
11407 * another potential fix is to just remove this check here, and let
11408 * code doing stacking order changes inside the destruction sequence
11409 * of an actor continue doing the work.
11411 * the third fix is to silently bail out early from every
11412 * set_child_*_sibling() and set_child_at_index() method, and avoid
11415 * I have a preference for the second solution, since it involves the
11416 * least amount of work, and the least amount of code duplication.
11418 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11420 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11422 g_warning ("The actor '%s' is currently being destroyed, and "
11423 "cannot be added as a child of another actor.",
11424 _clutter_actor_get_debug_name (child));
11429 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11430 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11431 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11432 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11433 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11434 show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11436 old_first_child = self->priv->first_child;
11437 old_last_child = self->priv->last_child;
11439 g_object_freeze_notify (G_OBJECT (self));
11442 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11444 g_object_ref_sink (child);
11445 child->priv->parent = NULL;
11446 child->priv->next_sibling = NULL;
11447 child->priv->prev_sibling = NULL;
11449 /* delegate the actual insertion */
11450 add_func (self, child, data);
11452 g_assert (child->priv->parent == self);
11454 self->priv->n_children += 1;
11456 self->priv->age += 1;
11458 /* if push_internal() has been called then we automatically set
11459 * the flag on the actor
11461 if (self->priv->internal_child)
11462 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11464 /* children may cause their parent to expand, if they are set
11465 * to expand; if a child is not expanded then it cannot change
11466 * its parent's state. any further change later on will queue
11467 * an expand state check.
11469 * this check, with the initial state of the needs_compute_expand
11470 * flag set to FALSE, should avoid recomputing the expand flags
11471 * state while building the actor tree.
11473 if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11474 (child->priv->needs_compute_expand ||
11475 child->priv->needs_x_expand ||
11476 child->priv->needs_y_expand))
11478 clutter_actor_queue_compute_expand (self);
11481 /* clutter_actor_reparent() will emit ::parent-set for us */
11482 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11483 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11487 /* If parent is mapped or realized, we need to also be mapped or
11488 * realized once we're inside the parent.
11490 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11492 /* propagate the parent's text direction to the child */
11493 text_dir = clutter_actor_get_text_direction (self);
11494 clutter_actor_set_text_direction (child, text_dir);
11497 if (show_on_set_parent && child->priv->show_on_set_parent)
11498 clutter_actor_show (child);
11500 if (CLUTTER_ACTOR_IS_MAPPED (child))
11501 clutter_actor_queue_redraw (child);
11503 /* maintain the invariant that if an actor needs layout,
11504 * its parents do as well
11506 if (child->priv->needs_width_request ||
11507 child->priv->needs_height_request ||
11508 child->priv->needs_allocation)
11510 /* we work around the short-circuiting we do
11511 * in clutter_actor_queue_relayout() since we
11512 * want to force a relayout
11514 child->priv->needs_width_request = TRUE;
11515 child->priv->needs_height_request = TRUE;
11516 child->priv->needs_allocation = TRUE;
11518 clutter_actor_queue_relayout (child->priv->parent);
11521 if (emit_actor_added)
11522 g_signal_emit_by_name (self, "actor-added", child);
11524 if (notify_first_last)
11526 if (old_first_child != self->priv->first_child)
11527 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11529 if (old_last_child != self->priv->last_child)
11530 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11533 g_object_thaw_notify (G_OBJECT (self));
11537 * clutter_actor_add_child:
11538 * @self: a #ClutterActor
11539 * @child: a #ClutterActor
11541 * Adds @child to the children of @self.
11543 * This function will acquire a reference on @child that will only
11544 * be released when calling clutter_actor_remove_child().
11546 * This function will take into consideration the #ClutterActor:depth
11547 * of @child, and will keep the list of children sorted.
11549 * This function will emit the #ClutterContainer::actor-added signal
11555 clutter_actor_add_child (ClutterActor *self,
11556 ClutterActor *child)
11558 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11559 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11560 g_return_if_fail (self != child);
11561 g_return_if_fail (child->priv->parent == NULL);
11563 clutter_actor_add_child_internal (self, child,
11564 ADD_CHILD_DEFAULT_FLAGS,
11565 insert_child_at_depth,
11570 * clutter_actor_insert_child_at_index:
11571 * @self: a #ClutterActor
11572 * @child: a #ClutterActor
11573 * @index_: the index
11575 * Inserts @child into the list of children of @self, using the
11576 * given @index_. If @index_ is greater than the number of children
11577 * in @self, or is less than 0, then the new child is added at the end.
11579 * This function will acquire a reference on @child that will only
11580 * be released when calling clutter_actor_remove_child().
11582 * This function will not take into consideration the #ClutterActor:depth
11585 * This function will emit the #ClutterContainer::actor-added signal
11591 clutter_actor_insert_child_at_index (ClutterActor *self,
11592 ClutterActor *child,
11595 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11596 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11597 g_return_if_fail (self != child);
11598 g_return_if_fail (child->priv->parent == NULL);
11600 clutter_actor_add_child_internal (self, child,
11601 ADD_CHILD_DEFAULT_FLAGS,
11602 insert_child_at_index,
11603 GINT_TO_POINTER (index_));
11607 * clutter_actor_insert_child_above:
11608 * @self: a #ClutterActor
11609 * @child: a #ClutterActor
11610 * @sibling: (allow-none): a child of @self, or %NULL
11612 * Inserts @child into the list of children of @self, above another
11613 * child of @self or, if @sibling is %NULL, above all the children
11616 * This function will acquire a reference on @child that will only
11617 * be released when calling clutter_actor_remove_child().
11619 * This function will not take into consideration the #ClutterActor:depth
11622 * This function will emit the #ClutterContainer::actor-added signal
11628 clutter_actor_insert_child_above (ClutterActor *self,
11629 ClutterActor *child,
11630 ClutterActor *sibling)
11632 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11633 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11634 g_return_if_fail (self != child);
11635 g_return_if_fail (child != sibling);
11636 g_return_if_fail (child->priv->parent == NULL);
11637 g_return_if_fail (sibling == NULL ||
11638 (CLUTTER_IS_ACTOR (sibling) &&
11639 sibling->priv->parent == self));
11641 clutter_actor_add_child_internal (self, child,
11642 ADD_CHILD_DEFAULT_FLAGS,
11643 insert_child_above,
11648 * clutter_actor_insert_child_below:
11649 * @self: a #ClutterActor
11650 * @child: a #ClutterActor
11651 * @sibling: (allow-none): a child of @self, or %NULL
11653 * Inserts @child into the list of children of @self, below another
11654 * child of @self or, if @sibling is %NULL, below all the children
11657 * This function will acquire a reference on @child that will only
11658 * be released when calling clutter_actor_remove_child().
11660 * This function will not take into consideration the #ClutterActor:depth
11663 * This function will emit the #ClutterContainer::actor-added signal
11669 clutter_actor_insert_child_below (ClutterActor *self,
11670 ClutterActor *child,
11671 ClutterActor *sibling)
11673 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11674 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11675 g_return_if_fail (self != child);
11676 g_return_if_fail (child != sibling);
11677 g_return_if_fail (child->priv->parent == NULL);
11678 g_return_if_fail (sibling == NULL ||
11679 (CLUTTER_IS_ACTOR (sibling) &&
11680 sibling->priv->parent == self));
11682 clutter_actor_add_child_internal (self, child,
11683 ADD_CHILD_DEFAULT_FLAGS,
11684 insert_child_below,
11689 * clutter_actor_set_parent:
11690 * @self: A #ClutterActor
11691 * @parent: A new #ClutterActor parent
11693 * Sets the parent of @self to @parent.
11695 * This function will result in @parent acquiring a reference on @self,
11696 * eventually by sinking its floating reference first. The reference
11697 * will be released by clutter_actor_unparent().
11699 * This function should only be called by legacy #ClutterActor<!-- -->s
11700 * implementing the #ClutterContainer interface.
11702 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11705 clutter_actor_set_parent (ClutterActor *self,
11706 ClutterActor *parent)
11708 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11709 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11710 g_return_if_fail (self != parent);
11711 g_return_if_fail (self->priv->parent == NULL);
11713 /* as this function will be called inside ClutterContainer::add
11714 * implementations or when building up a composite actor, we have
11715 * to preserve the old behaviour, and not create child meta or
11716 * emit the ::actor-added signal, to avoid recursion or double
11719 clutter_actor_add_child_internal (parent, self,
11720 ADD_CHILD_LEGACY_FLAGS,
11721 insert_child_at_depth,
11726 * clutter_actor_get_parent:
11727 * @self: A #ClutterActor
11729 * Retrieves the parent of @self.
11731 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11732 * if no parent is set
11735 clutter_actor_get_parent (ClutterActor *self)
11737 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11739 return self->priv->parent;
11743 * clutter_actor_get_paint_visibility:
11744 * @self: A #ClutterActor
11746 * Retrieves the 'paint' visibility of an actor recursively checking for non
11749 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11751 * Return Value: %TRUE if the actor is visibile and will be painted.
11756 clutter_actor_get_paint_visibility (ClutterActor *actor)
11758 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11760 return CLUTTER_ACTOR_IS_MAPPED (actor);
11764 * clutter_actor_remove_child:
11765 * @self: a #ClutterActor
11766 * @child: a #ClutterActor
11768 * Removes @child from the children of @self.
11770 * This function will release the reference added by
11771 * clutter_actor_add_child(), so if you want to keep using @child
11772 * you will have to acquire a referenced on it before calling this
11775 * This function will emit the #ClutterContainer::actor-removed
11781 clutter_actor_remove_child (ClutterActor *self,
11782 ClutterActor *child)
11784 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11785 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11786 g_return_if_fail (self != child);
11787 g_return_if_fail (child->priv->parent != NULL);
11788 g_return_if_fail (child->priv->parent == self);
11790 clutter_actor_remove_child_internal (self, child,
11791 REMOVE_CHILD_DEFAULT_FLAGS);
11795 * clutter_actor_remove_all_children:
11796 * @self: a #ClutterActor
11798 * Removes all children of @self.
11800 * This function releases the reference added by inserting a child actor
11801 * in the list of children of @self.
11803 * If the reference count of a child drops to zero, the child will be
11804 * destroyed. If you want to ensure the destruction of all the children
11805 * of @self, use clutter_actor_destroy_all_children().
11810 clutter_actor_remove_all_children (ClutterActor *self)
11812 ClutterActorIter iter;
11814 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11816 if (self->priv->n_children == 0)
11819 g_object_freeze_notify (G_OBJECT (self));
11821 clutter_actor_iter_init (&iter, self);
11822 while (clutter_actor_iter_next (&iter, NULL))
11823 clutter_actor_iter_remove (&iter);
11825 g_object_thaw_notify (G_OBJECT (self));
11828 g_assert (self->priv->first_child == NULL);
11829 g_assert (self->priv->last_child == NULL);
11830 g_assert (self->priv->n_children == 0);
11834 * clutter_actor_destroy_all_children:
11835 * @self: a #ClutterActor
11837 * Destroys all children of @self.
11839 * This function releases the reference added by inserting a child
11840 * actor in the list of children of @self, and ensures that the
11841 * #ClutterActor::destroy signal is emitted on each child of the
11844 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11845 * when its reference count drops to 0; the default handler of the
11846 * #ClutterActor::destroy signal will destroy all the children of an
11847 * actor. This function ensures that all children are destroyed, instead
11848 * of just removed from @self, unlike clutter_actor_remove_all_children()
11849 * which will merely release the reference and remove each child.
11851 * Unless you acquired an additional reference on each child of @self
11852 * prior to calling clutter_actor_remove_all_children() and want to reuse
11853 * the actors, you should use clutter_actor_destroy_all_children() in
11854 * order to make sure that children are destroyed and signal handlers
11855 * are disconnected even in cases where circular references prevent this
11856 * from automatically happening through reference counting alone.
11861 clutter_actor_destroy_all_children (ClutterActor *self)
11863 ClutterActorIter iter;
11865 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11867 if (self->priv->n_children == 0)
11870 g_object_freeze_notify (G_OBJECT (self));
11872 clutter_actor_iter_init (&iter, self);
11873 while (clutter_actor_iter_next (&iter, NULL))
11874 clutter_actor_iter_destroy (&iter);
11876 g_object_thaw_notify (G_OBJECT (self));
11879 g_assert (self->priv->first_child == NULL);
11880 g_assert (self->priv->last_child == NULL);
11881 g_assert (self->priv->n_children == 0);
11884 typedef struct _InsertBetweenData {
11885 ClutterActor *prev_sibling;
11886 ClutterActor *next_sibling;
11887 } InsertBetweenData;
11890 insert_child_between (ClutterActor *self,
11891 ClutterActor *child,
11894 InsertBetweenData *data = data_;
11895 ClutterActor *prev_sibling = data->prev_sibling;
11896 ClutterActor *next_sibling = data->next_sibling;
11898 child->priv->parent = self;
11899 child->priv->prev_sibling = prev_sibling;
11900 child->priv->next_sibling = next_sibling;
11902 if (prev_sibling != NULL)
11903 prev_sibling->priv->next_sibling = child;
11905 if (next_sibling != NULL)
11906 next_sibling->priv->prev_sibling = child;
11908 if (child->priv->prev_sibling == NULL)
11909 self->priv->first_child = child;
11911 if (child->priv->next_sibling == NULL)
11912 self->priv->last_child = child;
11916 * clutter_actor_replace_child:
11917 * @self: a #ClutterActor
11918 * @old_child: the child of @self to replace
11919 * @new_child: the #ClutterActor to replace @old_child
11921 * Replaces @old_child with @new_child in the list of children of @self.
11926 clutter_actor_replace_child (ClutterActor *self,
11927 ClutterActor *old_child,
11928 ClutterActor *new_child)
11930 ClutterActor *prev_sibling, *next_sibling;
11931 InsertBetweenData clos;
11933 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11934 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11935 g_return_if_fail (old_child->priv->parent == self);
11936 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11937 g_return_if_fail (old_child != new_child);
11938 g_return_if_fail (new_child != self);
11939 g_return_if_fail (new_child->priv->parent == NULL);
11941 prev_sibling = old_child->priv->prev_sibling;
11942 next_sibling = old_child->priv->next_sibling;
11943 clutter_actor_remove_child_internal (self, old_child,
11944 REMOVE_CHILD_DEFAULT_FLAGS);
11946 clos.prev_sibling = prev_sibling;
11947 clos.next_sibling = next_sibling;
11948 clutter_actor_add_child_internal (self, new_child,
11949 ADD_CHILD_DEFAULT_FLAGS,
11950 insert_child_between,
11955 * clutter_actor_unparent:
11956 * @self: a #ClutterActor
11958 * Removes the parent of @self.
11960 * This will cause the parent of @self to release the reference
11961 * acquired when calling clutter_actor_set_parent(), so if you
11962 * want to keep @self you will have to acquire a reference of
11963 * your own, through g_object_ref().
11965 * This function should only be called by legacy #ClutterActor<!-- -->s
11966 * implementing the #ClutterContainer interface.
11970 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11973 clutter_actor_unparent (ClutterActor *self)
11975 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11977 if (self->priv->parent == NULL)
11980 clutter_actor_remove_child_internal (self->priv->parent, self,
11981 REMOVE_CHILD_LEGACY_FLAGS);
11985 * clutter_actor_reparent:
11986 * @self: a #ClutterActor
11987 * @new_parent: the new #ClutterActor parent
11989 * Resets the parent actor of @self.
11991 * This function is logically equivalent to calling clutter_actor_unparent()
11992 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11993 * ensures the child is not finalized when unparented, and emits the
11994 * #ClutterActor::parent-set signal only once.
11996 * In reality, calling this function is less useful than it sounds, as some
11997 * application code may rely on changes in the intermediate state between
11998 * removal and addition of the actor from its old parent to the @new_parent.
11999 * Thus, it is strongly encouraged to avoid using this function in application
12004 * Deprecated: 1.10: Use clutter_actor_remove_child() and
12005 * clutter_actor_add_child() instead; remember to take a reference on
12006 * the actor being removed before calling clutter_actor_remove_child()
12007 * to avoid the reference count dropping to zero and the actor being
12011 clutter_actor_reparent (ClutterActor *self,
12012 ClutterActor *new_parent)
12014 ClutterActorPrivate *priv;
12016 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12017 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
12018 g_return_if_fail (self != new_parent);
12020 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
12022 g_warning ("Cannot set a parent on a toplevel actor");
12026 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
12028 g_warning ("Cannot set a parent currently being destroyed");
12034 if (priv->parent != new_parent)
12036 ClutterActor *old_parent;
12038 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12040 old_parent = priv->parent;
12042 g_object_ref (self);
12044 if (old_parent != NULL)
12046 /* go through the Container implementation if this is a regular
12047 * child and not an internal one
12049 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12051 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
12053 /* this will have to call unparent() */
12054 clutter_container_remove_actor (parent, self);
12057 clutter_actor_remove_child_internal (old_parent, self,
12058 REMOVE_CHILD_LEGACY_FLAGS);
12061 /* Note, will call set_parent() */
12062 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12063 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
12065 clutter_actor_add_child_internal (new_parent, self,
12066 ADD_CHILD_LEGACY_FLAGS,
12067 insert_child_at_depth,
12070 /* we emit the ::parent-set signal once */
12071 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
12073 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12075 /* the IN_REPARENT flag suspends state updates */
12076 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
12078 g_object_unref (self);
12083 * clutter_actor_contains:
12084 * @self: A #ClutterActor
12085 * @descendant: A #ClutterActor, possibly contained in @self
12087 * Determines if @descendant is contained inside @self (either as an
12088 * immediate child, or as a deeper descendant). If @self and
12089 * @descendant point to the same actor then it will also return %TRUE.
12091 * Return value: whether @descendent is contained within @self
12096 clutter_actor_contains (ClutterActor *self,
12097 ClutterActor *descendant)
12099 ClutterActor *actor;
12101 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12102 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12104 for (actor = descendant; actor; actor = actor->priv->parent)
12112 * clutter_actor_set_child_above_sibling:
12113 * @self: a #ClutterActor
12114 * @child: a #ClutterActor child of @self
12115 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12117 * Sets @child to be above @sibling in the list of children of @self.
12119 * If @sibling is %NULL, @child will be the new last child of @self.
12121 * This function is logically equivalent to removing @child and using
12122 * clutter_actor_insert_child_above(), but it will not emit signals
12123 * or change state on @child.
12128 clutter_actor_set_child_above_sibling (ClutterActor *self,
12129 ClutterActor *child,
12130 ClutterActor *sibling)
12132 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12133 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12134 g_return_if_fail (child->priv->parent == self);
12135 g_return_if_fail (child != sibling);
12136 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12138 if (sibling != NULL)
12139 g_return_if_fail (sibling->priv->parent == self);
12141 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12142 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12143 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12146 /* we don't want to change the state of child, or emit signals, or
12147 * regenerate ChildMeta instances here, but we still want to follow
12148 * the correct sequence of steps encoded in remove_child() and
12149 * add_child(), so that correctness is ensured, and we only go
12150 * through one known code path.
12152 g_object_ref (child);
12153 clutter_actor_remove_child_internal (self, child, 0);
12154 clutter_actor_add_child_internal (self, child,
12155 ADD_CHILD_NOTIFY_FIRST_LAST,
12156 insert_child_above,
12159 clutter_actor_queue_relayout (self);
12163 * clutter_actor_set_child_below_sibling:
12164 * @self: a #ClutterActor
12165 * @child: a #ClutterActor child of @self
12166 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12168 * Sets @child to be below @sibling in the list of children of @self.
12170 * If @sibling is %NULL, @child will be the new first child of @self.
12172 * This function is logically equivalent to removing @self and using
12173 * clutter_actor_insert_child_below(), but it will not emit signals
12174 * or change state on @child.
12179 clutter_actor_set_child_below_sibling (ClutterActor *self,
12180 ClutterActor *child,
12181 ClutterActor *sibling)
12183 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12184 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12185 g_return_if_fail (child->priv->parent == self);
12186 g_return_if_fail (child != sibling);
12187 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12189 if (sibling != NULL)
12190 g_return_if_fail (sibling->priv->parent == self);
12192 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12193 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12194 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12197 /* see the comment in set_child_above_sibling() */
12198 g_object_ref (child);
12199 clutter_actor_remove_child_internal (self, child, 0);
12200 clutter_actor_add_child_internal (self, child,
12201 ADD_CHILD_NOTIFY_FIRST_LAST,
12202 insert_child_below,
12205 clutter_actor_queue_relayout (self);
12209 * clutter_actor_set_child_at_index:
12210 * @self: a #ClutterActor
12211 * @child: a #ClutterActor child of @self
12212 * @index_: the new index for @child
12214 * Changes the index of @child in the list of children of @self.
12216 * This function is logically equivalent to removing @child and
12217 * calling clutter_actor_insert_child_at_index(), but it will not
12218 * emit signals or change state on @child.
12223 clutter_actor_set_child_at_index (ClutterActor *self,
12224 ClutterActor *child,
12227 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12228 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12229 g_return_if_fail (child->priv->parent == self);
12230 g_return_if_fail (index_ <= self->priv->n_children);
12232 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12233 CLUTTER_ACTOR_IN_DESTRUCTION (child))
12236 g_object_ref (child);
12237 clutter_actor_remove_child_internal (self, child, 0);
12238 clutter_actor_add_child_internal (self, child,
12239 ADD_CHILD_NOTIFY_FIRST_LAST,
12240 insert_child_at_index,
12241 GINT_TO_POINTER (index_));
12243 clutter_actor_queue_relayout (self);
12247 * clutter_actor_raise:
12248 * @self: A #ClutterActor
12249 * @below: (allow-none): A #ClutterActor to raise above.
12251 * Puts @self above @below.
12253 * Both actors must have the same parent, and the parent must implement
12254 * the #ClutterContainer interface
12256 * This function calls clutter_container_raise_child() internally.
12258 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12261 clutter_actor_raise (ClutterActor *self,
12262 ClutterActor *below)
12264 ClutterActor *parent;
12266 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12268 parent = clutter_actor_get_parent (self);
12269 if (parent == NULL)
12271 g_warning ("%s: Actor '%s' is not inside a container",
12273 _clutter_actor_get_debug_name (self));
12279 if (parent != clutter_actor_get_parent (below))
12281 g_warning ("%s Actor '%s' is not in the same container as "
12284 _clutter_actor_get_debug_name (self),
12285 _clutter_actor_get_debug_name (below));
12290 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12294 * clutter_actor_lower:
12295 * @self: A #ClutterActor
12296 * @above: (allow-none): A #ClutterActor to lower below
12298 * Puts @self below @above.
12300 * Both actors must have the same parent, and the parent must implement
12301 * the #ClutterContainer interface.
12303 * This function calls clutter_container_lower_child() internally.
12305 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12308 clutter_actor_lower (ClutterActor *self,
12309 ClutterActor *above)
12311 ClutterActor *parent;
12313 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12315 parent = clutter_actor_get_parent (self);
12316 if (parent == NULL)
12318 g_warning ("%s: Actor of type %s is not inside a container",
12320 _clutter_actor_get_debug_name (self));
12326 if (parent != clutter_actor_get_parent (above))
12328 g_warning ("%s: Actor '%s' is not in the same container as "
12331 _clutter_actor_get_debug_name (self),
12332 _clutter_actor_get_debug_name (above));
12337 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12341 * clutter_actor_raise_top:
12342 * @self: A #ClutterActor
12344 * Raises @self to the top.
12346 * This function calls clutter_actor_raise() internally.
12348 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12349 * a %NULL sibling, instead.
12352 clutter_actor_raise_top (ClutterActor *self)
12354 clutter_actor_raise (self, NULL);
12358 * clutter_actor_lower_bottom:
12359 * @self: A #ClutterActor
12361 * Lowers @self to the bottom.
12363 * This function calls clutter_actor_lower() internally.
12365 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12366 * a %NULL sibling, instead.
12369 clutter_actor_lower_bottom (ClutterActor *self)
12371 clutter_actor_lower (self, NULL);
12379 * clutter_actor_event:
12380 * @actor: a #ClutterActor
12381 * @event: a #ClutterEvent
12382 * @capture: TRUE if event in in capture phase, FALSE otherwise.
12384 * This function is used to emit an event on the main stage.
12385 * You should rarely need to use this function, except for
12386 * synthetising events.
12388 * Return value: the return value from the signal emission: %TRUE
12389 * if the actor handled the event, or %FALSE if the event was
12395 clutter_actor_event (ClutterActor *actor,
12396 ClutterEvent *event,
12399 gboolean retval = FALSE;
12400 gint signal_num = -1;
12402 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12403 g_return_val_if_fail (event != NULL, FALSE);
12405 g_object_ref (actor);
12409 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12415 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12419 switch (event->type)
12421 case CLUTTER_NOTHING:
12423 case CLUTTER_BUTTON_PRESS:
12424 signal_num = BUTTON_PRESS_EVENT;
12426 case CLUTTER_BUTTON_RELEASE:
12427 signal_num = BUTTON_RELEASE_EVENT;
12429 case CLUTTER_SCROLL:
12430 signal_num = SCROLL_EVENT;
12432 case CLUTTER_KEY_PRESS:
12433 signal_num = KEY_PRESS_EVENT;
12435 case CLUTTER_KEY_RELEASE:
12436 signal_num = KEY_RELEASE_EVENT;
12438 case CLUTTER_MOTION:
12439 signal_num = MOTION_EVENT;
12441 case CLUTTER_ENTER:
12442 signal_num = ENTER_EVENT;
12444 case CLUTTER_LEAVE:
12445 signal_num = LEAVE_EVENT;
12447 case CLUTTER_DELETE:
12448 case CLUTTER_DESTROY_NOTIFY:
12449 case CLUTTER_CLIENT_MESSAGE:
12455 if (signal_num != -1)
12456 g_signal_emit (actor, actor_signals[signal_num], 0,
12461 g_object_unref (actor);
12467 * clutter_actor_set_reactive:
12468 * @actor: a #ClutterActor
12469 * @reactive: whether the actor should be reactive to events
12471 * Sets @actor as reactive. Reactive actors will receive events.
12476 clutter_actor_set_reactive (ClutterActor *actor,
12479 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12481 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12485 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12487 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12489 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12493 * clutter_actor_get_reactive:
12494 * @actor: a #ClutterActor
12496 * Checks whether @actor is marked as reactive.
12498 * Return value: %TRUE if the actor is reactive
12503 clutter_actor_get_reactive (ClutterActor *actor)
12505 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12507 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12511 * clutter_actor_get_anchor_point:
12512 * @self: a #ClutterActor
12513 * @anchor_x: (out): return location for the X coordinate of the anchor point
12514 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12516 * Gets the current anchor point of the @actor in pixels.
12521 clutter_actor_get_anchor_point (ClutterActor *self,
12525 const ClutterTransformInfo *info;
12527 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12529 info = _clutter_actor_get_transform_info_or_defaults (self);
12530 clutter_anchor_coord_get_units (self, &info->anchor,
12537 * clutter_actor_set_anchor_point:
12538 * @self: a #ClutterActor
12539 * @anchor_x: X coordinate of the anchor point
12540 * @anchor_y: Y coordinate of the anchor point
12542 * Sets an anchor point for @self. The anchor point is a point in the
12543 * coordinate space of an actor to which the actor position within its
12544 * parent is relative; the default is (0, 0), i.e. the top-left corner
12550 clutter_actor_set_anchor_point (ClutterActor *self,
12554 ClutterTransformInfo *info;
12555 ClutterActorPrivate *priv;
12556 gboolean changed = FALSE;
12557 gfloat old_anchor_x, old_anchor_y;
12560 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12562 obj = G_OBJECT (self);
12564 info = _clutter_actor_get_transform_info (self);
12566 g_object_freeze_notify (obj);
12568 clutter_anchor_coord_get_units (self, &info->anchor,
12573 if (info->anchor.is_fractional)
12574 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12576 if (old_anchor_x != anchor_x)
12578 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12582 if (old_anchor_y != anchor_y)
12584 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12588 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12592 priv->transform_valid = FALSE;
12593 clutter_actor_queue_redraw (self);
12596 g_object_thaw_notify (obj);
12600 * clutter_actor_get_anchor_point_gravity:
12601 * @self: a #ClutterActor
12603 * Retrieves the anchor position expressed as a #ClutterGravity. If
12604 * the anchor point was specified using pixels or units this will
12605 * return %CLUTTER_GRAVITY_NONE.
12607 * Return value: the #ClutterGravity used by the anchor point
12612 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12614 const ClutterTransformInfo *info;
12616 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12618 info = _clutter_actor_get_transform_info_or_defaults (self);
12620 return clutter_anchor_coord_get_gravity (&info->anchor);
12624 * clutter_actor_move_anchor_point:
12625 * @self: a #ClutterActor
12626 * @anchor_x: X coordinate of the anchor point
12627 * @anchor_y: Y coordinate of the anchor point
12629 * Sets an anchor point for the actor, and adjusts the actor postion so that
12630 * the relative position of the actor toward its parent remains the same.
12635 clutter_actor_move_anchor_point (ClutterActor *self,
12639 gfloat old_anchor_x, old_anchor_y;
12640 const ClutterTransformInfo *info;
12642 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12644 info = _clutter_actor_get_transform_info (self);
12645 clutter_anchor_coord_get_units (self, &info->anchor,
12650 g_object_freeze_notify (G_OBJECT (self));
12652 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12654 if (self->priv->position_set)
12655 clutter_actor_move_by (self,
12656 anchor_x - old_anchor_x,
12657 anchor_y - old_anchor_y);
12659 g_object_thaw_notify (G_OBJECT (self));
12663 * clutter_actor_move_anchor_point_from_gravity:
12664 * @self: a #ClutterActor
12665 * @gravity: #ClutterGravity.
12667 * Sets an anchor point on the actor based on the given gravity, adjusting the
12668 * actor postion so that its relative position within its parent remains
12671 * Since version 1.0 the anchor point will be stored as a gravity so
12672 * that if the actor changes size then the anchor point will move. For
12673 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12674 * and later double the size of the actor, the anchor point will move
12675 * to the bottom right.
12680 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12681 ClutterGravity gravity)
12683 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12684 const ClutterTransformInfo *info;
12685 ClutterActorPrivate *priv;
12687 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12690 info = _clutter_actor_get_transform_info (self);
12692 g_object_freeze_notify (G_OBJECT (self));
12694 clutter_anchor_coord_get_units (self, &info->anchor,
12698 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12699 clutter_anchor_coord_get_units (self, &info->anchor,
12704 if (priv->position_set)
12705 clutter_actor_move_by (self,
12706 new_anchor_x - old_anchor_x,
12707 new_anchor_y - old_anchor_y);
12709 g_object_thaw_notify (G_OBJECT (self));
12713 * clutter_actor_set_anchor_point_from_gravity:
12714 * @self: a #ClutterActor
12715 * @gravity: #ClutterGravity.
12717 * Sets an anchor point on the actor, based on the given gravity (this is a
12718 * convenience function wrapping clutter_actor_set_anchor_point()).
12720 * Since version 1.0 the anchor point will be stored as a gravity so
12721 * that if the actor changes size then the anchor point will move. For
12722 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12723 * and later double the size of the actor, the anchor point will move
12724 * to the bottom right.
12729 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12730 ClutterGravity gravity)
12732 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12734 if (gravity == CLUTTER_GRAVITY_NONE)
12735 clutter_actor_set_anchor_point (self, 0, 0);
12738 GObject *obj = G_OBJECT (self);
12739 ClutterTransformInfo *info;
12741 g_object_freeze_notify (obj);
12743 info = _clutter_actor_get_transform_info (self);
12744 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12746 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12747 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12748 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12750 self->priv->transform_valid = FALSE;
12752 clutter_actor_queue_redraw (self);
12754 g_object_thaw_notify (obj);
12759 clutter_actor_store_content_box (ClutterActor *self,
12760 const ClutterActorBox *box)
12764 self->priv->content_box = *box;
12765 self->priv->content_box_valid = TRUE;
12768 self->priv->content_box_valid = FALSE;
12770 clutter_actor_queue_redraw (self);
12772 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12776 clutter_container_iface_init (ClutterContainerIface *iface)
12778 /* we don't override anything, as ClutterContainer already has a default
12779 * implementation that we can use, and which calls into our own API.
12794 parse_units (ClutterActor *self,
12795 ParseDimension dimension,
12798 GValue value = G_VALUE_INIT;
12801 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12804 json_node_get_value (node, &value);
12806 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12808 retval = (gfloat) g_value_get_int64 (&value);
12810 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12812 retval = g_value_get_double (&value);
12814 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12816 ClutterUnits units;
12819 res = clutter_units_from_string (&units, g_value_get_string (&value));
12821 retval = clutter_units_to_pixels (&units);
12824 g_warning ("Invalid value '%s': integers, strings or floating point "
12825 "values can be used for the x, y, width and height "
12826 "properties. Valid modifiers for strings are 'px', 'mm', "
12828 g_value_get_string (&value));
12834 g_warning ("Invalid value of type '%s': integers, strings of floating "
12835 "point values can be used for the x, y, width, height "
12836 "anchor-x and anchor-y properties.",
12837 g_type_name (G_VALUE_TYPE (&value)));
12840 g_value_unset (&value);
12846 ClutterRotateAxis axis;
12855 static inline gboolean
12856 parse_rotation_array (ClutterActor *actor,
12858 RotationInfo *info)
12862 if (json_array_get_length (array) != 2)
12866 element = json_array_get_element (array, 0);
12867 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12868 info->angle = json_node_get_double (element);
12873 element = json_array_get_element (array, 1);
12874 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12876 JsonArray *center = json_node_get_array (element);
12878 if (json_array_get_length (center) != 2)
12881 switch (info->axis)
12883 case CLUTTER_X_AXIS:
12884 info->center_y = parse_units (actor, PARSE_Y,
12885 json_array_get_element (center, 0));
12886 info->center_z = parse_units (actor, PARSE_Y,
12887 json_array_get_element (center, 1));
12890 case CLUTTER_Y_AXIS:
12891 info->center_x = parse_units (actor, PARSE_X,
12892 json_array_get_element (center, 0));
12893 info->center_z = parse_units (actor, PARSE_X,
12894 json_array_get_element (center, 1));
12897 case CLUTTER_Z_AXIS:
12898 info->center_x = parse_units (actor, PARSE_X,
12899 json_array_get_element (center, 0));
12900 info->center_y = parse_units (actor, PARSE_Y,
12901 json_array_get_element (center, 1));
12910 parse_rotation (ClutterActor *actor,
12912 RotationInfo *info)
12916 gboolean retval = FALSE;
12918 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12920 g_warning ("Invalid node of type '%s' found, expecting an array",
12921 json_node_type_name (node));
12925 array = json_node_get_array (node);
12926 len = json_array_get_length (array);
12928 for (i = 0; i < len; i++)
12930 JsonNode *element = json_array_get_element (array, i);
12931 JsonObject *object;
12934 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12936 g_warning ("Invalid node of type '%s' found, expecting an object",
12937 json_node_type_name (element));
12941 object = json_node_get_object (element);
12943 if (json_object_has_member (object, "x-axis"))
12945 member = json_object_get_member (object, "x-axis");
12947 info->axis = CLUTTER_X_AXIS;
12949 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12951 info->angle = json_node_get_double (member);
12954 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12955 retval = parse_rotation_array (actor,
12956 json_node_get_array (member),
12961 else if (json_object_has_member (object, "y-axis"))
12963 member = json_object_get_member (object, "y-axis");
12965 info->axis = CLUTTER_Y_AXIS;
12967 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12969 info->angle = json_node_get_double (member);
12972 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12973 retval = parse_rotation_array (actor,
12974 json_node_get_array (member),
12979 else if (json_object_has_member (object, "z-axis"))
12981 member = json_object_get_member (object, "z-axis");
12983 info->axis = CLUTTER_Z_AXIS;
12985 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12987 info->angle = json_node_get_double (member);
12990 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12991 retval = parse_rotation_array (actor,
12992 json_node_get_array (member),
13003 parse_actor_metas (ClutterScript *script,
13004 ClutterActor *actor,
13007 GList *elements, *l;
13008 GSList *retval = NULL;
13010 if (!JSON_NODE_HOLDS_ARRAY (node))
13013 elements = json_array_get_elements (json_node_get_array (node));
13015 for (l = elements; l != NULL; l = l->next)
13017 JsonNode *element = l->data;
13018 const gchar *id_ = _clutter_script_get_id_from_node (element);
13021 if (id_ == NULL || *id_ == '\0')
13024 meta = clutter_script_get_object (script, id_);
13028 retval = g_slist_prepend (retval, meta);
13031 g_list_free (elements);
13033 return g_slist_reverse (retval);
13037 parse_behaviours (ClutterScript *script,
13038 ClutterActor *actor,
13041 GList *elements, *l;
13042 GSList *retval = NULL;
13044 if (!JSON_NODE_HOLDS_ARRAY (node))
13047 elements = json_array_get_elements (json_node_get_array (node));
13049 for (l = elements; l != NULL; l = l->next)
13051 JsonNode *element = l->data;
13052 const gchar *id_ = _clutter_script_get_id_from_node (element);
13053 GObject *behaviour;
13055 if (id_ == NULL || *id_ == '\0')
13058 behaviour = clutter_script_get_object (script, id_);
13059 if (behaviour == NULL)
13062 retval = g_slist_prepend (retval, behaviour);
13065 g_list_free (elements);
13067 return g_slist_reverse (retval);
13070 static ClutterMargin *
13071 parse_margin (ClutterActor *self,
13074 ClutterMargin *margin;
13077 if (!JSON_NODE_HOLDS_ARRAY (node))
13079 g_warning ("The margin property must be an array of 1 to 4 elements");
13083 margin = clutter_margin_new ();
13084 array = json_node_get_array (node);
13085 switch (json_array_get_length (array))
13088 margin->top = margin->right = margin->bottom = margin->left =
13089 parse_units (self, 0, json_array_get_element (array, 0));
13093 margin->top = margin->bottom =
13094 parse_units (self, 0, json_array_get_element (array, 0));
13095 margin->right = margin->left =
13096 parse_units (self, 0, json_array_get_element (array, 1));
13101 parse_units (self, 0, json_array_get_element (array, 0));
13102 margin->right = margin->left =
13103 parse_units (self, 0, json_array_get_element (array, 1));
13105 parse_units (self, 0, json_array_get_element (array, 2));
13110 parse_units (self, 0, json_array_get_element (array, 0));
13112 parse_units (self, 0, json_array_get_element (array, 1));
13114 parse_units (self, 0, json_array_get_element (array, 2));
13116 parse_units (self, 0, json_array_get_element (array, 3));
13120 g_warning ("The margin property must be an array of 1 to 4 elements");
13121 clutter_margin_free (margin);
13128 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
13129 ClutterScript *script,
13134 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13135 gboolean retval = FALSE;
13137 if ((name[0] == 'x' && name[1] == '\0') ||
13138 (name[0] == 'y' && name[1] == '\0') ||
13139 (strcmp (name, "width") == 0) ||
13140 (strcmp (name, "height") == 0) ||
13141 (strcmp (name, "anchor_x") == 0) ||
13142 (strcmp (name, "anchor_y") == 0))
13144 ParseDimension dimension;
13147 if (name[0] == 'x')
13148 dimension = PARSE_X;
13149 else if (name[0] == 'y')
13150 dimension = PARSE_Y;
13151 else if (name[0] == 'w')
13152 dimension = PARSE_WIDTH;
13153 else if (name[0] == 'h')
13154 dimension = PARSE_HEIGHT;
13155 else if (name[0] == 'a' && name[7] == 'x')
13156 dimension = PARSE_ANCHOR_X;
13157 else if (name[0] == 'a' && name[7] == 'y')
13158 dimension = PARSE_ANCHOR_Y;
13162 units = parse_units (actor, dimension, node);
13164 /* convert back to pixels: all properties are pixel-based */
13165 g_value_init (value, G_TYPE_FLOAT);
13166 g_value_set_float (value, units);
13170 else if (strcmp (name, "rotation") == 0)
13172 RotationInfo *info;
13174 info = g_slice_new0 (RotationInfo);
13175 retval = parse_rotation (actor, node, info);
13179 g_value_init (value, G_TYPE_POINTER);
13180 g_value_set_pointer (value, info);
13183 g_slice_free (RotationInfo, info);
13185 else if (strcmp (name, "behaviours") == 0)
13189 #ifdef CLUTTER_ENABLE_DEBUG
13190 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13191 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13192 "and it should not be used in newly "
13193 "written ClutterScript definitions.");
13196 l = parse_behaviours (script, actor, node);
13198 g_value_init (value, G_TYPE_POINTER);
13199 g_value_set_pointer (value, l);
13203 else if (strcmp (name, "actions") == 0 ||
13204 strcmp (name, "constraints") == 0 ||
13205 strcmp (name, "effects") == 0)
13209 l = parse_actor_metas (script, actor, node);
13211 g_value_init (value, G_TYPE_POINTER);
13212 g_value_set_pointer (value, l);
13216 else if (strcmp (name, "margin") == 0)
13218 ClutterMargin *margin = parse_margin (actor, node);
13222 g_value_init (value, CLUTTER_TYPE_MARGIN);
13223 g_value_set_boxed (value, margin);
13232 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13233 ClutterScript *script,
13235 const GValue *value)
13237 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13239 #ifdef CLUTTER_ENABLE_DEBUG
13240 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13242 gchar *tmp = g_strdup_value_contents (value);
13244 CLUTTER_NOTE (SCRIPT,
13245 "in ClutterActor::set_custom_property('%s') = %s",
13251 #endif /* CLUTTER_ENABLE_DEBUG */
13253 if (strcmp (name, "rotation") == 0)
13255 RotationInfo *info;
13257 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13260 info = g_value_get_pointer (value);
13262 clutter_actor_set_rotation (actor,
13263 info->axis, info->angle,
13268 g_slice_free (RotationInfo, info);
13273 if (strcmp (name, "behaviours") == 0)
13275 GSList *behaviours, *l;
13277 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13280 behaviours = g_value_get_pointer (value);
13281 for (l = behaviours; l != NULL; l = l->next)
13283 ClutterBehaviour *behaviour = l->data;
13285 clutter_behaviour_apply (behaviour, actor);
13288 g_slist_free (behaviours);
13293 if (strcmp (name, "actions") == 0 ||
13294 strcmp (name, "constraints") == 0 ||
13295 strcmp (name, "effects") == 0)
13299 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13302 metas = g_value_get_pointer (value);
13303 for (l = metas; l != NULL; l = l->next)
13305 if (name[0] == 'a')
13306 clutter_actor_add_action (actor, l->data);
13308 if (name[0] == 'c')
13309 clutter_actor_add_constraint (actor, l->data);
13311 if (name[0] == 'e')
13312 clutter_actor_add_effect (actor, l->data);
13315 g_slist_free (metas);
13319 if (strcmp (name, "margin") == 0)
13321 clutter_actor_set_margin (actor, g_value_get_boxed (value));
13325 g_object_set_property (G_OBJECT (scriptable), name, value);
13329 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13331 iface->parse_custom_node = clutter_actor_parse_custom_node;
13332 iface->set_custom_property = clutter_actor_set_custom_property;
13335 static ClutterActorMeta *
13336 get_meta_from_animation_property (ClutterActor *actor,
13340 ClutterActorPrivate *priv = actor->priv;
13341 ClutterActorMeta *meta = NULL;
13344 /* if this is not a special property, fall through */
13345 if (name[0] != '@')
13348 /* detect the properties named using the following spec:
13350 * @<section>.<meta-name>.<property-name>
13352 * where <section> can be one of the following:
13358 * and <meta-name> is the name set on a specific ActorMeta
13361 tokens = g_strsplit (name + 1, ".", -1);
13362 if (tokens == NULL || g_strv_length (tokens) != 3)
13364 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13366 g_strfreev (tokens);
13370 if (strcmp (tokens[0], "actions") == 0)
13371 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13373 if (strcmp (tokens[0], "constraints") == 0)
13374 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13376 if (strcmp (tokens[0], "effects") == 0)
13377 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13379 if (name_p != NULL)
13380 *name_p = g_strdup (tokens[2]);
13382 CLUTTER_NOTE (ANIMATION,
13383 "Looking for property '%s' of object '%s' in section '%s'",
13388 g_strfreev (tokens);
13393 static GParamSpec *
13394 clutter_actor_find_property (ClutterAnimatable *animatable,
13395 const gchar *property_name)
13397 ClutterActorMeta *meta = NULL;
13398 GObjectClass *klass = NULL;
13399 GParamSpec *pspec = NULL;
13400 gchar *p_name = NULL;
13402 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13408 klass = G_OBJECT_GET_CLASS (meta);
13410 pspec = g_object_class_find_property (klass, p_name);
13414 klass = G_OBJECT_GET_CLASS (animatable);
13416 pspec = g_object_class_find_property (klass, property_name);
13425 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13426 const gchar *property_name,
13429 ClutterActorMeta *meta = NULL;
13430 gchar *p_name = NULL;
13432 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13437 g_object_get_property (G_OBJECT (meta), p_name, initial);
13439 g_object_get_property (G_OBJECT (animatable), property_name, initial);
13445 * clutter_actor_set_animatable_property:
13446 * @actor: a #ClutterActor
13447 * @prop_id: the paramspec id
13448 * @value: the value to set
13449 * @pspec: the paramspec
13451 * Sets values of animatable properties.
13453 * This is a variant of clutter_actor_set_property() that gets called
13454 * by the #ClutterAnimatable implementation of #ClutterActor for the
13455 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13458 * Unlike the implementation of #GObjectClass.set_property(), this
13459 * function will not update the interval if a transition involving an
13460 * animatable property is in progress - this avoids cycles with the
13461 * transition API calling the public API.
13464 clutter_actor_set_animatable_property (ClutterActor *actor,
13466 const GValue *value,
13469 GObject *obj = G_OBJECT (actor);
13471 g_object_freeze_notify (obj);
13476 clutter_actor_set_x_internal (actor, g_value_get_float (value));
13480 clutter_actor_set_y_internal (actor, g_value_get_float (value));
13483 case PROP_POSITION:
13484 clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13488 clutter_actor_set_width_internal (actor, g_value_get_float (value));
13492 clutter_actor_set_height_internal (actor, g_value_get_float (value));
13496 clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13499 case PROP_ALLOCATION:
13500 clutter_actor_allocate_internal (actor,
13501 g_value_get_boxed (value),
13502 actor->priv->allocation_flags);
13506 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13510 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13513 case PROP_BACKGROUND_COLOR:
13514 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13518 clutter_actor_set_scale_factor_internal (actor,
13519 g_value_get_double (value),
13524 clutter_actor_set_scale_factor_internal (actor,
13525 g_value_get_double (value),
13529 case PROP_ROTATION_ANGLE_X:
13530 clutter_actor_set_rotation_angle_internal (actor,
13532 g_value_get_double (value));
13535 case PROP_ROTATION_ANGLE_Y:
13536 clutter_actor_set_rotation_angle_internal (actor,
13538 g_value_get_double (value));
13541 case PROP_ROTATION_ANGLE_Z:
13542 clutter_actor_set_rotation_angle_internal (actor,
13544 g_value_get_double (value));
13547 case PROP_CONTENT_BOX:
13548 clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13552 g_object_set_property (obj, pspec->name, value);
13556 g_object_thaw_notify (obj);
13560 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13561 const gchar *property_name,
13562 const GValue *final)
13564 ClutterActor *actor = CLUTTER_ACTOR (animatable);
13565 ClutterActorMeta *meta = NULL;
13566 gchar *p_name = NULL;
13568 meta = get_meta_from_animation_property (actor,
13572 g_object_set_property (G_OBJECT (meta), p_name, final);
13575 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13578 pspec = g_object_class_find_property (obj_class, property_name);
13580 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13582 /* XXX - I'm going to the special hell for this */
13583 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13586 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13593 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13595 iface->find_property = clutter_actor_find_property;
13596 iface->get_initial_state = clutter_actor_get_initial_state;
13597 iface->set_final_state = clutter_actor_set_final_state;
13601 * clutter_actor_transform_stage_point:
13602 * @self: A #ClutterActor
13603 * @x: (in): x screen coordinate of the point to unproject
13604 * @y: (in): y screen coordinate of the point to unproject
13605 * @x_out: (out): return location for the unprojected x coordinance
13606 * @y_out: (out): return location for the unprojected y coordinance
13608 * This function translates screen coordinates (@x, @y) to
13609 * coordinates relative to the actor. For example, it can be used to translate
13610 * screen events from global screen coordinates into actor-local coordinates.
13612 * The conversion can fail, notably if the transform stack results in the
13613 * actor being projected on the screen as a mere line.
13615 * The conversion should not be expected to be pixel-perfect due to the
13616 * nature of the operation. In general the error grows when the skewing
13617 * of the actor rectangle on screen increases.
13619 * <note><para>This function can be computationally intensive.</para></note>
13621 * <note><para>This function only works when the allocation is up-to-date,
13622 * i.e. inside of paint().</para></note>
13624 * Return value: %TRUE if conversion was successful.
13629 clutter_actor_transform_stage_point (ClutterActor *self,
13635 ClutterVertex v[4];
13638 int du, dv, xi, yi;
13640 float xf, yf, wf, det;
13641 ClutterActorPrivate *priv;
13643 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13647 /* This implementation is based on the quad -> quad projection algorithm
13648 * described by Paul Heckbert in:
13650 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13652 * and the sample implementation at:
13654 * http://www.cs.cmu.edu/~ph/src/texfund/
13656 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13657 * quad to rectangle only, which significantly simplifies things; the
13658 * function calls have been unrolled, and most of the math is done in fixed
13662 clutter_actor_get_abs_allocation_vertices (self, v);
13664 /* Keeping these as ints simplifies the multiplication (no significant
13665 * loss of precision here).
13667 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13668 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13673 #define UX2FP(x) (x)
13674 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13676 /* First, find mapping from unit uv square to xy quadrilateral; this
13677 * equivalent to the pmap_square_quad() functions in the sample
13678 * implementation, which we can simplify, since our target is always
13681 px = v[0].x - v[1].x + v[3].x - v[2].x;
13682 py = v[0].y - v[1].y + v[3].y - v[2].y;
13686 /* affine transform */
13687 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13688 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13689 RQ[2][0] = UX2FP (v[0].x);
13690 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13691 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13692 RQ[2][1] = UX2FP (v[0].y);
13699 /* projective transform */
13700 double dx1, dx2, dy1, dy2, del;
13702 dx1 = UX2FP (v[1].x - v[3].x);
13703 dx2 = UX2FP (v[2].x - v[3].x);
13704 dy1 = UX2FP (v[1].y - v[3].y);
13705 dy2 = UX2FP (v[2].y - v[3].y);
13707 del = DET2FP (dx1, dx2, dy1, dy2);
13712 * The division here needs to be done in floating point for
13713 * precisions reasons.
13715 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13716 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13717 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13719 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13720 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13721 RQ[2][0] = UX2FP (v[0].x);
13722 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13723 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13724 RQ[2][1] = UX2FP (v[0].y);
13728 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13729 * square. Since our rectangle is based at 0,0 we only need to scale.
13739 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13742 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13743 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13744 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13745 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13746 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13747 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13748 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13749 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13750 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13753 * Check the resulting matrix is OK.
13755 det = (RQ[0][0] * ST[0][0])
13756 + (RQ[0][1] * ST[0][1])
13757 + (RQ[0][2] * ST[0][2]);
13762 * Now transform our point with the ST matrix; the notional w
13763 * coordinate is 1, hence the last part is simply added.
13768 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13769 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13770 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13785 * clutter_actor_is_rotated:
13786 * @self: a #ClutterActor
13788 * Checks whether any rotation is applied to the actor.
13790 * Return value: %TRUE if the actor is rotated.
13795 clutter_actor_is_rotated (ClutterActor *self)
13797 const ClutterTransformInfo *info;
13799 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13801 info = _clutter_actor_get_transform_info_or_defaults (self);
13803 if (info->rx_angle || info->ry_angle || info->rz_angle)
13810 * clutter_actor_is_scaled:
13811 * @self: a #ClutterActor
13813 * Checks whether the actor is scaled in either dimension.
13815 * Return value: %TRUE if the actor is scaled.
13820 clutter_actor_is_scaled (ClutterActor *self)
13822 const ClutterTransformInfo *info;
13824 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13826 info = _clutter_actor_get_transform_info_or_defaults (self);
13828 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13835 _clutter_actor_get_stage_internal (ClutterActor *actor)
13837 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13838 actor = actor->priv->parent;
13844 * clutter_actor_get_stage:
13845 * @actor: a #ClutterActor
13847 * Retrieves the #ClutterStage where @actor is contained.
13849 * Return value: (transfer none) (type Clutter.Stage): the stage
13850 * containing the actor, or %NULL
13855 clutter_actor_get_stage (ClutterActor *actor)
13857 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13859 return _clutter_actor_get_stage_internal (actor);
13863 * clutter_actor_allocate_available_size:
13864 * @self: a #ClutterActor
13865 * @x: the actor's X coordinate
13866 * @y: the actor's Y coordinate
13867 * @available_width: the maximum available width, or -1 to use the
13868 * actor's natural width
13869 * @available_height: the maximum available height, or -1 to use the
13870 * actor's natural height
13871 * @flags: flags controlling the allocation
13873 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13874 * preferred size, but limiting it to the maximum available width
13875 * and height provided.
13877 * This function will do the right thing when dealing with the
13878 * actor's request mode.
13880 * The implementation of this function is equivalent to:
13883 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13885 * clutter_actor_get_preferred_width (self, available_height,
13887 * &natural_width);
13888 * width = CLAMP (natural_width, min_width, available_width);
13890 * clutter_actor_get_preferred_height (self, width,
13892 * &natural_height);
13893 * height = CLAMP (natural_height, min_height, available_height);
13897 * clutter_actor_get_preferred_height (self, available_width,
13899 * &natural_height);
13900 * height = CLAMP (natural_height, min_height, available_height);
13902 * clutter_actor_get_preferred_width (self, height,
13904 * &natural_width);
13905 * width = CLAMP (natural_width, min_width, available_width);
13908 * box.x1 = x; box.y1 = y;
13909 * box.x2 = box.x1 + available_width;
13910 * box.y2 = box.y1 + available_height;
13911 * clutter_actor_allocate (self, &box, flags);
13914 * This function can be used by fluid layout managers to allocate
13915 * an actor's preferred size without making it bigger than the area
13916 * available for the container.
13921 clutter_actor_allocate_available_size (ClutterActor *self,
13924 gfloat available_width,
13925 gfloat available_height,
13926 ClutterAllocationFlags flags)
13928 ClutterActorPrivate *priv;
13929 gfloat width, height;
13930 gfloat min_width, min_height;
13931 gfloat natural_width, natural_height;
13932 ClutterActorBox box;
13934 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13938 width = height = 0.0;
13940 switch (priv->request_mode)
13942 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13943 clutter_actor_get_preferred_width (self, available_height,
13946 width = CLAMP (natural_width, min_width, available_width);
13948 clutter_actor_get_preferred_height (self, width,
13951 height = CLAMP (natural_height, min_height, available_height);
13954 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13955 clutter_actor_get_preferred_height (self, available_width,
13958 height = CLAMP (natural_height, min_height, available_height);
13960 clutter_actor_get_preferred_width (self, height,
13963 width = CLAMP (natural_width, min_width, available_width);
13970 box.x2 = box.x1 + width;
13971 box.y2 = box.y1 + height;
13972 clutter_actor_allocate (self, &box, flags);
13976 * clutter_actor_allocate_preferred_size:
13977 * @self: a #ClutterActor
13978 * @flags: flags controlling the allocation
13980 * Allocates the natural size of @self.
13982 * This function is a utility call for #ClutterActor implementations
13983 * that allocates the actor's preferred natural size. It can be used
13984 * by fixed layout managers (like #ClutterGroup or so called
13985 * 'composite actors') inside the ClutterActor::allocate
13986 * implementation to give each child exactly how much space it
13989 * This function is not meant to be used by applications. It is also
13990 * not meant to be used outside the implementation of the
13991 * ClutterActor::allocate virtual function.
13996 clutter_actor_allocate_preferred_size (ClutterActor *self,
13997 ClutterAllocationFlags flags)
13999 gfloat actor_x, actor_y;
14000 gfloat natural_width, natural_height;
14001 ClutterActorBox actor_box;
14003 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14005 actor_x = clutter_actor_get_x (self);
14006 actor_y = clutter_actor_get_y (self);
14008 clutter_actor_get_preferred_size (self,
14013 actor_box.x1 = actor_x;
14014 actor_box.y1 = actor_y;
14015 actor_box.x2 = actor_box.x1 + natural_width;
14016 actor_box.y2 = actor_box.y1 + natural_height;
14018 clutter_actor_allocate (self, &actor_box, flags);
14022 * clutter_actor_allocate_align_fill:
14023 * @self: a #ClutterActor
14024 * @box: a #ClutterActorBox, containing the available width and height
14025 * @x_align: the horizontal alignment, between 0 and 1
14026 * @y_align: the vertical alignment, between 0 and 1
14027 * @x_fill: whether the actor should fill horizontally
14028 * @y_fill: whether the actor should fill vertically
14029 * @flags: allocation flags to be passed to clutter_actor_allocate()
14031 * Allocates @self by taking into consideration the available allocation
14032 * area; an alignment factor on either axis; and whether the actor should
14033 * fill the allocation on either axis.
14035 * The @box should contain the available allocation width and height;
14036 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
14037 * allocation will be offset by their value.
14039 * This function takes into consideration the geometry request specified by
14040 * the #ClutterActor:request-mode property, and the text direction.
14042 * This function is useful for fluid layout managers, like #ClutterBinLayout
14043 * or #ClutterTableLayout
14048 clutter_actor_allocate_align_fill (ClutterActor *self,
14049 const ClutterActorBox *box,
14054 ClutterAllocationFlags flags)
14056 ClutterActorPrivate *priv;
14057 ClutterActorBox allocation = { 0, };
14058 gfloat x_offset, y_offset;
14059 gfloat available_width, available_height;
14060 gfloat child_width, child_height;
14062 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14063 g_return_if_fail (box != NULL);
14064 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
14065 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
14069 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
14070 clutter_actor_box_get_size (box, &available_width, &available_height);
14072 if (available_width < 0)
14073 available_width = 0;
14075 if (available_height < 0)
14076 available_height = 0;
14080 allocation.x1 = x_offset;
14081 allocation.x2 = allocation.x1 + available_width;
14086 allocation.y1 = y_offset;
14087 allocation.y2 = allocation.y1 + available_height;
14090 /* if we are filling horizontally and vertically then we're done */
14091 if (x_fill && y_fill)
14094 child_width = child_height = 0.0f;
14096 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
14098 gfloat min_width, natural_width;
14099 gfloat min_height, natural_height;
14101 clutter_actor_get_preferred_width (self, available_height,
14105 child_width = CLAMP (natural_width, min_width, available_width);
14109 clutter_actor_get_preferred_height (self, child_width,
14113 child_height = CLAMP (natural_height, min_height, available_height);
14118 gfloat min_width, natural_width;
14119 gfloat min_height, natural_height;
14121 clutter_actor_get_preferred_height (self, available_width,
14125 child_height = CLAMP (natural_height, min_height, available_height);
14129 clutter_actor_get_preferred_width (self, child_height,
14133 child_width = CLAMP (natural_width, min_width, available_width);
14137 /* invert the horizontal alignment for RTL languages */
14138 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
14139 x_align = 1.0 - x_align;
14143 allocation.x1 = x_offset
14144 + ((available_width - child_width) * x_align);
14145 allocation.x2 = allocation.x1 + child_width;
14150 allocation.y1 = y_offset
14151 + ((available_height - child_height) * y_align);
14152 allocation.y2 = allocation.y1 + child_height;
14156 clutter_actor_box_clamp_to_pixel (&allocation);
14157 clutter_actor_allocate (self, &allocation, flags);
14161 * clutter_actor_grab_key_focus:
14162 * @self: a #ClutterActor
14164 * Sets the key focus of the #ClutterStage including @self
14165 * to this #ClutterActor.
14170 clutter_actor_grab_key_focus (ClutterActor *self)
14172 ClutterActor *stage;
14174 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14176 stage = _clutter_actor_get_stage_internal (self);
14178 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14182 * clutter_actor_get_pango_context:
14183 * @self: a #ClutterActor
14185 * Retrieves the #PangoContext for @self. The actor's #PangoContext
14186 * is already configured using the appropriate font map, resolution
14187 * and font options.
14189 * Unlike clutter_actor_create_pango_context(), this context is owend
14190 * by the #ClutterActor and it will be updated each time the options
14191 * stored by the #ClutterBackend change.
14193 * You can use the returned #PangoContext to create a #PangoLayout
14194 * and render text using cogl_pango_render_layout() to reuse the
14195 * glyphs cache also used by Clutter.
14197 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14198 * The returned #PangoContext is owned by the actor and should not be
14199 * unreferenced by the application code
14204 clutter_actor_get_pango_context (ClutterActor *self)
14206 ClutterActorPrivate *priv;
14208 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14212 if (priv->pango_context != NULL)
14213 return priv->pango_context;
14215 priv->pango_context = _clutter_context_get_pango_context ();
14216 g_object_ref (priv->pango_context);
14218 return priv->pango_context;
14222 * clutter_actor_create_pango_context:
14223 * @self: a #ClutterActor
14225 * Creates a #PangoContext for the given actor. The #PangoContext
14226 * is already configured using the appropriate font map, resolution
14227 * and font options.
14229 * See also clutter_actor_get_pango_context().
14231 * Return value: (transfer full): the newly created #PangoContext.
14232 * Use g_object_unref() on the returned value to deallocate its
14238 clutter_actor_create_pango_context (ClutterActor *self)
14240 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14242 return _clutter_context_create_pango_context ();
14246 * clutter_actor_create_pango_layout:
14247 * @self: a #ClutterActor
14248 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14250 * Creates a new #PangoLayout from the same #PangoContext used
14251 * by the #ClutterActor. The #PangoLayout is already configured
14252 * with the font map, resolution and font options, and the
14255 * If you want to keep around a #PangoLayout created by this
14256 * function you will have to connect to the #ClutterBackend::font-changed
14257 * and #ClutterBackend::resolution-changed signals, and call
14258 * pango_layout_context_changed() in response to them.
14260 * Return value: (transfer full): the newly created #PangoLayout.
14261 * Use g_object_unref() when done
14266 clutter_actor_create_pango_layout (ClutterActor *self,
14269 PangoContext *context;
14270 PangoLayout *layout;
14272 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14274 context = clutter_actor_get_pango_context (self);
14275 layout = pango_layout_new (context);
14278 pango_layout_set_text (layout, text, -1);
14283 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14284 * ClutterOffscreenEffect.
14287 _clutter_actor_set_opacity_override (ClutterActor *self,
14290 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14292 self->priv->opacity_override = opacity;
14296 _clutter_actor_get_opacity_override (ClutterActor *self)
14298 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14300 return self->priv->opacity_override;
14303 /* Allows you to disable applying the actors model view transform during
14304 * a paint. Used by ClutterClone. */
14306 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14309 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14311 self->priv->enable_model_view_transform = enable;
14315 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14318 ClutterActorPrivate *priv;
14320 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14324 priv->enable_paint_unmapped = enable;
14326 if (priv->enable_paint_unmapped)
14328 /* Make sure that the parents of the widget are realized first;
14329 * otherwise checks in clutter_actor_update_map_state() will
14332 clutter_actor_realize (self);
14334 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14338 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14343 clutter_anchor_coord_get_units (ClutterActor *self,
14344 const AnchorCoord *coord,
14349 if (coord->is_fractional)
14351 gfloat actor_width, actor_height;
14353 clutter_actor_get_size (self, &actor_width, &actor_height);
14356 *x = actor_width * coord->v.fraction.x;
14359 *y = actor_height * coord->v.fraction.y;
14367 *x = coord->v.units.x;
14370 *y = coord->v.units.y;
14373 *z = coord->v.units.z;
14378 clutter_anchor_coord_set_units (AnchorCoord *coord,
14383 coord->is_fractional = FALSE;
14384 coord->v.units.x = x;
14385 coord->v.units.y = y;
14386 coord->v.units.z = z;
14389 static ClutterGravity
14390 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14392 if (coord->is_fractional)
14394 if (coord->v.fraction.x == 0.0)
14396 if (coord->v.fraction.y == 0.0)
14397 return CLUTTER_GRAVITY_NORTH_WEST;
14398 else if (coord->v.fraction.y == 0.5)
14399 return CLUTTER_GRAVITY_WEST;
14400 else if (coord->v.fraction.y == 1.0)
14401 return CLUTTER_GRAVITY_SOUTH_WEST;
14403 return CLUTTER_GRAVITY_NONE;
14405 else if (coord->v.fraction.x == 0.5)
14407 if (coord->v.fraction.y == 0.0)
14408 return CLUTTER_GRAVITY_NORTH;
14409 else if (coord->v.fraction.y == 0.5)
14410 return CLUTTER_GRAVITY_CENTER;
14411 else if (coord->v.fraction.y == 1.0)
14412 return CLUTTER_GRAVITY_SOUTH;
14414 return CLUTTER_GRAVITY_NONE;
14416 else if (coord->v.fraction.x == 1.0)
14418 if (coord->v.fraction.y == 0.0)
14419 return CLUTTER_GRAVITY_NORTH_EAST;
14420 else if (coord->v.fraction.y == 0.5)
14421 return CLUTTER_GRAVITY_EAST;
14422 else if (coord->v.fraction.y == 1.0)
14423 return CLUTTER_GRAVITY_SOUTH_EAST;
14425 return CLUTTER_GRAVITY_NONE;
14428 return CLUTTER_GRAVITY_NONE;
14431 return CLUTTER_GRAVITY_NONE;
14435 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14436 ClutterGravity gravity)
14440 case CLUTTER_GRAVITY_NORTH:
14441 coord->v.fraction.x = 0.5;
14442 coord->v.fraction.y = 0.0;
14445 case CLUTTER_GRAVITY_NORTH_EAST:
14446 coord->v.fraction.x = 1.0;
14447 coord->v.fraction.y = 0.0;
14450 case CLUTTER_GRAVITY_EAST:
14451 coord->v.fraction.x = 1.0;
14452 coord->v.fraction.y = 0.5;
14455 case CLUTTER_GRAVITY_SOUTH_EAST:
14456 coord->v.fraction.x = 1.0;
14457 coord->v.fraction.y = 1.0;
14460 case CLUTTER_GRAVITY_SOUTH:
14461 coord->v.fraction.x = 0.5;
14462 coord->v.fraction.y = 1.0;
14465 case CLUTTER_GRAVITY_SOUTH_WEST:
14466 coord->v.fraction.x = 0.0;
14467 coord->v.fraction.y = 1.0;
14470 case CLUTTER_GRAVITY_WEST:
14471 coord->v.fraction.x = 0.0;
14472 coord->v.fraction.y = 0.5;
14475 case CLUTTER_GRAVITY_NORTH_WEST:
14476 coord->v.fraction.x = 0.0;
14477 coord->v.fraction.y = 0.0;
14480 case CLUTTER_GRAVITY_CENTER:
14481 coord->v.fraction.x = 0.5;
14482 coord->v.fraction.y = 0.5;
14486 coord->v.fraction.x = 0.0;
14487 coord->v.fraction.y = 0.0;
14491 coord->is_fractional = TRUE;
14495 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14497 if (coord->is_fractional)
14498 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14500 return (coord->v.units.x == 0.0
14501 && coord->v.units.y == 0.0
14502 && coord->v.units.z == 0.0);
14506 * clutter_actor_get_flags:
14507 * @self: a #ClutterActor
14509 * Retrieves the flags set on @self
14511 * Return value: a bitwise or of #ClutterActorFlags or 0
14516 clutter_actor_get_flags (ClutterActor *self)
14518 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14520 return self->flags;
14524 * clutter_actor_set_flags:
14525 * @self: a #ClutterActor
14526 * @flags: the flags to set
14528 * Sets @flags on @self
14530 * This function will emit notifications for the changed properties
14535 clutter_actor_set_flags (ClutterActor *self,
14536 ClutterActorFlags flags)
14538 ClutterActorFlags old_flags;
14540 gboolean was_reactive_set, reactive_set;
14541 gboolean was_realized_set, realized_set;
14542 gboolean was_mapped_set, mapped_set;
14543 gboolean was_visible_set, visible_set;
14545 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14547 if (self->flags == flags)
14550 obj = G_OBJECT (self);
14551 g_object_ref (obj);
14552 g_object_freeze_notify (obj);
14554 old_flags = self->flags;
14556 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14557 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14558 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14559 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14561 self->flags |= flags;
14563 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14564 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14565 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14566 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14568 if (reactive_set != was_reactive_set)
14569 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14571 if (realized_set != was_realized_set)
14572 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14574 if (mapped_set != was_mapped_set)
14575 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14577 if (visible_set != was_visible_set)
14578 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14580 g_object_thaw_notify (obj);
14581 g_object_unref (obj);
14585 * clutter_actor_unset_flags:
14586 * @self: a #ClutterActor
14587 * @flags: the flags to unset
14589 * Unsets @flags on @self
14591 * This function will emit notifications for the changed properties
14596 clutter_actor_unset_flags (ClutterActor *self,
14597 ClutterActorFlags flags)
14599 ClutterActorFlags old_flags;
14601 gboolean was_reactive_set, reactive_set;
14602 gboolean was_realized_set, realized_set;
14603 gboolean was_mapped_set, mapped_set;
14604 gboolean was_visible_set, visible_set;
14606 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14608 obj = G_OBJECT (self);
14609 g_object_freeze_notify (obj);
14611 old_flags = self->flags;
14613 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14614 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14615 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14616 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14618 self->flags &= ~flags;
14620 if (self->flags == old_flags)
14623 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14624 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14625 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14626 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14628 if (reactive_set != was_reactive_set)
14629 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14631 if (realized_set != was_realized_set)
14632 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14634 if (mapped_set != was_mapped_set)
14635 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14637 if (visible_set != was_visible_set)
14638 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14640 g_object_thaw_notify (obj);
14644 * clutter_actor_get_transformation_matrix:
14645 * @self: a #ClutterActor
14646 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14648 * Retrieves the transformations applied to @self relative to its
14654 clutter_actor_get_transformation_matrix (ClutterActor *self,
14655 CoglMatrix *matrix)
14657 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14659 cogl_matrix_init_identity (matrix);
14661 _clutter_actor_apply_modelview_transform (self, matrix);
14665 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14666 gboolean is_in_clone_paint)
14668 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14669 self->priv->in_clone_paint = is_in_clone_paint;
14673 * clutter_actor_is_in_clone_paint:
14674 * @self: a #ClutterActor
14676 * Checks whether @self is being currently painted by a #ClutterClone
14678 * This function is useful only inside the ::paint virtual function
14679 * implementations or within handlers for the #ClutterActor::paint
14682 * This function should not be used by applications
14684 * Return value: %TRUE if the #ClutterActor is currently being painted
14685 * by a #ClutterClone, and %FALSE otherwise
14690 clutter_actor_is_in_clone_paint (ClutterActor *self)
14692 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14694 return self->priv->in_clone_paint;
14698 set_direction_recursive (ClutterActor *actor,
14699 gpointer user_data)
14701 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14703 clutter_actor_set_text_direction (actor, text_dir);
14709 * clutter_actor_set_text_direction:
14710 * @self: a #ClutterActor
14711 * @text_dir: the text direction for @self
14713 * Sets the #ClutterTextDirection for an actor
14715 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14717 * If @self implements #ClutterContainer then this function will recurse
14718 * inside all the children of @self (including the internal ones).
14720 * Composite actors not implementing #ClutterContainer, or actors requiring
14721 * special handling when the text direction changes, should connect to
14722 * the #GObject::notify signal for the #ClutterActor:text-direction property
14727 clutter_actor_set_text_direction (ClutterActor *self,
14728 ClutterTextDirection text_dir)
14730 ClutterActorPrivate *priv;
14732 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14733 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14737 if (priv->text_direction != text_dir)
14739 priv->text_direction = text_dir;
14741 /* we need to emit the notify::text-direction first, so that
14742 * the sub-classes can catch that and do specific handling of
14743 * the text direction; see clutter_text_direction_changed_cb()
14744 * inside clutter-text.c
14746 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14748 _clutter_actor_foreach_child (self, set_direction_recursive,
14749 GINT_TO_POINTER (text_dir));
14751 clutter_actor_queue_relayout (self);
14756 _clutter_actor_set_has_pointer (ClutterActor *self,
14757 gboolean has_pointer)
14759 ClutterActorPrivate *priv = self->priv;
14761 if (priv->has_pointer != has_pointer)
14763 priv->has_pointer = has_pointer;
14765 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14770 * clutter_actor_get_text_direction:
14771 * @self: a #ClutterActor
14773 * Retrieves the value set using clutter_actor_set_text_direction()
14775 * If no text direction has been previously set, the default text
14776 * direction, as returned by clutter_get_default_text_direction(), will
14777 * be returned instead
14779 * Return value: the #ClutterTextDirection for the actor
14783 ClutterTextDirection
14784 clutter_actor_get_text_direction (ClutterActor *self)
14786 ClutterActorPrivate *priv;
14788 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14789 CLUTTER_TEXT_DIRECTION_LTR);
14793 /* if no direction has been set yet use the default */
14794 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14795 priv->text_direction = clutter_get_default_text_direction ();
14797 return priv->text_direction;
14801 * clutter_actor_push_internal:
14802 * @self: a #ClutterActor
14804 * Should be used by actors implementing the #ClutterContainer and with
14805 * internal children added through clutter_actor_set_parent(), for instance:
14809 * my_actor_init (MyActor *self)
14811 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14813 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14815 * /* calling clutter_actor_set_parent() now will result in
14816 * * the internal flag being set on a child of MyActor
14819 * /* internal child - a background texture */
14820 * self->priv->background_tex = clutter_texture_new ();
14821 * clutter_actor_set_parent (self->priv->background_tex,
14822 * CLUTTER_ACTOR (self));
14824 * /* internal child - a label */
14825 * self->priv->label = clutter_text_new ();
14826 * clutter_actor_set_parent (self->priv->label,
14827 * CLUTTER_ACTOR (self));
14829 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14831 * /* calling clutter_actor_set_parent() now will not result in
14832 * * the internal flag being set on a child of MyActor
14837 * This function will be used by Clutter to toggle an "internal child"
14838 * flag whenever clutter_actor_set_parent() is called; internal children
14839 * are handled differently by Clutter, specifically when destroying their
14842 * Call clutter_actor_pop_internal() when you finished adding internal
14845 * Nested calls to clutter_actor_push_internal() are allowed, but each
14846 * one must by followed by a clutter_actor_pop_internal() call.
14850 * Deprecated: 1.10: All children of an actor are accessible through
14851 * the #ClutterActor API, and #ClutterActor implements the
14852 * #ClutterContainer interface, so this function is only useful
14853 * for legacy containers overriding the default implementation.
14856 clutter_actor_push_internal (ClutterActor *self)
14858 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14860 self->priv->internal_child += 1;
14864 * clutter_actor_pop_internal:
14865 * @self: a #ClutterActor
14867 * Disables the effects of clutter_actor_push_internal().
14871 * Deprecated: 1.10: All children of an actor are accessible through
14872 * the #ClutterActor API. This function is only useful for legacy
14873 * containers overriding the default implementation of the
14874 * #ClutterContainer interface.
14877 clutter_actor_pop_internal (ClutterActor *self)
14879 ClutterActorPrivate *priv;
14881 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14885 if (priv->internal_child == 0)
14887 g_warning ("Mismatched %s: you need to call "
14888 "clutter_actor_push_composite() at least once before "
14889 "calling this function", G_STRFUNC);
14893 priv->internal_child -= 1;
14897 * clutter_actor_has_pointer:
14898 * @self: a #ClutterActor
14900 * Checks whether an actor contains the pointer of a
14901 * #ClutterInputDevice
14903 * Return value: %TRUE if the actor contains the pointer, and
14909 clutter_actor_has_pointer (ClutterActor *self)
14911 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14913 return self->priv->has_pointer;
14916 /* XXX: This is a workaround for not being able to break the ABI of
14917 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14918 * clutter_actor_queue_clipped_redraw() for details.
14920 ClutterPaintVolume *
14921 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14923 return g_object_get_data (G_OBJECT (self),
14924 "-clutter-actor-queue-redraw-clip");
14928 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14929 ClutterPaintVolume *clip)
14931 g_object_set_data (G_OBJECT (self),
14932 "-clutter-actor-queue-redraw-clip",
14937 * clutter_actor_has_allocation:
14938 * @self: a #ClutterActor
14940 * Checks if the actor has an up-to-date allocation assigned to
14941 * it. This means that the actor should have an allocation: it's
14942 * visible and has a parent. It also means that there is no
14943 * outstanding relayout request in progress for the actor or its
14944 * children (There might be other outstanding layout requests in
14945 * progress that will cause the actor to get a new allocation
14946 * when the stage is laid out, however).
14948 * If this function returns %FALSE, then the actor will normally
14949 * be allocated before it is next drawn on the screen.
14951 * Return value: %TRUE if the actor has an up-to-date allocation
14956 clutter_actor_has_allocation (ClutterActor *self)
14958 ClutterActorPrivate *priv;
14960 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14964 return priv->parent != NULL &&
14965 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14966 !priv->needs_allocation;
14970 * clutter_actor_add_action:
14971 * @self: a #ClutterActor
14972 * @action: a #ClutterAction
14974 * Adds @action to the list of actions applied to @self
14976 * A #ClutterAction can only belong to one actor at a time
14978 * The #ClutterActor will hold a reference on @action until either
14979 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14985 clutter_actor_add_action (ClutterActor *self,
14986 ClutterAction *action)
14988 ClutterActorPrivate *priv;
14990 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14991 g_return_if_fail (CLUTTER_IS_ACTION (action));
14995 if (priv->actions == NULL)
14997 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14998 priv->actions->actor = self;
15001 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
15003 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15007 * clutter_actor_add_action_with_name:
15008 * @self: a #ClutterActor
15009 * @name: the name to set on the action
15010 * @action: a #ClutterAction
15012 * A convenience function for setting the name of a #ClutterAction
15013 * while adding it to the list of actions applied to @self
15015 * This function is the logical equivalent of:
15018 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15019 * clutter_actor_add_action (self, action);
15025 clutter_actor_add_action_with_name (ClutterActor *self,
15027 ClutterAction *action)
15029 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15030 g_return_if_fail (name != NULL);
15031 g_return_if_fail (CLUTTER_IS_ACTION (action));
15033 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15034 clutter_actor_add_action (self, action);
15038 * clutter_actor_remove_action:
15039 * @self: a #ClutterActor
15040 * @action: a #ClutterAction
15042 * Removes @action from the list of actions applied to @self
15044 * The reference held by @self on the #ClutterAction will be released
15049 clutter_actor_remove_action (ClutterActor *self,
15050 ClutterAction *action)
15052 ClutterActorPrivate *priv;
15054 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15055 g_return_if_fail (CLUTTER_IS_ACTION (action));
15059 if (priv->actions == NULL)
15062 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
15064 if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
15065 g_clear_object (&priv->actions);
15067 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15071 * clutter_actor_remove_action_by_name:
15072 * @self: a #ClutterActor
15073 * @name: the name of the action to remove
15075 * Removes the #ClutterAction with the given name from the list
15076 * of actions applied to @self
15081 clutter_actor_remove_action_by_name (ClutterActor *self,
15084 ClutterActorPrivate *priv;
15085 ClutterActorMeta *meta;
15087 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15088 g_return_if_fail (name != NULL);
15092 if (priv->actions == NULL)
15095 meta = _clutter_meta_group_get_meta (priv->actions, name);
15099 _clutter_meta_group_remove_meta (priv->actions, meta);
15101 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15105 * clutter_actor_get_actions:
15106 * @self: a #ClutterActor
15108 * Retrieves the list of actions applied to @self
15110 * Return value: (transfer container) (element-type Clutter.Action): a copy
15111 * of the list of #ClutterAction<!-- -->s. The contents of the list are
15112 * owned by the #ClutterActor. Use g_list_free() to free the resources
15113 * allocated by the returned #GList
15118 clutter_actor_get_actions (ClutterActor *self)
15120 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15122 if (self->priv->actions == NULL)
15125 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
15129 * clutter_actor_get_action:
15130 * @self: a #ClutterActor
15131 * @name: the name of the action to retrieve
15133 * Retrieves the #ClutterAction with the given name in the list
15134 * of actions applied to @self
15136 * Return value: (transfer none): a #ClutterAction for the given
15137 * name, or %NULL. The returned #ClutterAction is owned by the
15138 * actor and it should not be unreferenced directly
15143 clutter_actor_get_action (ClutterActor *self,
15146 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15147 g_return_val_if_fail (name != NULL, NULL);
15149 if (self->priv->actions == NULL)
15152 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
15156 * clutter_actor_clear_actions:
15157 * @self: a #ClutterActor
15159 * Clears the list of actions applied to @self
15164 clutter_actor_clear_actions (ClutterActor *self)
15166 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15168 if (self->priv->actions == NULL)
15171 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
15175 * clutter_actor_add_constraint:
15176 * @self: a #ClutterActor
15177 * @constraint: a #ClutterConstraint
15179 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15182 * The #ClutterActor will hold a reference on the @constraint until
15183 * either clutter_actor_remove_constraint() or
15184 * clutter_actor_clear_constraints() is called.
15189 clutter_actor_add_constraint (ClutterActor *self,
15190 ClutterConstraint *constraint)
15192 ClutterActorPrivate *priv;
15194 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15195 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15199 if (priv->constraints == NULL)
15201 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15202 priv->constraints->actor = self;
15205 _clutter_meta_group_add_meta (priv->constraints,
15206 CLUTTER_ACTOR_META (constraint));
15207 clutter_actor_queue_relayout (self);
15209 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15213 * clutter_actor_add_constraint_with_name:
15214 * @self: a #ClutterActor
15215 * @name: the name to set on the constraint
15216 * @constraint: a #ClutterConstraint
15218 * A convenience function for setting the name of a #ClutterConstraint
15219 * while adding it to the list of constraints applied to @self
15221 * This function is the logical equivalent of:
15224 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15225 * clutter_actor_add_constraint (self, constraint);
15231 clutter_actor_add_constraint_with_name (ClutterActor *self,
15233 ClutterConstraint *constraint)
15235 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15236 g_return_if_fail (name != NULL);
15237 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15239 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15240 clutter_actor_add_constraint (self, constraint);
15244 * clutter_actor_remove_constraint:
15245 * @self: a #ClutterActor
15246 * @constraint: a #ClutterConstraint
15248 * Removes @constraint from the list of constraints applied to @self
15250 * The reference held by @self on the #ClutterConstraint will be released
15255 clutter_actor_remove_constraint (ClutterActor *self,
15256 ClutterConstraint *constraint)
15258 ClutterActorPrivate *priv;
15260 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15261 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15265 if (priv->constraints == NULL)
15268 _clutter_meta_group_remove_meta (priv->constraints,
15269 CLUTTER_ACTOR_META (constraint));
15271 if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15272 g_clear_object (&priv->constraints);
15274 clutter_actor_queue_relayout (self);
15276 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15280 * clutter_actor_remove_constraint_by_name:
15281 * @self: a #ClutterActor
15282 * @name: the name of the constraint to remove
15284 * Removes the #ClutterConstraint with the given name from the list
15285 * of constraints applied to @self
15290 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15293 ClutterActorPrivate *priv;
15294 ClutterActorMeta *meta;
15296 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15297 g_return_if_fail (name != NULL);
15301 if (priv->constraints == NULL)
15304 meta = _clutter_meta_group_get_meta (priv->constraints, name);
15308 _clutter_meta_group_remove_meta (priv->constraints, meta);
15309 clutter_actor_queue_relayout (self);
15313 * clutter_actor_get_constraints:
15314 * @self: a #ClutterActor
15316 * Retrieves the list of constraints applied to @self
15318 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15319 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15320 * owned by the #ClutterActor. Use g_list_free() to free the resources
15321 * allocated by the returned #GList
15326 clutter_actor_get_constraints (ClutterActor *self)
15328 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15330 if (self->priv->constraints == NULL)
15333 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15337 * clutter_actor_get_constraint:
15338 * @self: a #ClutterActor
15339 * @name: the name of the constraint to retrieve
15341 * Retrieves the #ClutterConstraint with the given name in the list
15342 * of constraints applied to @self
15344 * Return value: (transfer none): a #ClutterConstraint for the given
15345 * name, or %NULL. The returned #ClutterConstraint is owned by the
15346 * actor and it should not be unreferenced directly
15350 ClutterConstraint *
15351 clutter_actor_get_constraint (ClutterActor *self,
15354 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15355 g_return_val_if_fail (name != NULL, NULL);
15357 if (self->priv->constraints == NULL)
15360 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15364 * clutter_actor_clear_constraints:
15365 * @self: a #ClutterActor
15367 * Clears the list of constraints applied to @self
15372 clutter_actor_clear_constraints (ClutterActor *self)
15374 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15376 if (self->priv->constraints == NULL)
15379 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15381 clutter_actor_queue_relayout (self);
15385 * clutter_actor_set_clip_to_allocation:
15386 * @self: a #ClutterActor
15387 * @clip_set: %TRUE to apply a clip tracking the allocation
15389 * Sets whether @self should be clipped to the same size as its
15395 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15398 ClutterActorPrivate *priv;
15400 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15402 clip_set = !!clip_set;
15406 if (priv->clip_to_allocation != clip_set)
15408 priv->clip_to_allocation = clip_set;
15410 clutter_actor_queue_redraw (self);
15412 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15417 * clutter_actor_get_clip_to_allocation:
15418 * @self: a #ClutterActor
15420 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15422 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15427 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15429 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15431 return self->priv->clip_to_allocation;
15435 * clutter_actor_add_effect:
15436 * @self: a #ClutterActor
15437 * @effect: a #ClutterEffect
15439 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15441 * The #ClutterActor will hold a reference on the @effect until either
15442 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15448 clutter_actor_add_effect (ClutterActor *self,
15449 ClutterEffect *effect)
15451 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15452 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15454 _clutter_actor_add_effect_internal (self, effect);
15456 clutter_actor_queue_redraw (self);
15458 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15462 * clutter_actor_add_effect_with_name:
15463 * @self: a #ClutterActor
15464 * @name: the name to set on the effect
15465 * @effect: a #ClutterEffect
15467 * A convenience function for setting the name of a #ClutterEffect
15468 * while adding it to the list of effectss applied to @self
15470 * This function is the logical equivalent of:
15473 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15474 * clutter_actor_add_effect (self, effect);
15480 clutter_actor_add_effect_with_name (ClutterActor *self,
15482 ClutterEffect *effect)
15484 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15485 g_return_if_fail (name != NULL);
15486 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15488 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15489 clutter_actor_add_effect (self, effect);
15493 * clutter_actor_remove_effect:
15494 * @self: a #ClutterActor
15495 * @effect: a #ClutterEffect
15497 * Removes @effect from the list of effects applied to @self
15499 * The reference held by @self on the #ClutterEffect will be released
15504 clutter_actor_remove_effect (ClutterActor *self,
15505 ClutterEffect *effect)
15507 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15508 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15510 _clutter_actor_remove_effect_internal (self, effect);
15512 clutter_actor_queue_redraw (self);
15514 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15518 * clutter_actor_remove_effect_by_name:
15519 * @self: a #ClutterActor
15520 * @name: the name of the effect to remove
15522 * Removes the #ClutterEffect with the given name from the list
15523 * of effects applied to @self
15528 clutter_actor_remove_effect_by_name (ClutterActor *self,
15531 ClutterActorPrivate *priv;
15532 ClutterActorMeta *meta;
15534 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15535 g_return_if_fail (name != NULL);
15539 if (priv->effects == NULL)
15542 meta = _clutter_meta_group_get_meta (priv->effects, name);
15546 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15550 * clutter_actor_get_effects:
15551 * @self: a #ClutterActor
15553 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15555 * Return value: (transfer container) (element-type Clutter.Effect): a list
15556 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15557 * list are owned by Clutter and they should not be freed. You should
15558 * free the returned list using g_list_free() when done
15563 clutter_actor_get_effects (ClutterActor *self)
15565 ClutterActorPrivate *priv;
15567 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15571 if (priv->effects == NULL)
15574 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15578 * clutter_actor_get_effect:
15579 * @self: a #ClutterActor
15580 * @name: the name of the effect to retrieve
15582 * Retrieves the #ClutterEffect with the given name in the list
15583 * of effects applied to @self
15585 * Return value: (transfer none): a #ClutterEffect for the given
15586 * name, or %NULL. The returned #ClutterEffect is owned by the
15587 * actor and it should not be unreferenced directly
15592 clutter_actor_get_effect (ClutterActor *self,
15595 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15596 g_return_val_if_fail (name != NULL, NULL);
15598 if (self->priv->effects == NULL)
15601 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15605 * clutter_actor_clear_effects:
15606 * @self: a #ClutterActor
15608 * Clears the list of effects applied to @self
15613 clutter_actor_clear_effects (ClutterActor *self)
15615 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15617 if (self->priv->effects == NULL)
15620 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15622 clutter_actor_queue_redraw (self);
15626 * clutter_actor_has_key_focus:
15627 * @self: a #ClutterActor
15629 * Checks whether @self is the #ClutterActor that has key focus
15631 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15636 clutter_actor_has_key_focus (ClutterActor *self)
15638 ClutterActor *stage;
15640 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15642 stage = _clutter_actor_get_stage_internal (self);
15646 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15650 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15651 ClutterPaintVolume *pv)
15653 ClutterActorPrivate *priv = self->priv;
15655 /* Actors are only expected to report a valid paint volume
15656 * while they have a valid allocation. */
15657 if (G_UNLIKELY (priv->needs_allocation))
15659 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15660 "Actor needs allocation",
15661 _clutter_actor_get_debug_name (self));
15665 /* Check if there are any handlers connected to the paint
15666 * signal. If there are then all bets are off for what the paint
15667 * volume for this actor might possibly be!
15669 * XXX: It's expected that this is going to end up being quite a
15670 * costly check to have to do here, but we haven't come up with
15671 * another solution that can reliably catch paint signal handlers at
15672 * the right time to either avoid artefacts due to invalid stage
15673 * clipping or due to incorrect culling.
15675 * Previously we checked in clutter_actor_paint(), but at that time
15676 * we may already be using a stage clip that could be derived from
15677 * an invalid paint-volume. We used to try and handle that by
15678 * queuing a follow up, unclipped, redraw but still the previous
15679 * checking wasn't enough to catch invalid volumes involved in
15680 * culling (considering that containers may derive their volume from
15681 * children that haven't yet been painted)
15683 * Longer term, improved solutions could be:
15684 * - Disallow painting in the paint signal, only allow using it
15685 * for tracking when paints happen. We can add another API that
15686 * allows monkey patching the paint of arbitrary actors but in a
15687 * more controlled way and that also supports modifying the
15689 * - If we could be notified somehow when signal handlers are
15690 * connected we wouldn't have to poll for handlers like this.
15692 if (g_signal_has_handler_pending (self,
15693 actor_signals[PAINT],
15697 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15698 "Actor has \"paint\" signal handlers",
15699 _clutter_actor_get_debug_name (self));
15703 _clutter_paint_volume_init_static (pv, self);
15705 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15707 clutter_paint_volume_free (pv);
15708 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15709 "Actor failed to report a volume",
15710 _clutter_actor_get_debug_name (self));
15714 /* since effects can modify the paint volume, we allow them to actually
15715 * do this by making get_paint_volume() "context sensitive"
15717 if (priv->effects != NULL)
15719 if (priv->current_effect != NULL)
15721 const GList *effects, *l;
15723 /* if we are being called from within the paint sequence of
15724 * an actor, get the paint volume up to the current effect
15726 effects = _clutter_meta_group_peek_metas (priv->effects);
15728 l != NULL || (l != NULL && l->data != priv->current_effect);
15731 if (!_clutter_effect_get_paint_volume (l->data, pv))
15733 clutter_paint_volume_free (pv);
15734 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15735 "Effect (%s) failed to report a volume",
15736 _clutter_actor_get_debug_name (self),
15737 _clutter_actor_meta_get_debug_name (l->data));
15744 const GList *effects, *l;
15746 /* otherwise, get the cumulative volume */
15747 effects = _clutter_meta_group_peek_metas (priv->effects);
15748 for (l = effects; l != NULL; l = l->next)
15749 if (!_clutter_effect_get_paint_volume (l->data, pv))
15751 clutter_paint_volume_free (pv);
15752 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15753 "Effect (%s) failed to report a volume",
15754 _clutter_actor_get_debug_name (self),
15755 _clutter_actor_meta_get_debug_name (l->data));
15764 /* The public clutter_actor_get_paint_volume API returns a const
15765 * pointer since we return a pointer directly to the cached
15766 * PaintVolume associated with the actor and don't want the user to
15767 * inadvertently modify it, but for internal uses we sometimes need
15768 * access to the same PaintVolume but need to apply some book-keeping
15769 * modifications to it so we don't want a const pointer.
15771 static ClutterPaintVolume *
15772 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15774 ClutterActorPrivate *priv;
15778 if (priv->paint_volume_valid)
15779 clutter_paint_volume_free (&priv->paint_volume);
15781 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15783 priv->paint_volume_valid = TRUE;
15784 return &priv->paint_volume;
15788 priv->paint_volume_valid = FALSE;
15794 * clutter_actor_get_paint_volume:
15795 * @self: a #ClutterActor
15797 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15798 * when a paint volume can't be determined.
15800 * The paint volume is defined as the 3D space occupied by an actor
15801 * when being painted.
15803 * This function will call the <function>get_paint_volume()</function>
15804 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15805 * should not usually care about overriding the default implementation,
15806 * unless they are, for instance: painting outside their allocation, or
15807 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15810 * <note>2D actors overriding <function>get_paint_volume()</function>
15811 * ensure their volume has a depth of 0. (This will be true so long as
15812 * you don't call clutter_paint_volume_set_depth().)</note>
15814 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15815 * or %NULL if no volume could be determined. The returned pointer
15816 * is not guaranteed to be valid across multiple frames; if you want
15817 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15821 const ClutterPaintVolume *
15822 clutter_actor_get_paint_volume (ClutterActor *self)
15824 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15826 return _clutter_actor_get_paint_volume_mutable (self);
15830 * clutter_actor_get_transformed_paint_volume:
15831 * @self: a #ClutterActor
15832 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15833 * (or %NULL for the stage)
15835 * Retrieves the 3D paint volume of an actor like
15836 * clutter_actor_get_paint_volume() does (Please refer to the
15837 * documentation of clutter_actor_get_paint_volume() for more
15838 * details.) and it additionally transforms the paint volume into the
15839 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15840 * is passed for @relative_to_ancestor)
15842 * This can be used by containers that base their paint volume on
15843 * the volume of their children. Such containers can query the
15844 * transformed paint volume of all of its children and union them
15845 * together using clutter_paint_volume_union().
15847 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15848 * or %NULL if no volume could be determined. The returned pointer is
15849 * not guaranteed to be valid across multiple frames; if you wish to
15850 * keep it, you will have to copy it using clutter_paint_volume_copy().
15854 const ClutterPaintVolume *
15855 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15856 ClutterActor *relative_to_ancestor)
15858 const ClutterPaintVolume *volume;
15859 ClutterActor *stage;
15860 ClutterPaintVolume *transformed_volume;
15862 stage = _clutter_actor_get_stage_internal (self);
15863 if (G_UNLIKELY (stage == NULL))
15866 if (relative_to_ancestor == NULL)
15867 relative_to_ancestor = stage;
15869 volume = clutter_actor_get_paint_volume (self);
15870 if (volume == NULL)
15873 transformed_volume =
15874 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15876 _clutter_paint_volume_copy_static (volume, transformed_volume);
15878 _clutter_paint_volume_transform_relative (transformed_volume,
15879 relative_to_ancestor);
15881 return transformed_volume;
15885 * clutter_actor_get_paint_box:
15886 * @self: a #ClutterActor
15887 * @box: (out): return location for a #ClutterActorBox
15889 * Retrieves the paint volume of the passed #ClutterActor, and
15890 * transforms it into a 2D bounding box in stage coordinates.
15892 * This function is useful to determine the on screen area occupied by
15893 * the actor. The box is only an approximation and may often be
15894 * considerably larger due to the optimizations used to calculate the
15895 * box. The box is never smaller though, so it can reliably be used
15898 * There are times when a 2D paint box can't be determined, e.g.
15899 * because the actor isn't yet parented under a stage or because
15900 * the actor is unable to determine a paint volume.
15902 * Return value: %TRUE if a 2D paint box could be determined, else
15908 clutter_actor_get_paint_box (ClutterActor *self,
15909 ClutterActorBox *box)
15911 ClutterActor *stage;
15912 ClutterPaintVolume *pv;
15914 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15915 g_return_val_if_fail (box != NULL, FALSE);
15917 stage = _clutter_actor_get_stage_internal (self);
15918 if (G_UNLIKELY (!stage))
15921 pv = _clutter_actor_get_paint_volume_mutable (self);
15922 if (G_UNLIKELY (!pv))
15925 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15931 * clutter_actor_has_overlaps:
15932 * @self: A #ClutterActor
15934 * Asks the actor's implementation whether it may contain overlapping
15937 * For example; Clutter may use this to determine whether the painting
15938 * should be redirected to an offscreen buffer to correctly implement
15939 * the opacity property.
15941 * Custom actors can override the default response by implementing the
15942 * #ClutterActor <function>has_overlaps</function> virtual function. See
15943 * clutter_actor_set_offscreen_redirect() for more information.
15945 * Return value: %TRUE if the actor may have overlapping primitives, and
15951 clutter_actor_has_overlaps (ClutterActor *self)
15953 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15955 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15959 * clutter_actor_has_effects:
15960 * @self: A #ClutterActor
15962 * Returns whether the actor has any effects applied.
15964 * Return value: %TRUE if the actor has any effects,
15970 clutter_actor_has_effects (ClutterActor *self)
15972 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15974 if (self->priv->effects == NULL)
15977 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15981 * clutter_actor_has_constraints:
15982 * @self: A #ClutterActor
15984 * Returns whether the actor has any constraints applied.
15986 * Return value: %TRUE if the actor has any constraints,
15992 clutter_actor_has_constraints (ClutterActor *self)
15994 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15996 return self->priv->constraints != NULL;
16000 * clutter_actor_has_actions:
16001 * @self: A #ClutterActor
16003 * Returns whether the actor has any actions applied.
16005 * Return value: %TRUE if the actor has any actions,
16011 clutter_actor_has_actions (ClutterActor *self)
16013 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16015 return self->priv->actions != NULL;
16019 * clutter_actor_get_n_children:
16020 * @self: a #ClutterActor
16022 * Retrieves the number of children of @self.
16024 * Return value: the number of children of an actor
16029 clutter_actor_get_n_children (ClutterActor *self)
16031 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
16033 return self->priv->n_children;
16037 * clutter_actor_get_child_at_index:
16038 * @self: a #ClutterActor
16039 * @index_: the position in the list of children
16041 * Retrieves the actor at the given @index_ inside the list of
16042 * children of @self.
16044 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16049 clutter_actor_get_child_at_index (ClutterActor *self,
16052 ClutterActor *iter;
16055 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16056 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
16058 for (iter = self->priv->first_child, i = 0;
16059 iter != NULL && i < index_;
16060 iter = iter->priv->next_sibling, i += 1)
16067 * _clutter_actor_foreach_child:
16068 * @actor: The actor whos children you want to iterate
16069 * @callback: The function to call for each child
16070 * @user_data: Private data to pass to @callback
16072 * Calls a given @callback once for each child of the specified @actor and
16073 * passing the @user_data pointer each time.
16075 * Return value: returns %TRUE if all children were iterated, else
16076 * %FALSE if a callback broke out of iteration early.
16079 _clutter_actor_foreach_child (ClutterActor *self,
16080 ClutterForeachCallback callback,
16081 gpointer user_data)
16083 ClutterActor *iter;
16086 if (self->priv->first_child == NULL)
16090 iter = self->priv->first_child;
16092 /* we use this form so that it's safe to change the children
16093 * list while iterating it
16095 while (cont && iter != NULL)
16097 ClutterActor *next = iter->priv->next_sibling;
16099 cont = callback (iter, user_data);
16108 /* For debugging purposes this gives us a simple way to print out
16109 * the scenegraph e.g in gdb using:
16111 * _clutter_actor_traverse (stage,
16113 * clutter_debug_print_actor_cb,
16118 static ClutterActorTraverseVisitFlags
16119 clutter_debug_print_actor_cb (ClutterActor *actor,
16123 g_print ("%*s%s:%p\n",
16125 _clutter_actor_get_debug_name (actor),
16128 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16133 _clutter_actor_traverse_breadth (ClutterActor *actor,
16134 ClutterTraverseCallback callback,
16135 gpointer user_data)
16137 GQueue *queue = g_queue_new ();
16138 ClutterActor dummy;
16139 int current_depth = 0;
16141 g_queue_push_tail (queue, actor);
16142 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
16144 while ((actor = g_queue_pop_head (queue)))
16146 ClutterActorTraverseVisitFlags flags;
16148 if (actor == &dummy)
16151 g_queue_push_tail (queue, &dummy);
16155 flags = callback (actor, current_depth, user_data);
16156 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16158 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16160 ClutterActor *iter;
16162 for (iter = actor->priv->first_child;
16164 iter = iter->priv->next_sibling)
16166 g_queue_push_tail (queue, iter);
16171 g_queue_free (queue);
16174 static ClutterActorTraverseVisitFlags
16175 _clutter_actor_traverse_depth (ClutterActor *actor,
16176 ClutterTraverseCallback before_children_callback,
16177 ClutterTraverseCallback after_children_callback,
16179 gpointer user_data)
16181 ClutterActorTraverseVisitFlags flags;
16183 flags = before_children_callback (actor, current_depth, user_data);
16184 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16185 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16187 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16189 ClutterActor *iter;
16191 for (iter = actor->priv->first_child;
16193 iter = iter->priv->next_sibling)
16195 flags = _clutter_actor_traverse_depth (iter,
16196 before_children_callback,
16197 after_children_callback,
16201 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16202 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16206 if (after_children_callback)
16207 return after_children_callback (actor, current_depth, user_data);
16209 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16212 /* _clutter_actor_traverse:
16213 * @actor: The actor to start traversing the graph from
16214 * @flags: These flags may affect how the traversal is done
16215 * @before_children_callback: A function to call before visiting the
16216 * children of the current actor.
16217 * @after_children_callback: A function to call after visiting the
16218 * children of the current actor. (Ignored if
16219 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16220 * @user_data: The private data to pass to the callbacks
16222 * Traverses the scenegraph starting at the specified @actor and
16223 * descending through all its children and its children's children.
16224 * For each actor traversed @before_children_callback and
16225 * @after_children_callback are called with the specified
16226 * @user_data, before and after visiting that actor's children.
16228 * The callbacks can return flags that affect the ongoing traversal
16229 * such as by skipping over an actors children or bailing out of
16230 * any further traversing.
16233 _clutter_actor_traverse (ClutterActor *actor,
16234 ClutterActorTraverseFlags flags,
16235 ClutterTraverseCallback before_children_callback,
16236 ClutterTraverseCallback after_children_callback,
16237 gpointer user_data)
16239 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16240 _clutter_actor_traverse_breadth (actor,
16241 before_children_callback,
16243 else /* DEPTH_FIRST */
16244 _clutter_actor_traverse_depth (actor,
16245 before_children_callback,
16246 after_children_callback,
16247 0, /* start depth */
16252 on_layout_manager_changed (ClutterLayoutManager *manager,
16253 ClutterActor *self)
16255 clutter_actor_queue_relayout (self);
16259 * clutter_actor_set_layout_manager:
16260 * @self: a #ClutterActor
16261 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16263 * Sets the #ClutterLayoutManager delegate object that will be used to
16264 * lay out the children of @self.
16266 * The #ClutterActor will take a reference on the passed @manager which
16267 * will be released either when the layout manager is removed, or when
16268 * the actor is destroyed.
16273 clutter_actor_set_layout_manager (ClutterActor *self,
16274 ClutterLayoutManager *manager)
16276 ClutterActorPrivate *priv;
16278 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16279 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16283 if (priv->layout_manager != NULL)
16285 g_signal_handlers_disconnect_by_func (priv->layout_manager,
16286 G_CALLBACK (on_layout_manager_changed),
16288 clutter_layout_manager_set_container (priv->layout_manager, NULL);
16289 g_clear_object (&priv->layout_manager);
16292 priv->layout_manager = manager;
16294 if (priv->layout_manager != NULL)
16296 g_object_ref_sink (priv->layout_manager);
16297 clutter_layout_manager_set_container (priv->layout_manager,
16298 CLUTTER_CONTAINER (self));
16299 g_signal_connect (priv->layout_manager, "layout-changed",
16300 G_CALLBACK (on_layout_manager_changed),
16304 clutter_actor_queue_relayout (self);
16306 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16310 * clutter_actor_get_layout_manager:
16311 * @self: a #ClutterActor
16313 * Retrieves the #ClutterLayoutManager used by @self.
16315 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16320 ClutterLayoutManager *
16321 clutter_actor_get_layout_manager (ClutterActor *self)
16323 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16325 return self->priv->layout_manager;
16328 static const ClutterLayoutInfo default_layout_info = {
16329 CLUTTER_POINT_INIT_ZERO, /* fixed-pos */
16330 { 0, 0, 0, 0 }, /* margin */
16331 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
16332 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
16333 FALSE, FALSE, /* expand */
16334 CLUTTER_SIZE_INIT_ZERO, /* minimum */
16335 CLUTTER_SIZE_INIT_ZERO, /* natural */
16339 layout_info_free (gpointer data)
16341 if (G_LIKELY (data != NULL))
16342 g_slice_free (ClutterLayoutInfo, data);
16346 * _clutter_actor_get_layout_info:
16347 * @self: a #ClutterActor
16349 * Retrieves a pointer to the ClutterLayoutInfo structure.
16351 * If the actor does not have a ClutterLayoutInfo associated to it, one
16352 * will be created and initialized to the default values.
16354 * This function should be used for setters.
16356 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16359 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16361 ClutterLayoutInfo *
16362 _clutter_actor_get_layout_info (ClutterActor *self)
16364 ClutterLayoutInfo *retval;
16366 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16367 if (retval == NULL)
16369 retval = g_slice_new (ClutterLayoutInfo);
16371 *retval = default_layout_info;
16373 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16382 * _clutter_actor_get_layout_info_or_defaults:
16383 * @self: a #ClutterActor
16385 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16387 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16388 * then the default structure will be returned.
16390 * This function should only be used for getters.
16392 * Return value: a const pointer to the ClutterLayoutInfo structure
16394 const ClutterLayoutInfo *
16395 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16397 const ClutterLayoutInfo *info;
16399 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16401 return &default_layout_info;
16407 * clutter_actor_set_x_align:
16408 * @self: a #ClutterActor
16409 * @x_align: the horizontal alignment policy
16411 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16412 * actor received extra horizontal space.
16414 * See also the #ClutterActor:x-align property.
16419 clutter_actor_set_x_align (ClutterActor *self,
16420 ClutterActorAlign x_align)
16422 ClutterLayoutInfo *info;
16424 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16426 info = _clutter_actor_get_layout_info (self);
16428 if (info->x_align != x_align)
16430 info->x_align = x_align;
16432 clutter_actor_queue_relayout (self);
16434 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16439 * clutter_actor_get_x_align:
16440 * @self: a #ClutterActor
16442 * Retrieves the horizontal alignment policy set using
16443 * clutter_actor_set_x_align().
16445 * Return value: the horizontal alignment policy.
16450 clutter_actor_get_x_align (ClutterActor *self)
16452 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16454 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16458 * clutter_actor_set_y_align:
16459 * @self: a #ClutterActor
16460 * @y_align: the vertical alignment policy
16462 * Sets the vertical alignment policy of a #ClutterActor, in case the
16463 * actor received extra vertical space.
16465 * See also the #ClutterActor:y-align property.
16470 clutter_actor_set_y_align (ClutterActor *self,
16471 ClutterActorAlign y_align)
16473 ClutterLayoutInfo *info;
16475 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16477 info = _clutter_actor_get_layout_info (self);
16479 if (info->y_align != y_align)
16481 info->y_align = y_align;
16483 clutter_actor_queue_relayout (self);
16485 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16490 * clutter_actor_get_y_align:
16491 * @self: a #ClutterActor
16493 * Retrieves the vertical alignment policy set using
16494 * clutter_actor_set_y_align().
16496 * Return value: the vertical alignment policy.
16501 clutter_actor_get_y_align (ClutterActor *self)
16503 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16505 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16509 * clutter_actor_set_margin:
16510 * @self: a #ClutterActor
16511 * @margin: a #ClutterMargin
16513 * Sets all the components of the margin of a #ClutterActor.
16518 clutter_actor_set_margin (ClutterActor *self,
16519 const ClutterMargin *margin)
16521 ClutterLayoutInfo *info;
16525 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16526 g_return_if_fail (margin != NULL);
16528 obj = G_OBJECT (self);
16531 g_object_freeze_notify (obj);
16533 info = _clutter_actor_get_layout_info (self);
16535 if (info->margin.top != margin->top)
16537 info->margin.top = margin->top;
16538 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16542 if (info->margin.right != margin->right)
16544 info->margin.right = margin->right;
16545 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16549 if (info->margin.bottom != margin->bottom)
16551 info->margin.bottom = margin->bottom;
16552 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16556 if (info->margin.left != margin->left)
16558 info->margin.left = margin->left;
16559 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16564 clutter_actor_queue_relayout (self);
16566 g_object_thaw_notify (obj);
16570 * clutter_actor_get_margin:
16571 * @self: a #ClutterActor
16572 * @margin: (out caller-allocates): return location for a #ClutterMargin
16574 * Retrieves all the components of the margin of a #ClutterActor.
16579 clutter_actor_get_margin (ClutterActor *self,
16580 ClutterMargin *margin)
16582 const ClutterLayoutInfo *info;
16584 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16585 g_return_if_fail (margin != NULL);
16587 info = _clutter_actor_get_layout_info_or_defaults (self);
16589 *margin = info->margin;
16593 * clutter_actor_set_margin_top:
16594 * @self: a #ClutterActor
16595 * @margin: the top margin
16597 * Sets the margin from the top of a #ClutterActor.
16602 clutter_actor_set_margin_top (ClutterActor *self,
16605 ClutterLayoutInfo *info;
16607 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16608 g_return_if_fail (margin >= 0.f);
16610 info = _clutter_actor_get_layout_info (self);
16612 if (info->margin.top == margin)
16615 info->margin.top = margin;
16617 clutter_actor_queue_relayout (self);
16619 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16623 * clutter_actor_get_margin_top:
16624 * @self: a #ClutterActor
16626 * Retrieves the top margin of a #ClutterActor.
16628 * Return value: the top margin
16633 clutter_actor_get_margin_top (ClutterActor *self)
16635 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16637 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16641 * clutter_actor_set_margin_bottom:
16642 * @self: a #ClutterActor
16643 * @margin: the bottom margin
16645 * Sets the margin from the bottom of a #ClutterActor.
16650 clutter_actor_set_margin_bottom (ClutterActor *self,
16653 ClutterLayoutInfo *info;
16655 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16656 g_return_if_fail (margin >= 0.f);
16658 info = _clutter_actor_get_layout_info (self);
16660 if (info->margin.bottom == margin)
16663 info->margin.bottom = margin;
16665 clutter_actor_queue_relayout (self);
16667 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16671 * clutter_actor_get_margin_bottom:
16672 * @self: a #ClutterActor
16674 * Retrieves the bottom margin of a #ClutterActor.
16676 * Return value: the bottom margin
16681 clutter_actor_get_margin_bottom (ClutterActor *self)
16683 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16685 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16689 * clutter_actor_set_margin_left:
16690 * @self: a #ClutterActor
16691 * @margin: the left margin
16693 * Sets the margin from the left of a #ClutterActor.
16698 clutter_actor_set_margin_left (ClutterActor *self,
16701 ClutterLayoutInfo *info;
16703 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16704 g_return_if_fail (margin >= 0.f);
16706 info = _clutter_actor_get_layout_info (self);
16708 if (info->margin.left == margin)
16711 info->margin.left = margin;
16713 clutter_actor_queue_relayout (self);
16715 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16719 * clutter_actor_get_margin_left:
16720 * @self: a #ClutterActor
16722 * Retrieves the left margin of a #ClutterActor.
16724 * Return value: the left margin
16729 clutter_actor_get_margin_left (ClutterActor *self)
16731 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16733 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16737 * clutter_actor_set_margin_right:
16738 * @self: a #ClutterActor
16739 * @margin: the right margin
16741 * Sets the margin from the right of a #ClutterActor.
16746 clutter_actor_set_margin_right (ClutterActor *self,
16749 ClutterLayoutInfo *info;
16751 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16752 g_return_if_fail (margin >= 0.f);
16754 info = _clutter_actor_get_layout_info (self);
16756 if (info->margin.right == margin)
16759 info->margin.right = margin;
16761 clutter_actor_queue_relayout (self);
16763 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16767 * clutter_actor_get_margin_right:
16768 * @self: a #ClutterActor
16770 * Retrieves the right margin of a #ClutterActor.
16772 * Return value: the right margin
16777 clutter_actor_get_margin_right (ClutterActor *self)
16779 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16781 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16785 clutter_actor_set_background_color_internal (ClutterActor *self,
16786 const ClutterColor *color)
16788 ClutterActorPrivate *priv = self->priv;
16791 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16794 obj = G_OBJECT (self);
16796 priv->bg_color = *color;
16797 priv->bg_color_set = TRUE;
16799 clutter_actor_queue_redraw (self);
16801 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16802 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16806 * clutter_actor_set_background_color:
16807 * @self: a #ClutterActor
16808 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16811 * Sets the background color of a #ClutterActor.
16813 * The background color will be used to cover the whole allocation of the
16814 * actor. The default background color of an actor is transparent.
16816 * To check whether an actor has a background color, you can use the
16817 * #ClutterActor:background-color-set actor property.
16819 * The #ClutterActor:background-color property is animatable.
16824 clutter_actor_set_background_color (ClutterActor *self,
16825 const ClutterColor *color)
16827 ClutterActorPrivate *priv;
16829 GParamSpec *bg_color_pspec;
16831 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16833 obj = G_OBJECT (self);
16839 priv->bg_color_set = FALSE;
16840 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16841 clutter_actor_queue_redraw (self);
16845 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16846 if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16848 _clutter_actor_create_transition (self, bg_color_pspec,
16853 _clutter_actor_update_transition (self, bg_color_pspec, color);
16855 clutter_actor_queue_redraw (self);
16859 * clutter_actor_get_background_color:
16860 * @self: a #ClutterActor
16861 * @color: (out caller-allocates): return location for a #ClutterColor
16863 * Retrieves the color set using clutter_actor_set_background_color().
16868 clutter_actor_get_background_color (ClutterActor *self,
16869 ClutterColor *color)
16871 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16872 g_return_if_fail (color != NULL);
16874 *color = self->priv->bg_color;
16878 * clutter_actor_get_previous_sibling:
16879 * @self: a #ClutterActor
16881 * Retrieves the sibling of @self that comes before it in the list
16882 * of children of @self's parent.
16884 * The returned pointer is only valid until the scene graph changes; it
16885 * is not safe to modify the list of children of @self while iterating
16888 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16893 clutter_actor_get_previous_sibling (ClutterActor *self)
16895 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16897 return self->priv->prev_sibling;
16901 * clutter_actor_get_next_sibling:
16902 * @self: a #ClutterActor
16904 * Retrieves the sibling of @self that comes after it in the list
16905 * of children of @self's parent.
16907 * The returned pointer is only valid until the scene graph changes; it
16908 * is not safe to modify the list of children of @self while iterating
16911 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16916 clutter_actor_get_next_sibling (ClutterActor *self)
16918 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16920 return self->priv->next_sibling;
16924 * clutter_actor_get_first_child:
16925 * @self: a #ClutterActor
16927 * Retrieves the first child of @self.
16929 * The returned pointer is only valid until the scene graph changes; it
16930 * is not safe to modify the list of children of @self while iterating
16933 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16938 clutter_actor_get_first_child (ClutterActor *self)
16940 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16942 return self->priv->first_child;
16946 * clutter_actor_get_last_child:
16947 * @self: a #ClutterActor
16949 * Retrieves the last child of @self.
16951 * The returned pointer is only valid until the scene graph changes; it
16952 * is not safe to modify the list of children of @self while iterating
16955 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16960 clutter_actor_get_last_child (ClutterActor *self)
16962 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16964 return self->priv->last_child;
16967 /* easy way to have properly named fields instead of the dummy ones
16968 * we use in the public structure
16970 typedef struct _RealActorIter
16972 ClutterActor *root; /* dummy1 */
16973 ClutterActor *current; /* dummy2 */
16974 gpointer padding_1; /* dummy3 */
16975 gint age; /* dummy4 */
16976 gpointer padding_2; /* dummy5 */
16980 * clutter_actor_iter_init:
16981 * @iter: a #ClutterActorIter
16982 * @root: a #ClutterActor
16984 * Initializes a #ClutterActorIter, which can then be used to iterate
16985 * efficiently over a section of the scene graph, and associates it
16988 * Modifying the scene graph section that contains @root will invalidate
16992 * ClutterActorIter iter;
16993 * ClutterActor *child;
16995 * clutter_actor_iter_init (&iter, container);
16996 * while (clutter_actor_iter_next (&iter, &child))
16998 * /* do something with child */
17005 clutter_actor_iter_init (ClutterActorIter *iter,
17006 ClutterActor *root)
17008 RealActorIter *ri = (RealActorIter *) iter;
17010 g_return_if_fail (iter != NULL);
17011 g_return_if_fail (CLUTTER_IS_ACTOR (root));
17014 ri->current = NULL;
17015 ri->age = root->priv->age;
17019 * clutter_actor_iter_next:
17020 * @iter: a #ClutterActorIter
17021 * @child: (out): return location for a #ClutterActor
17023 * Advances the @iter and retrieves the next child of the root #ClutterActor
17024 * that was used to initialize the #ClutterActorIterator.
17026 * If the iterator can advance, this function returns %TRUE and sets the
17029 * If the iterator cannot advance, this function returns %FALSE, and
17030 * the contents of @child are undefined.
17032 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17037 clutter_actor_iter_next (ClutterActorIter *iter,
17038 ClutterActor **child)
17040 RealActorIter *ri = (RealActorIter *) iter;
17042 g_return_val_if_fail (iter != NULL, FALSE);
17043 g_return_val_if_fail (ri->root != NULL, FALSE);
17044 #ifndef G_DISABLE_ASSERT
17045 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17048 if (ri->current == NULL)
17049 ri->current = ri->root->priv->first_child;
17051 ri->current = ri->current->priv->next_sibling;
17054 *child = ri->current;
17056 return ri->current != NULL;
17060 * clutter_actor_iter_prev:
17061 * @iter: a #ClutterActorIter
17062 * @child: (out): return location for a #ClutterActor
17064 * Advances the @iter and retrieves the previous child of the root
17065 * #ClutterActor that was used to initialize the #ClutterActorIterator.
17067 * If the iterator can advance, this function returns %TRUE and sets the
17070 * If the iterator cannot advance, this function returns %FALSE, and
17071 * the contents of @child are undefined.
17073 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17078 clutter_actor_iter_prev (ClutterActorIter *iter,
17079 ClutterActor **child)
17081 RealActorIter *ri = (RealActorIter *) iter;
17083 g_return_val_if_fail (iter != NULL, FALSE);
17084 g_return_val_if_fail (ri->root != NULL, FALSE);
17085 #ifndef G_DISABLE_ASSERT
17086 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17089 if (ri->current == NULL)
17090 ri->current = ri->root->priv->last_child;
17092 ri->current = ri->current->priv->prev_sibling;
17095 *child = ri->current;
17097 return ri->current != NULL;
17101 * clutter_actor_iter_remove:
17102 * @iter: a #ClutterActorIter
17104 * Safely removes the #ClutterActor currently pointer to by the iterator
17107 * This function can only be called after clutter_actor_iter_next() or
17108 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17109 * than once for the same actor.
17111 * This function will call clutter_actor_remove_child() internally.
17116 clutter_actor_iter_remove (ClutterActorIter *iter)
17118 RealActorIter *ri = (RealActorIter *) iter;
17121 g_return_if_fail (iter != NULL);
17122 g_return_if_fail (ri->root != NULL);
17123 #ifndef G_DISABLE_ASSERT
17124 g_return_if_fail (ri->age == ri->root->priv->age);
17126 g_return_if_fail (ri->current != NULL);
17132 ri->current = cur->priv->prev_sibling;
17134 clutter_actor_remove_child_internal (ri->root, cur,
17135 REMOVE_CHILD_DEFAULT_FLAGS);
17142 * clutter_actor_iter_destroy:
17143 * @iter: a #ClutterActorIter
17145 * Safely destroys the #ClutterActor currently pointer to by the iterator
17148 * This function can only be called after clutter_actor_iter_next() or
17149 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17150 * than once for the same actor.
17152 * This function will call clutter_actor_destroy() internally.
17157 clutter_actor_iter_destroy (ClutterActorIter *iter)
17159 RealActorIter *ri = (RealActorIter *) iter;
17162 g_return_if_fail (iter != NULL);
17163 g_return_if_fail (ri->root != NULL);
17164 #ifndef G_DISABLE_ASSERT
17165 g_return_if_fail (ri->age == ri->root->priv->age);
17167 g_return_if_fail (ri->current != NULL);
17173 ri->current = cur->priv->prev_sibling;
17175 clutter_actor_destroy (cur);
17181 static const ClutterAnimationInfo default_animation_info = {
17182 NULL, /* transitions */
17184 NULL, /* cur_state */
17188 clutter_animation_info_free (gpointer data)
17192 ClutterAnimationInfo *info = data;
17194 if (info->transitions != NULL)
17195 g_hash_table_unref (info->transitions);
17197 if (info->states != NULL)
17198 g_array_unref (info->states);
17200 g_slice_free (ClutterAnimationInfo, info);
17204 const ClutterAnimationInfo *
17205 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17207 const ClutterAnimationInfo *res;
17208 GObject *obj = G_OBJECT (self);
17210 res = g_object_get_qdata (obj, quark_actor_animation_info);
17214 return &default_animation_info;
17217 ClutterAnimationInfo *
17218 _clutter_actor_get_animation_info (ClutterActor *self)
17220 GObject *obj = G_OBJECT (self);
17221 ClutterAnimationInfo *res;
17223 res = g_object_get_qdata (obj, quark_actor_animation_info);
17226 res = g_slice_new (ClutterAnimationInfo);
17228 *res = default_animation_info;
17230 g_object_set_qdata_full (obj, quark_actor_animation_info,
17232 clutter_animation_info_free);
17238 ClutterTransition *
17239 _clutter_actor_get_transition (ClutterActor *actor,
17242 const ClutterAnimationInfo *info;
17244 info = _clutter_actor_get_animation_info_or_defaults (actor);
17246 if (info->transitions == NULL)
17249 return g_hash_table_lookup (info->transitions, pspec->name);
17253 transition_closure_free (gpointer data)
17255 if (G_LIKELY (data != NULL))
17257 TransitionClosure *clos = data;
17258 ClutterTimeline *timeline;
17260 timeline = CLUTTER_TIMELINE (clos->transition);
17262 if (clutter_timeline_is_playing (timeline))
17263 clutter_timeline_stop (timeline);
17265 g_signal_handler_disconnect (clos->transition, clos->completed_id);
17267 g_object_unref (clos->transition);
17268 g_free (clos->name);
17270 g_slice_free (TransitionClosure, clos);
17275 on_transition_stopped (ClutterTransition *transition,
17276 gboolean is_finished,
17277 TransitionClosure *clos)
17279 ClutterActor *actor = clos->actor;
17280 ClutterAnimationInfo *info;
17282 /* reset the caches used by animations */
17283 clutter_actor_store_content_box (actor, NULL);
17288 info = _clutter_actor_get_animation_info (actor);
17290 /* we take a reference here because removing the closure
17291 * will release the reference on the transition, and we
17292 * want the transition to survive the signal emission;
17293 * the master clock will release the last reference at
17294 * the end of the frame processing.
17296 g_object_ref (transition);
17297 g_hash_table_remove (info->transitions, clos->name);
17299 /* if it's the last transition then we clean up */
17300 if (g_hash_table_size (info->transitions) == 0)
17302 g_hash_table_unref (info->transitions);
17303 info->transitions = NULL;
17305 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17306 _clutter_actor_get_debug_name (actor));
17308 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17313 _clutter_actor_update_transition (ClutterActor *actor,
17317 TransitionClosure *clos;
17318 ClutterTimeline *timeline;
17319 ClutterInterval *interval;
17320 const ClutterAnimationInfo *info;
17323 GValue initial = G_VALUE_INIT;
17324 GValue final = G_VALUE_INIT;
17325 char *error = NULL;
17327 info = _clutter_actor_get_animation_info_or_defaults (actor);
17329 if (info->transitions == NULL)
17332 clos = g_hash_table_lookup (info->transitions, pspec->name);
17336 timeline = CLUTTER_TIMELINE (clos->transition);
17338 va_start (var_args, pspec);
17340 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17342 g_value_init (&initial, ptype);
17343 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17347 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17350 g_critical ("%s: %s", G_STRLOC, error);
17355 interval = clutter_transition_get_interval (clos->transition);
17356 clutter_interval_set_initial_value (interval, &initial);
17357 clutter_interval_set_final_value (interval, &final);
17359 /* if we're updating with an easing duration of zero milliseconds,
17360 * we just jump the timeline to the end and let it run its course
17362 if (info->cur_state != NULL &&
17363 info->cur_state->easing_duration != 0)
17365 guint cur_duration = clutter_timeline_get_duration (timeline);
17366 ClutterAnimationMode cur_mode =
17367 clutter_timeline_get_progress_mode (timeline);
17369 if (cur_duration != info->cur_state->easing_duration)
17370 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17372 if (cur_mode != info->cur_state->easing_mode)
17373 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17375 clutter_timeline_rewind (timeline);
17379 guint duration = clutter_timeline_get_duration (timeline);
17381 clutter_timeline_advance (timeline, duration);
17385 g_value_unset (&initial);
17386 g_value_unset (&final);
17392 * _clutter_actor_create_transition:
17393 * @actor: a #ClutterActor
17394 * @pspec: the property used for the transition
17395 * @...: initial and final state
17397 * Creates a #ClutterTransition for the property represented by @pspec.
17399 * Return value: a #ClutterTransition
17401 ClutterTransition *
17402 _clutter_actor_create_transition (ClutterActor *actor,
17406 ClutterAnimationInfo *info;
17407 ClutterTransition *res = NULL;
17408 gboolean call_restore = FALSE;
17409 TransitionClosure *clos;
17412 info = _clutter_actor_get_animation_info (actor);
17414 /* XXX - this will go away in 2.0
17416 * if no state has been pushed, we assume that the easing state is
17417 * in "compatibility mode": all transitions have a duration of 0
17418 * msecs, which means that they happen immediately. in Clutter 2.0
17419 * this will turn into a g_assert(info->states != NULL), as every
17420 * actor will start with a predefined easing state
17422 if (info->states == NULL)
17424 clutter_actor_save_easing_state (actor);
17425 clutter_actor_set_easing_duration (actor, 0);
17426 call_restore = TRUE;
17429 if (info->transitions == NULL)
17430 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17432 transition_closure_free);
17434 va_start (var_args, pspec);
17436 clos = g_hash_table_lookup (info->transitions, pspec->name);
17439 ClutterTimeline *timeline;
17440 ClutterInterval *interval;
17441 GValue initial = G_VALUE_INIT;
17442 GValue final = G_VALUE_INIT;
17446 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17448 G_VALUE_COLLECT_INIT (&initial, ptype,
17453 g_critical ("%s: %s", G_STRLOC, error);
17458 G_VALUE_COLLECT_INIT (&final, ptype,
17464 g_critical ("%s: %s", G_STRLOC, error);
17465 g_value_unset (&initial);
17470 /* if the current easing state has a duration of 0, then we don't
17471 * bother to create the transition, and we just set the final value
17472 * directly on the actor; we don't go through the Animatable
17473 * interface because we know we got here through an animatable
17476 if (info->cur_state->easing_duration == 0)
17478 clutter_actor_set_animatable_property (actor,
17482 g_value_unset (&initial);
17483 g_value_unset (&final);
17488 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17490 g_value_unset (&initial);
17491 g_value_unset (&final);
17493 res = clutter_property_transition_new (pspec->name);
17495 clutter_transition_set_interval (res, interval);
17496 clutter_transition_set_remove_on_complete (res, TRUE);
17498 timeline = CLUTTER_TIMELINE (res);
17499 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17500 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17501 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17503 /* this will start the transition as well */
17504 clutter_actor_add_transition (actor, pspec->name, res);
17506 /* the actor now owns the transition */
17507 g_object_unref (res);
17510 res = clos->transition;
17514 clutter_actor_restore_easing_state (actor);
17522 * clutter_actor_add_transition:
17523 * @self: a #ClutterActor
17524 * @name: the name of the transition to add
17525 * @transition: the #ClutterTransition to add
17527 * Adds a @transition to the #ClutterActor's list of animations.
17529 * The @name string is a per-actor unique identifier of the @transition: only
17530 * one #ClutterTransition can be associated to the specified @name.
17532 * The @transition will be started once added.
17534 * This function will take a reference on the @transition.
17536 * This function is usually called implicitly when modifying an animatable
17542 clutter_actor_add_transition (ClutterActor *self,
17544 ClutterTransition *transition)
17546 ClutterTimeline *timeline;
17547 TransitionClosure *clos;
17548 ClutterAnimationInfo *info;
17550 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17551 g_return_if_fail (name != NULL);
17552 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17554 info = _clutter_actor_get_animation_info (self);
17556 if (info->transitions == NULL)
17557 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17559 transition_closure_free);
17561 if (g_hash_table_lookup (info->transitions, name) != NULL)
17563 g_warning ("A transition with name '%s' already exists for "
17566 _clutter_actor_get_debug_name (self));
17570 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17572 timeline = CLUTTER_TIMELINE (transition);
17574 clos = g_slice_new (TransitionClosure);
17575 clos->actor = self;
17576 clos->transition = g_object_ref (transition);
17577 clos->name = g_strdup (name);
17578 clos->completed_id = g_signal_connect (timeline, "stopped",
17579 G_CALLBACK (on_transition_stopped),
17582 CLUTTER_NOTE (ANIMATION,
17583 "Adding transition '%s' [%p] to actor '%s'",
17586 _clutter_actor_get_debug_name (self));
17588 g_hash_table_insert (info->transitions, clos->name, clos);
17589 clutter_timeline_start (timeline);
17593 * clutter_actor_remove_transition:
17594 * @self: a #ClutterActor
17595 * @name: the name of the transition to remove
17597 * Removes the transition stored inside a #ClutterActor using @name
17600 * If the transition is currently in progress, it will be stopped.
17602 * This function releases the reference acquired when the transition
17603 * was added to the #ClutterActor.
17608 clutter_actor_remove_transition (ClutterActor *self,
17611 const ClutterAnimationInfo *info;
17613 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17614 g_return_if_fail (name != NULL);
17616 info = _clutter_actor_get_animation_info_or_defaults (self);
17618 if (info->transitions == NULL)
17621 g_hash_table_remove (info->transitions, name);
17625 * clutter_actor_remove_all_transitions:
17626 * @self: a #ClutterActor
17628 * Removes all transitions associated to @self.
17633 clutter_actor_remove_all_transitions (ClutterActor *self)
17635 const ClutterAnimationInfo *info;
17637 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17639 info = _clutter_actor_get_animation_info_or_defaults (self);
17640 if (info->transitions == NULL)
17643 g_hash_table_remove_all (info->transitions);
17647 * clutter_actor_set_easing_duration:
17648 * @self: a #ClutterActor
17649 * @msecs: the duration of the easing, or %NULL
17651 * Sets the duration of the tweening for animatable properties
17652 * of @self for the current easing state.
17657 clutter_actor_set_easing_duration (ClutterActor *self,
17660 ClutterAnimationInfo *info;
17662 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17664 info = _clutter_actor_get_animation_info (self);
17666 if (info->cur_state == NULL)
17668 g_warning ("You must call clutter_actor_save_easing_state() prior "
17669 "to calling clutter_actor_set_easing_duration().");
17673 if (info->cur_state->easing_duration != msecs)
17674 info->cur_state->easing_duration = msecs;
17678 * clutter_actor_get_easing_duration:
17679 * @self: a #ClutterActor
17681 * Retrieves the duration of the tweening for animatable
17682 * properties of @self for the current easing state.
17684 * Return value: the duration of the tweening, in milliseconds
17689 clutter_actor_get_easing_duration (ClutterActor *self)
17691 const ClutterAnimationInfo *info;
17693 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17695 info = _clutter_actor_get_animation_info_or_defaults (self);
17697 if (info->cur_state != NULL)
17698 return info->cur_state->easing_duration;
17704 * clutter_actor_set_easing_mode:
17705 * @self: a #ClutterActor
17706 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17708 * Sets the easing mode for the tweening of animatable properties
17714 clutter_actor_set_easing_mode (ClutterActor *self,
17715 ClutterAnimationMode mode)
17717 ClutterAnimationInfo *info;
17719 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17720 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17721 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17723 info = _clutter_actor_get_animation_info (self);
17725 if (info->cur_state == NULL)
17727 g_warning ("You must call clutter_actor_save_easing_state() prior "
17728 "to calling clutter_actor_set_easing_mode().");
17732 if (info->cur_state->easing_mode != mode)
17733 info->cur_state->easing_mode = mode;
17737 * clutter_actor_get_easing_mode:
17738 * @self: a #ClutterActor
17740 * Retrieves the easing mode for the tweening of animatable properties
17741 * of @self for the current easing state.
17743 * Return value: an easing mode
17747 ClutterAnimationMode
17748 clutter_actor_get_easing_mode (ClutterActor *self)
17750 const ClutterAnimationInfo *info;
17752 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17754 info = _clutter_actor_get_animation_info_or_defaults (self);
17756 if (info->cur_state != NULL)
17757 return info->cur_state->easing_mode;
17759 return CLUTTER_EASE_OUT_CUBIC;
17763 * clutter_actor_set_easing_delay:
17764 * @self: a #ClutterActor
17765 * @msecs: the delay before the start of the tweening, in milliseconds
17767 * Sets the delay that should be applied before tweening animatable
17773 clutter_actor_set_easing_delay (ClutterActor *self,
17776 ClutterAnimationInfo *info;
17778 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17780 info = _clutter_actor_get_animation_info (self);
17782 if (info->cur_state == NULL)
17784 g_warning ("You must call clutter_actor_save_easing_state() prior "
17785 "to calling clutter_actor_set_easing_delay().");
17789 if (info->cur_state->easing_delay != msecs)
17790 info->cur_state->easing_delay = msecs;
17794 * clutter_actor_get_easing_delay:
17795 * @self: a #ClutterActor
17797 * Retrieves the delay that should be applied when tweening animatable
17800 * Return value: a delay, in milliseconds
17805 clutter_actor_get_easing_delay (ClutterActor *self)
17807 const ClutterAnimationInfo *info;
17809 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17811 info = _clutter_actor_get_animation_info_or_defaults (self);
17813 if (info->cur_state != NULL)
17814 return info->cur_state->easing_delay;
17820 * clutter_actor_get_transition:
17821 * @self: a #ClutterActor
17822 * @name: the name of the transition
17824 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17825 * transition @name.
17827 * Transitions created for animatable properties use the name of the
17828 * property itself, for instance the code below:
17831 * clutter_actor_set_easing_duration (actor, 1000);
17832 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17834 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17835 * g_signal_connect (transition, "stopped",
17836 * G_CALLBACK (on_transition_stopped),
17840 * will call the <function>on_transition_stopped</function> callback when
17841 * the transition is finished.
17843 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17844 * was found to match the passed name; the returned instance is owned
17845 * by Clutter and it should not be freed
17849 ClutterTransition *
17850 clutter_actor_get_transition (ClutterActor *self,
17853 TransitionClosure *clos;
17854 const ClutterAnimationInfo *info;
17856 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17857 g_return_val_if_fail (name != NULL, NULL);
17859 info = _clutter_actor_get_animation_info_or_defaults (self);
17860 if (info->transitions == NULL)
17863 clos = g_hash_table_lookup (info->transitions, name);
17867 return clos->transition;
17871 * clutter_actor_save_easing_state:
17872 * @self: a #ClutterActor
17874 * Saves the current easing state for animatable properties, and creates
17875 * a new state with the default values for easing mode and duration.
17880 clutter_actor_save_easing_state (ClutterActor *self)
17882 ClutterAnimationInfo *info;
17885 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17887 info = _clutter_actor_get_animation_info (self);
17889 if (info->states == NULL)
17890 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17892 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17893 new_state.easing_duration = 250;
17894 new_state.easing_delay = 0;
17896 g_array_append_val (info->states, new_state);
17898 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17902 * clutter_actor_restore_easing_state:
17903 * @self: a #ClutterActor
17905 * Restores the easing state as it was prior to a call to
17906 * clutter_actor_save_easing_state().
17911 clutter_actor_restore_easing_state (ClutterActor *self)
17913 ClutterAnimationInfo *info;
17915 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17917 info = _clutter_actor_get_animation_info (self);
17919 if (info->states == NULL)
17921 g_critical ("The function clutter_actor_restore_easing_state() has "
17922 "called without a previous call to "
17923 "clutter_actor_save_easing_state().");
17927 g_array_remove_index (info->states, info->states->len - 1);
17929 if (info->states->len > 0)
17930 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17933 g_array_unref (info->states);
17934 info->states = NULL;
17935 info->cur_state = NULL;
17940 * clutter_actor_set_content:
17941 * @self: a #ClutterActor
17942 * @content: (allow-none): a #ClutterContent, or %NULL
17944 * Sets the contents of a #ClutterActor.
17949 clutter_actor_set_content (ClutterActor *self,
17950 ClutterContent *content)
17952 ClutterActorPrivate *priv;
17954 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17955 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17959 if (priv->content != NULL)
17961 _clutter_content_detached (priv->content, self);
17962 g_clear_object (&priv->content);
17965 priv->content = content;
17967 if (priv->content != NULL)
17969 g_object_ref (priv->content);
17970 _clutter_content_attached (priv->content, self);
17973 /* given that the content is always painted within the allocation,
17974 * we only need to queue a redraw here
17976 clutter_actor_queue_redraw (self);
17978 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17980 /* if the content gravity is not resize-fill, and the new content has a
17981 * different preferred size than the previous one, then the content box
17982 * may have been changed. since we compute that lazily, we just notify
17983 * here, and let whomever watches :content-box do whatever they need to
17986 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17987 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17991 * clutter_actor_get_content:
17992 * @self: a #ClutterActor
17994 * Retrieves the contents of @self.
17996 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17997 * or %NULL if none was set
18002 clutter_actor_get_content (ClutterActor *self)
18004 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
18006 return self->priv->content;
18010 * clutter_actor_set_content_gravity:
18011 * @self: a #ClutterActor
18012 * @gravity: the #ClutterContentGravity
18014 * Sets the gravity of the #ClutterContent used by @self.
18016 * See the description of the #ClutterActor:content-gravity property for
18017 * more information.
18019 * The #ClutterActor:content-gravity property is animatable.
18024 clutter_actor_set_content_gravity (ClutterActor *self,
18025 ClutterContentGravity gravity)
18027 ClutterActorPrivate *priv;
18029 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18033 if (priv->content_gravity == gravity)
18036 priv->content_box_valid = FALSE;
18038 if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
18040 ClutterActorBox from_box, to_box;
18042 clutter_actor_get_content_box (self, &from_box);
18044 priv->content_gravity = gravity;
18046 clutter_actor_get_content_box (self, &to_box);
18048 _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
18054 ClutterActorBox to_box;
18056 priv->content_gravity = gravity;
18058 clutter_actor_get_content_box (self, &to_box);
18060 _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
18064 clutter_actor_queue_redraw (self);
18066 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
18070 * clutter_actor_get_content_gravity:
18071 * @self: a #ClutterActor
18073 * Retrieves the content gravity as set using
18074 * clutter_actor_get_content_gravity().
18076 * Return value: the content gravity
18080 ClutterContentGravity
18081 clutter_actor_get_content_gravity (ClutterActor *self)
18083 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
18084 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
18086 return self->priv->content_gravity;
18090 * clutter_actor_get_content_box:
18091 * @self: a #ClutterActor
18092 * @box: (out caller-allocates): the return location for the bounding
18093 * box for the #ClutterContent
18095 * Retrieves the bounding box for the #ClutterContent of @self.
18097 * The bounding box is relative to the actor's allocation.
18099 * If no #ClutterContent is set for @self, or if @self has not been
18100 * allocated yet, then the result is undefined.
18102 * The content box is guaranteed to be, at most, as big as the allocation
18103 * of the #ClutterActor.
18105 * If the #ClutterContent used by the actor has a preferred size, then
18106 * it is possible to modify the content box by using the
18107 * #ClutterActor:content-gravity property.
18112 clutter_actor_get_content_box (ClutterActor *self,
18113 ClutterActorBox *box)
18115 ClutterActorPrivate *priv;
18116 gfloat content_w, content_h;
18117 gfloat alloc_w, alloc_h;
18119 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18120 g_return_if_fail (box != NULL);
18126 box->x2 = priv->allocation.x2 - priv->allocation.x1;
18127 box->y2 = priv->allocation.y2 - priv->allocation.y1;
18129 if (priv->content_box_valid)
18131 *box = priv->content_box;
18135 /* no need to do any more work */
18136 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18139 if (priv->content == NULL)
18142 /* if the content does not have a preferred size then there is
18143 * no point in computing the content box
18145 if (!clutter_content_get_preferred_size (priv->content,
18153 switch (priv->content_gravity)
18155 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18156 box->x2 = box->x1 + MIN (content_w, alloc_w);
18157 box->y2 = box->y1 + MIN (content_h, alloc_h);
18160 case CLUTTER_CONTENT_GRAVITY_TOP:
18161 if (alloc_w > content_w)
18163 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18164 box->x2 = box->x1 + content_w;
18166 box->y2 = box->y1 + MIN (content_h, alloc_h);
18169 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18170 if (alloc_w > content_w)
18172 box->x1 += (alloc_w - content_w);
18173 box->x2 = box->x1 + content_w;
18175 box->y2 = box->y1 + MIN (content_h, alloc_h);
18178 case CLUTTER_CONTENT_GRAVITY_LEFT:
18179 box->x2 = box->x1 + MIN (content_w, alloc_w);
18180 if (alloc_h > content_h)
18182 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18183 box->y2 = box->y1 + content_h;
18187 case CLUTTER_CONTENT_GRAVITY_CENTER:
18188 if (alloc_w > content_w)
18190 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18191 box->x2 = box->x1 + content_w;
18193 if (alloc_h > content_h)
18195 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18196 box->y2 = box->y1 + content_h;
18200 case CLUTTER_CONTENT_GRAVITY_RIGHT:
18201 if (alloc_w > content_w)
18203 box->x1 += (alloc_w - content_w);
18204 box->x2 = box->x1 + content_w;
18206 if (alloc_h > content_h)
18208 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18209 box->y2 = box->y1 + content_h;
18213 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18214 box->x2 = box->x1 + MIN (content_w, alloc_w);
18215 if (alloc_h > content_h)
18217 box->y1 += (alloc_h - content_h);
18218 box->y2 = box->y1 + content_h;
18222 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18223 if (alloc_w > content_w)
18225 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18226 box->x2 = box->x1 + content_w;
18228 if (alloc_h > content_h)
18230 box->y1 += (alloc_h - content_h);
18231 box->y2 = box->y1 + content_h;
18235 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18236 if (alloc_w > content_w)
18238 box->x1 += (alloc_w - content_w);
18239 box->x2 = box->x1 + content_w;
18241 if (alloc_h > content_h)
18243 box->y1 += (alloc_h - content_h);
18244 box->y2 = box->y1 + content_h;
18248 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18249 g_assert_not_reached ();
18252 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18254 double r_c = content_w / content_h;
18258 if ((alloc_w / r_c) > alloc_h)
18263 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18264 box->y2 = box->y1 + (alloc_w / r_c);
18271 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18272 box->x2 = box->x1 + (alloc_h * r_c);
18277 if ((alloc_w / r_c) > alloc_h)
18282 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18283 box->x2 = box->x1 + (alloc_h * r_c);
18290 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18291 box->y2 = box->y1 + (alloc_w / r_c);
18295 CLUTTER_NOTE (LAYOUT,
18296 "r_c: %.3f, r_a: %.3f\t"
18297 "a: [%.2fx%.2f], c: [%.2fx%.2f]\t"
18298 "b: [%.2f, %.2f, %.2f, %.2f]",
18299 r_c, alloc_w / alloc_h,
18301 content_w, content_h,
18302 box->x1, box->y1, box->x2, box->y2);
18309 * clutter_actor_set_content_scaling_filters:
18310 * @self: a #ClutterActor
18311 * @min_filter: the minification filter for the content
18312 * @mag_filter: the magnification filter for the content
18314 * Sets the minification and magnification filter to be applied when
18315 * scaling the #ClutterActor:content of a #ClutterActor.
18317 * The #ClutterActor:minification-filter will be used when reducing
18318 * the size of the content; the #ClutterActor:magnification-filter
18319 * will be used when increasing the size of the content.
18324 clutter_actor_set_content_scaling_filters (ClutterActor *self,
18325 ClutterScalingFilter min_filter,
18326 ClutterScalingFilter mag_filter)
18328 ClutterActorPrivate *priv;
18332 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18335 obj = G_OBJECT (self);
18337 g_object_freeze_notify (obj);
18341 if (priv->min_filter != min_filter)
18343 priv->min_filter = min_filter;
18346 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18349 if (priv->mag_filter != mag_filter)
18351 priv->mag_filter = mag_filter;
18354 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18358 clutter_actor_queue_redraw (self);
18360 g_object_thaw_notify (obj);
18364 * clutter_actor_get_content_scaling_filters:
18365 * @self: a #ClutterActor
18366 * @min_filter: (out) (allow-none): return location for the minification
18368 * @mag_filter: (out) (allow-none): return location for the magnification
18371 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18376 clutter_actor_get_content_scaling_filters (ClutterActor *self,
18377 ClutterScalingFilter *min_filter,
18378 ClutterScalingFilter *mag_filter)
18380 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18382 if (min_filter != NULL)
18383 *min_filter = self->priv->min_filter;
18385 if (mag_filter != NULL)
18386 *mag_filter = self->priv->mag_filter;
18390 * clutter_actor_queue_compute_expand:
18391 * @self: a #ClutterActor
18393 * Invalidates the needs_x_expand and needs_y_expand flags on @self
18394 * and its parents up to the top-level actor.
18396 * This function also queues a relayout if anything changed.
18399 clutter_actor_queue_compute_expand (ClutterActor *self)
18401 ClutterActor *parent;
18404 if (self->priv->needs_compute_expand)
18409 while (parent != NULL)
18411 if (!parent->priv->needs_compute_expand)
18413 parent->priv->needs_compute_expand = TRUE;
18417 parent = parent->priv->parent;
18421 clutter_actor_queue_relayout (self);
18425 * clutter_actor_set_x_expand:
18426 * @self: a #ClutterActor
18427 * @expand: whether the actor should expand horizontally
18429 * Sets whether a #ClutterActor should expand horizontally; this means
18430 * that layout manager should allocate extra space for the actor, if
18433 * Setting an actor to expand will also make all its parent expand, so
18434 * that it's possible to build an actor tree and only set this flag on
18435 * its leaves and not on every single actor.
18440 clutter_actor_set_x_expand (ClutterActor *self,
18443 ClutterLayoutInfo *info;
18445 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18449 info = _clutter_actor_get_layout_info (self);
18450 if (info->x_expand != expand)
18452 info->x_expand = expand;
18454 self->priv->x_expand_set = TRUE;
18456 clutter_actor_queue_compute_expand (self);
18458 g_object_notify_by_pspec (G_OBJECT (self),
18459 obj_props[PROP_X_EXPAND]);
18464 * clutter_actor_get_x_expand:
18465 * @self: a #ClutterActor
18467 * Retrieves the value set with clutter_actor_set_x_expand().
18469 * See also: clutter_actor_needs_expand()
18471 * Return value: %TRUE if the actor has been set to expand
18476 clutter_actor_get_x_expand (ClutterActor *self)
18478 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18480 return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18484 * clutter_actor_set_y_expand:
18485 * @self: a #ClutterActor
18486 * @expand: whether the actor should expand vertically
18488 * Sets whether a #ClutterActor should expand horizontally; this means
18489 * that layout manager should allocate extra space for the actor, if
18492 * Setting an actor to expand will also make all its parent expand, so
18493 * that it's possible to build an actor tree and only set this flag on
18494 * its leaves and not on every single actor.
18499 clutter_actor_set_y_expand (ClutterActor *self,
18502 ClutterLayoutInfo *info;
18504 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18508 info = _clutter_actor_get_layout_info (self);
18509 if (info->y_expand != expand)
18511 info->y_expand = expand;
18513 self->priv->y_expand_set = TRUE;
18515 clutter_actor_queue_compute_expand (self);
18517 g_object_notify_by_pspec (G_OBJECT (self),
18518 obj_props[PROP_Y_EXPAND]);
18523 * clutter_actor_get_y_expand:
18524 * @self: a #ClutterActor
18526 * Retrieves the value set with clutter_actor_set_y_expand().
18528 * See also: clutter_actor_needs_expand()
18530 * Return value: %TRUE if the actor has been set to expand
18535 clutter_actor_get_y_expand (ClutterActor *self)
18537 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18539 return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18543 clutter_actor_compute_expand_recursive (ClutterActor *self,
18544 gboolean *x_expand_p,
18545 gboolean *y_expand_p)
18547 ClutterActorIter iter;
18548 ClutterActor *child;
18549 gboolean x_expand, y_expand;
18551 x_expand = y_expand = FALSE;
18553 /* note that we don't recurse into children if we're already set to expand;
18554 * this avoids traversing the whole actor tree, even if it may lead to some
18555 * child left with the needs_compute_expand flag set.
18557 clutter_actor_iter_init (&iter, self);
18558 while (clutter_actor_iter_next (&iter, &child))
18560 x_expand = x_expand ||
18561 clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL);
18563 y_expand = y_expand ||
18564 clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL);
18567 *x_expand_p = x_expand;
18568 *y_expand_p = y_expand;
18572 clutter_actor_compute_expand (ClutterActor *self)
18574 if (self->priv->needs_compute_expand)
18576 const ClutterLayoutInfo *info;
18577 gboolean x_expand, y_expand;
18579 info = _clutter_actor_get_layout_info_or_defaults (self);
18581 if (self->priv->x_expand_set)
18582 x_expand = info->x_expand;
18586 if (self->priv->y_expand_set)
18587 y_expand = info->y_expand;
18591 /* we don't need to recurse down to the children if the
18592 * actor has been forcibly set to expand
18594 if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18596 if (self->priv->n_children != 0)
18598 gboolean *x_expand_p, *y_expand_p;
18599 gboolean ignored = FALSE;
18601 x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18602 y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18604 clutter_actor_compute_expand_recursive (self,
18610 self->priv->needs_compute_expand = FALSE;
18611 self->priv->needs_x_expand = (x_expand != FALSE);
18612 self->priv->needs_y_expand = (y_expand != FALSE);
18617 * clutter_actor_needs_expand:
18618 * @self: a #ClutterActor
18619 * @orientation: the direction of expansion
18621 * Checks whether an actor, or any of its children, is set to expand
18622 * horizontally or vertically.
18624 * This function should only be called by layout managers that can
18625 * assign extra space to their children.
18627 * If you want to know whether the actor was explicitly set to expand,
18628 * use clutter_actor_get_x_expand() or clutter_actor_get_y_expand().
18630 * Return value: %TRUE if the actor should expand
18635 clutter_actor_needs_expand (ClutterActor *self,
18636 ClutterOrientation orientation)
18638 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18640 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18643 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18646 clutter_actor_compute_expand (self);
18648 switch (orientation)
18650 case CLUTTER_ORIENTATION_HORIZONTAL:
18651 return self->priv->needs_x_expand;
18653 case CLUTTER_ORIENTATION_VERTICAL:
18654 return self->priv->needs_y_expand;